aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2017-01-07 16:47:07 +0100
committerChristian Grothoff <christian@grothoff.org>2017-01-07 16:47:07 +0100
commitddadc570d8fd3ce7a4f658adf9a2c9b9d9c0dcba (patch)
tree076f4d7b4732099d33662de3bdff51c965cae8df /src/nat-auto
parent659e270f9e023112ca864065a22db5e484ba5ef6 (diff)
downloadgnunet-ddadc570d8fd3ce7a4f658adf9a2c9b9d9c0dcba.tar.gz
gnunet-ddadc570d8fd3ce7a4f658adf9a2c9b9d9c0dcba.zip
remove legacy NAT library logic, or preserve if it might still be useful
Diffstat (limited to 'src/nat-auto')
-rw-r--r--src/nat-auto/gnunet-nat-auto_legacy.c645
-rw-r--r--src/nat-auto/gnunet-service-nat-auto.c3
-rw-r--r--src/nat-auto/gnunet-service-nat-auto_legacy.c1081
3 files changed, 1728 insertions, 1 deletions
diff --git a/src/nat-auto/gnunet-nat-auto_legacy.c b/src/nat-auto/gnunet-nat-auto_legacy.c
new file mode 100644
index 000000000..803ff23e3
--- /dev/null
+++ b/src/nat-auto/gnunet-nat-auto_legacy.c
@@ -0,0 +1,645 @@
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/**
22 * @file nat/nat_test.c
23 * @brief functions to test if the NAT configuration is successful at achieving NAT traversal (with the help of a gnunet-nat-server)
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_nat_lib.h"
29#include "nat.h"
30
31#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
32
33#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
34
35/**
36 * Entry we keep for each incoming connection.
37 */
38struct NatActivity
39{
40 /**
41 * This is a doubly-linked list.
42 */
43 struct NatActivity *next;
44
45 /**
46 * This is a doubly-linked list.
47 */
48 struct NatActivity *prev;
49
50 /**
51 * Socket of the incoming connection.
52 */
53 struct GNUNET_NETWORK_Handle *sock;
54
55 /**
56 * Handle of the master context.
57 */
58 struct GNUNET_NAT_Test *h;
59
60 /**
61 * Task reading from the incoming connection.
62 */
63 struct GNUNET_SCHEDULER_Task *rtask;
64};
65
66
67/**
68 * Entry we keep for each connection to the gnunet-nat-service.
69 */
70struct ClientActivity
71{
72 /**
73 * This is a doubly-linked list.
74 */
75 struct ClientActivity *next;
76
77 /**
78 * This is a doubly-linked list.
79 */
80 struct ClientActivity *prev;
81
82 /**
83 * Socket of the incoming connection.
84 */
85 struct GNUNET_MQ_Handle *mq;
86
87 /**
88 * Handle to overall NAT test.
89 */
90 struct GNUNET_NAT_Test *h;
91
92};
93
94
95/**
96 * Handle to a NAT test.
97 */
98struct GNUNET_NAT_Test
99{
100
101 /**
102 * Configuration used
103 */
104 const struct GNUNET_CONFIGURATION_Handle *cfg;
105
106 /**
107 * Function to call with success report
108 */
109 GNUNET_NAT_TestCallback report;
110
111 /**
112 * Closure for @e report.
113 */
114 void *report_cls;
115
116 /**
117 * Handle to NAT traversal in use
118 */
119 struct GNUNET_NAT_Handle *nat;
120
121 /**
122 * Handle to listen socket, or NULL
123 */
124 struct GNUNET_NETWORK_Handle *lsock;
125
126 /**
127 * Head of list of nat activities.
128 */
129 struct NatActivity *na_head;
130
131 /**
132 * Tail of list of nat activities.
133 */
134 struct NatActivity *na_tail;
135
136 /**
137 * Head of list of client activities.
138 */
139 struct ClientActivity *ca_head;
140
141 /**
142 * Tail of list of client activities.
143 */
144 struct ClientActivity *ca_tail;
145
146 /**
147 * Identity of task for the listen socket (if any)
148 */
149 struct GNUNET_SCHEDULER_Task *ltask;
150
151 /**
152 * Task identifier for the timeout (if any)
153 */
154 struct GNUNET_SCHEDULER_Task *ttask;
155
156 /**
157 * #GNUNET_YES if we're testing TCP
158 */
159 int is_tcp;
160
161 /**
162 * Data that should be transmitted or source-port.
163 */
164 uint16_t data;
165
166 /**
167 * Advertised port to the other peer.
168 */
169 uint16_t adv_port;
170
171 /**
172 * Status code to be reported to the timeout/status call
173 */
174 enum GNUNET_NAT_StatusCode status;
175};
176
177
178/**
179 * Function called from #GNUNET_NAT_register whenever someone asks us
180 * to do connection reversal.
181 *
182 * @param cls closure, our `struct GNUNET_NAT_Handle`
183 * @param addr public IP address of the other peer
184 * @param addrlen actual lenght of the @a addr
185 */
186static void
187reversal_cb (void *cls,
188 const struct sockaddr *addr,
189 socklen_t addrlen)
190{
191 struct GNUNET_NAT_Test *h = cls;
192 const struct sockaddr_in *sa;
193
194 if (sizeof (struct sockaddr_in) != addrlen)
195 return;
196 sa = (const struct sockaddr_in *) addr;
197 if (h->data != sa->sin_port)
198 {
199 LOG (GNUNET_ERROR_TYPE_DEBUG,
200 "Received connection reversal request for wrong port\n");
201 return; /* wrong port */
202 }
203 /* report success */
204 h->report (h->report_cls,
205 GNUNET_NAT_ERROR_SUCCESS);
206}
207
208
209/**
210 * Activity on our incoming socket. Read data from the
211 * incoming connection.
212 *
213 * @param cls the `struct GNUNET_NAT_Test`
214 */
215static void
216do_udp_read (void *cls)
217{
218 struct GNUNET_NAT_Test *tst = cls;
219 uint16_t data;
220 const struct GNUNET_SCHEDULER_TaskContext *tc;
221
222 tc = GNUNET_SCHEDULER_get_task_context ();
223 tst->ltask =
224 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
225 tst->lsock,
226 &do_udp_read,
227 tst);
228 if ((NULL != tc->write_ready) &&
229 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
230 tst->lsock)) &&
231 (sizeof (data) ==
232 GNUNET_NETWORK_socket_recv (tst->lsock,
233 &data,
234 sizeof (data))))
235 {
236 if (data == tst->data)
237 tst->report (tst->report_cls,
238 GNUNET_NAT_ERROR_SUCCESS);
239 else
240 LOG (GNUNET_ERROR_TYPE_DEBUG,
241 "Received data mismatches expected value\n");
242 }
243 else
244 LOG (GNUNET_ERROR_TYPE_DEBUG,
245 "Failed to receive data from inbound connection\n");
246}
247
248
249/**
250 * Activity on our incoming socket. Read data from the
251 * incoming connection.
252 *
253 * @param cls the `struct NatActivity`
254 */
255static void
256do_read (void *cls)
257{
258 struct NatActivity *na = cls;
259 struct GNUNET_NAT_Test *tst;
260 uint16_t data;
261 const struct GNUNET_SCHEDULER_TaskContext *tc;
262
263 tc = GNUNET_SCHEDULER_get_task_context ();
264 na->rtask = NULL;
265 tst = na->h;
266 GNUNET_CONTAINER_DLL_remove (tst->na_head,
267 tst->na_tail,
268 na);
269 if ((NULL != tc->write_ready) &&
270 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
271 na->sock)) &&
272 (sizeof (data) ==
273 GNUNET_NETWORK_socket_recv (na->sock,
274 &data,
275 sizeof (data))))
276 {
277 if (data == tst->data)
278 tst->report (tst->report_cls,
279 GNUNET_NAT_ERROR_SUCCESS);
280 else
281 LOG (GNUNET_ERROR_TYPE_DEBUG,
282 "Received data does not match expected value\n");
283 }
284 else
285 LOG (GNUNET_ERROR_TYPE_DEBUG,
286 "Failed to receive data from inbound connection\n");
287 GNUNET_NETWORK_socket_close (na->sock);
288 GNUNET_free (na);
289}
290
291
292/**
293 * Activity on our listen socket. Accept the
294 * incoming connection.
295 *
296 * @param cls the `struct GNUNET_NAT_Test`
297 */
298static void
299do_accept (void *cls)
300{
301 struct GNUNET_NAT_Test *tst = cls;
302 struct GNUNET_NETWORK_Handle *s;
303 struct NatActivity *wl;
304
305 tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
306 tst->lsock,
307 &do_accept,
308 tst);
309 s = GNUNET_NETWORK_socket_accept (tst->lsock,
310 NULL,
311 NULL);
312 if (NULL == s)
313 {
314 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
315 "accept");
316 return; /* odd error */
317 }
318 LOG (GNUNET_ERROR_TYPE_DEBUG,
319 "Got an inbound connection, waiting for data\n");
320 wl = GNUNET_new (struct NatActivity);
321 wl->sock = s;
322 wl->h = tst;
323 wl->rtask =
324 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
325 wl->sock,
326 &do_read,
327 wl);
328 GNUNET_CONTAINER_DLL_insert (tst->na_head,
329 tst->na_tail,
330 wl);
331}
332
333
334/**
335 * We got disconnected from the NAT server. Stop
336 * waiting for a reply.
337 *
338 * @param cls the `struct ClientActivity`
339 * @param error error code
340 */
341static void
342mq_error_handler (void *cls,
343 enum GNUNET_MQ_Error error)
344{
345 struct ClientActivity *ca = cls;
346 struct GNUNET_NAT_Test *tst = ca->h;
347
348 GNUNET_CONTAINER_DLL_remove (tst->ca_head,
349 tst->ca_tail,
350 ca);
351 GNUNET_MQ_destroy (ca->mq);
352 GNUNET_free (ca);
353}
354
355
356/**
357 * Address-callback, used to send message to gnunet-nat-server.
358 *
359 * @param cls closure
360 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
361 * the previous (now invalid) one
362 * @param addr either the previous or the new public IP address
363 * @param addrlen actual length of the @a addr
364 */
365static void
366addr_cb (void *cls,
367 int add_remove,
368 const struct sockaddr *addr,
369 socklen_t addrlen)
370{
371 struct GNUNET_NAT_Test *h = cls;
372 struct ClientActivity *ca;
373 struct GNUNET_MQ_Envelope *env;
374 struct GNUNET_NAT_TestMessage *msg;
375 const struct sockaddr_in *sa;
376
377 if (GNUNET_YES != add_remove)
378 return;
379 if (addrlen != sizeof (struct sockaddr_in))
380 {
381 LOG (GNUNET_ERROR_TYPE_DEBUG,
382 "NAT test ignores IPv6 address `%s' returned from NAT library\n",
383 GNUNET_a2s (addr,
384 addrlen));
385 return; /* ignore IPv6 here */
386 }
387 LOG (GNUNET_ERROR_TYPE_INFO,
388 "Asking gnunet-nat-server to connect to `%s'\n",
389 GNUNET_a2s (addr,
390 addrlen));
391
392 ca = GNUNET_new (struct ClientActivity);
393 ca->h = h;
394 ca->mq = GNUNET_CLIENT_connecT (h->cfg,
395 "gnunet-nat-server",
396 NULL,
397 &mq_error_handler,
398 ca);
399 if (NULL == ca->mq)
400 {
401 GNUNET_free (ca);
402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 _("Failed to connect to `gnunet-nat-server'\n"));
404 return;
405 }
406 GNUNET_CONTAINER_DLL_insert (h->ca_head,
407 h->ca_tail,
408 ca);
409 sa = (const struct sockaddr_in *) addr;
410 env = GNUNET_MQ_msg (msg,
411 GNUNET_MESSAGE_TYPE_NAT_TEST);
412 msg->dst_ipv4 = sa->sin_addr.s_addr;
413 msg->dport = sa->sin_port;
414 msg->data = h->data;
415 msg->is_tcp = htonl ((uint32_t) h->is_tcp);
416 GNUNET_MQ_send (ca->mq,
417 env);
418}
419
420
421/**
422 * Timeout task for a nat test.
423 * Calls the report-callback with a timeout return value
424 *
425 * Destroys the nat handle after the callback has been processed.
426 *
427 * @param cls handle to the timed out NAT test
428 */
429static void
430do_timeout (void *cls)
431{
432 struct GNUNET_NAT_Test *nh = cls;
433
434 nh->ttask = NULL;
435 nh->report (nh->report_cls,
436 (GNUNET_NAT_ERROR_SUCCESS == nh->status)
437 ? GNUNET_NAT_ERROR_TIMEOUT
438 : nh->status);
439}
440
441
442/**
443 * Start testing if NAT traversal works using the
444 * given configuration (IPv4-only).
445 *
446 * ALL failures are reported directly to the report callback
447 *
448 * @param cfg configuration for the NAT traversal
449 * @param is_tcp #GNUNET_YES to test TCP, #GNUNET_NO to test UDP
450 * @param bnd_port port to bind to, 0 for connection reversal
451 * @param adv_port externally advertised port to use
452 * @param timeout delay after which the test should be aborted
453 * @param report function to call with the result of the test
454 * @param report_cls closure for @a report
455 * @return handle to cancel NAT test or NULL. The error is always indicated via the report callback
456 */
457struct GNUNET_NAT_Test *
458GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
459 int is_tcp,
460 uint16_t bnd_port,
461 uint16_t adv_port,
462 struct GNUNET_TIME_Relative timeout,
463 GNUNET_NAT_TestCallback report,
464 void *report_cls)
465{
466 struct GNUNET_NAT_Test *nh;
467 struct sockaddr_in sa;
468 const struct sockaddr *addrs[] = {
469 (const struct sockaddr *) &sa
470 };
471 const socklen_t addrlens[] = {
472 sizeof (sa)
473 };
474
475 memset (&sa, 0, sizeof (sa));
476 sa.sin_family = AF_INET;
477 sa.sin_port = htons (bnd_port);
478#if HAVE_SOCKADDR_IN_SIN_LEN
479 sa.sin_len = sizeof (sa);
480#endif
481
482 nh = GNUNET_new (struct GNUNET_NAT_Test);
483 nh->cfg = cfg;
484 nh->is_tcp = is_tcp;
485 nh->data = bnd_port;
486 nh->adv_port = adv_port;
487 nh->report = report;
488 nh->report_cls = report_cls;
489 nh->status = GNUNET_NAT_ERROR_SUCCESS;
490 if (0 == bnd_port)
491 {
492 nh->nat
493 = GNUNET_NAT_register (cfg,
494 is_tcp,
495 0,
496 0,
497 NULL,
498 NULL,
499 &addr_cb,
500 &reversal_cb,
501 nh,
502 NULL);
503 }
504 else
505 {
506 nh->lsock =
507 GNUNET_NETWORK_socket_create (AF_INET,
508 (is_tcp ==
509 GNUNET_YES) ? SOCK_STREAM : SOCK_DGRAM,
510 0);
511 if ((nh->lsock == NULL) ||
512 (GNUNET_OK !=
513 GNUNET_NETWORK_socket_bind (nh->lsock,
514 (const struct sockaddr *) &sa,
515 sizeof (sa))))
516 {
517 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
518 _("Failed to create listen socket bound to `%s' for NAT test: %s\n"),
519 GNUNET_a2s ((const struct sockaddr *) &sa,
520 sizeof (sa)),
521 STRERROR (errno));
522 if (NULL != nh->lsock)
523 {
524 GNUNET_NETWORK_socket_close (nh->lsock);
525 nh->lsock = NULL;
526 }
527 nh->status = GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR;
528 nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
529 nh);
530 return nh;
531 }
532 if (GNUNET_YES == is_tcp)
533 {
534 GNUNET_break (GNUNET_OK ==
535 GNUNET_NETWORK_socket_listen (nh->lsock,
536 5));
537 nh->ltask =
538 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
539 nh->lsock,
540 &do_accept,
541 nh);
542 }
543 else
544 {
545 nh->ltask =
546 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
547 nh->lsock,
548 &do_udp_read,
549 nh);
550 }
551 LOG (GNUNET_ERROR_TYPE_INFO,
552 "NAT test listens on port %u (%s)\n",
553 bnd_port,
554 (GNUNET_YES == is_tcp) ? "tcp" : "udp");
555 nh->nat = GNUNET_NAT_register (cfg,
556 is_tcp,
557 adv_port,
558 1,
559 addrs,
560 addrlens,
561 &addr_cb,
562 NULL,
563 nh,
564 NULL);
565 if (NULL == nh->nat)
566 {
567 LOG (GNUNET_ERROR_TYPE_INFO,
568 _("NAT test failed to start NAT library\n"));
569 if (NULL != nh->ltask)
570 {
571 GNUNET_SCHEDULER_cancel (nh->ltask);
572 nh->ltask = NULL;
573 }
574 if (NULL != nh->lsock)
575 {
576 GNUNET_NETWORK_socket_close (nh->lsock);
577 nh->lsock = NULL;
578 }
579 nh->status = GNUNET_NAT_ERROR_NAT_REGISTER_FAILED;
580 nh->ttask = GNUNET_SCHEDULER_add_now (&do_timeout,
581 nh);
582 return nh;
583 }
584 }
585 nh->ttask = GNUNET_SCHEDULER_add_delayed (timeout,
586 &do_timeout,
587 nh);
588 return nh;
589}
590
591
592/**
593 * Stop an active NAT test.
594 *
595 * @param tst test to stop.
596 */
597void
598GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
599{
600 struct NatActivity *pos;
601 struct ClientActivity *cpos;
602
603 LOG (GNUNET_ERROR_TYPE_DEBUG,
604 "Stopping NAT test\n");
605 while (NULL != (cpos = tst->ca_head))
606 {
607 GNUNET_CONTAINER_DLL_remove (tst->ca_head,
608 tst->ca_tail,
609 cpos);
610 GNUNET_MQ_destroy (cpos->mq);
611 GNUNET_free (cpos);
612 }
613 while (NULL != (pos = tst->na_head))
614 {
615 GNUNET_CONTAINER_DLL_remove (tst->na_head,
616 tst->na_tail,
617 pos);
618 GNUNET_SCHEDULER_cancel (pos->rtask);
619 GNUNET_NETWORK_socket_close (pos->sock);
620 GNUNET_free (pos);
621 }
622 if (NULL != tst->ttask)
623 {
624 GNUNET_SCHEDULER_cancel (tst->ttask);
625 tst->ttask = NULL;
626 }
627 if (NULL != tst->ltask)
628 {
629 GNUNET_SCHEDULER_cancel (tst->ltask);
630 tst->ltask = NULL;
631 }
632 if (NULL != tst->lsock)
633 {
634 GNUNET_NETWORK_socket_close (tst->lsock);
635 tst->lsock = NULL;
636 }
637 if (NULL != tst->nat)
638 {
639 GNUNET_NAT_unregister (tst->nat);
640 tst->nat = NULL;
641 }
642 GNUNET_free (tst);
643}
644
645/* end of nat_test.c */
diff --git a/src/nat-auto/gnunet-service-nat-auto.c b/src/nat-auto/gnunet-service-nat-auto.c
index f4e1b09e4..fafc4d382 100644
--- a/src/nat-auto/gnunet-service-nat-auto.c
+++ b/src/nat-auto/gnunet-service-nat-auto.c
@@ -27,6 +27,7 @@
27 * - merge client handle and autoconfig context 27 * - merge client handle and autoconfig context
28 * - implement "more" autoconfig: 28 * - implement "more" autoconfig:
29 * + re-work gnunet-nat-server & integrate! 29 * + re-work gnunet-nat-server & integrate!
30 * + integrate "legacy" code
30 * + test manually punched NAT (how?) 31 * + test manually punched NAT (how?)
31 */ 32 */
32#include "platform.h" 33#include "platform.h"
@@ -450,7 +451,7 @@ client_disconnect_cb (void *cls,
450 * Define "main" method using service macro. 451 * Define "main" method using service macro.
451 */ 452 */
452GNUNET_SERVICE_MAIN 453GNUNET_SERVICE_MAIN
453("nat", 454("nat-auto",
454 GNUNET_SERVICE_OPTION_NONE, 455 GNUNET_SERVICE_OPTION_NONE,
455 &run, 456 &run,
456 &client_connect_cb, 457 &client_connect_cb,
diff --git a/src/nat-auto/gnunet-service-nat-auto_legacy.c b/src/nat-auto/gnunet-service-nat-auto_legacy.c
new file mode 100644
index 000000000..061d0cbe6
--- /dev/null
+++ b/src/nat-auto/gnunet-service-nat-auto_legacy.c
@@ -0,0 +1,1081 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2015 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/nat_auto.c
23 * @brief functions for auto-configuration of the network
24 * @author Christian Grothoff
25 * @author Bruno Cabral
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_resolver_service.h"
30#include "gnunet_nat_lib.h"
31#include "nat.h"
32
33#define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
34
35
36/**
37 * How long do we wait for the NAT test to report success?
38 */
39#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
40
41#define NAT_SERVER_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
42
43/**
44 * Phases of the auto configuration.
45 */
46enum AutoPhase
47{
48 /**
49 * Initial start value.
50 */
51 AUTO_INIT = 0,
52
53 /**
54 * Test our external IP.
55 */
56 AUTO_EXTERNAL_IP,
57
58 /**
59 * Test our external IP.
60 */
61 AUTO_STUN,
62
63 /**
64 * Test our internal IP.
65 */
66 AUTO_LOCAL_IP,
67
68 /**
69 * Test if NAT was punched.
70 */
71 AUTO_NAT_PUNCHED,
72
73 /**
74 * Test if UPnP is working.
75 */
76 AUTO_UPNPC,
77
78 /**
79 * Test if ICMP server works.
80 */
81 AUTO_ICMP_SERVER,
82
83 /**
84 * Test if ICMP client works.
85 */
86 AUTO_ICMP_CLIENT,
87
88 /**
89 * Last phase, we're done.
90 */
91 AUTO_DONE
92
93};
94
95
96/**
97 * Handle to auto-configuration in progress.
98 */
99struct GNUNET_NAT_AutoHandle
100{
101
102 /**
103 * Handle to the active NAT test.
104 */
105 struct GNUNET_NAT_Test *tst;
106
107 /**
108 * Function to call when done.
109 */
110 GNUNET_NAT_AutoResultCallback fin_cb;
111
112 /**
113 * Closure for @e fin_cb.
114 */
115 void *fin_cb_cls;
116
117 /**
118 * Handle for active 'GNUNET_NAT_mini_get_external_ipv4'-operation.
119 */
120 struct GNUNET_NAT_ExternalHandle *eh;
121
122 /**
123 * Current configuration (with updates from previous phases)
124 */
125 struct GNUNET_CONFIGURATION_Handle *cfg;
126
127 /**
128 * Original configuration (used to calculate differences)
129 */
130 struct GNUNET_CONFIGURATION_Handle *initial_cfg;
131
132 /**
133 * Task identifier for the timeout.
134 */
135 struct GNUNET_SCHEDULER_Task *task;
136
137 /**
138 * Message queue to the gnunet-nat-server.
139 */
140 struct GNUNET_MQ_Handle *mq;
141
142 /**
143 * Where are we in the test?
144 */
145 enum AutoPhase phase;
146
147 /**
148 * Situation of the NAT
149 */
150 enum GNUNET_NAT_Type type;
151
152 /**
153 * Do we have IPv6?
154 */
155 int have_v6;
156
157 /**
158 * UPnP already set the external ip address ?
159 */
160 int upnp_set_external_address;
161
162 /**
163 * Did the external server connected back ?
164 */
165 int connected_back;
166
167 /**
168 * Address detected by STUN
169 */
170 char *stun_ip;
171
172 unsigned int stun_port;
173
174 /**
175 * Internal IP is the same as the public one ?
176 */
177 int internal_ip_is_public;
178
179 /**
180 * Error code for better debugging and user feedback
181 */
182 enum GNUNET_NAT_StatusCode ret;
183};
184
185
186/**
187 * The listen socket of the service for IPv4
188 */
189static struct GNUNET_NETWORK_Handle *lsock4;
190
191/**
192 * The listen task ID for IPv4
193 */
194static struct GNUNET_SCHEDULER_Task *ltask4;
195
196/**
197 * The port the test service is running on (default 7895)
198 */
199static unsigned long long port = 7895;
200
201static char *stun_server = "stun.ekiga.net";
202
203static unsigned int stun_port = 3478;
204
205
206/**
207 * Run the next phase of the auto test.
208 *
209 * @param ah auto test handle
210 */
211static void
212next_phase (struct GNUNET_NAT_AutoHandle *ah);
213
214
215static void
216process_stun_reply(struct sockaddr_in *answer,
217 struct GNUNET_NAT_AutoHandle *ah)
218{
219 ah->stun_ip = inet_ntoa(answer->sin_addr);
220 ah->stun_port = ntohs (answer->sin_port);
221 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
222 "External IP is: %s , with port %u\n",
223 ah->stun_ip,
224 ah->stun_port);
225 next_phase (ah);
226}
227
228
229/**
230 * Function that terminates the test.
231 */
232static void
233stop_stun ()
234{
235 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
236 "Stopping STUN and quitting...\n");
237 /* Clean task */
238 if (NULL != ltask4)
239 {
240 GNUNET_SCHEDULER_cancel (ltask4);
241 ltask4 = NULL;
242 }
243 /* Clean socket */
244 if (NULL != lsock4)
245 {
246 GNUNET_NETWORK_socket_close (lsock4);
247 lsock4 = NULL;
248 }
249}
250
251
252/**
253 * Activity on our incoming socket. Read data from the
254 * incoming connection.
255 *
256 * @param cls
257 */
258static void
259do_udp_read (void *cls)
260{
261 struct GNUNET_NAT_AutoHandle *ah = cls;
262 unsigned char reply_buf[1024];
263 ssize_t rlen;
264 struct sockaddr_in answer;
265 const struct GNUNET_SCHEDULER_TaskContext *tc;
266
267 tc = GNUNET_SCHEDULER_get_task_context ();
268 if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) &&
269 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
270 lsock4)))
271 {
272 rlen = GNUNET_NETWORK_socket_recv (lsock4,
273 reply_buf,
274 sizeof (reply_buf));
275
276 //Lets handle the packet
277 memset (&answer, 0, sizeof(struct sockaddr_in));
278 if (ah->phase == AUTO_NAT_PUNCHED)
279 {
280 //Destroy the connection
281 GNUNET_NETWORK_socket_close (lsock4);
282 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
283 "The external server was able to connect back");
284 ah->connected_back = GNUNET_YES;
285 next_phase (ah);
286 }
287 else
288 {
289 if (GNUNET_OK ==
290 GNUNET_NAT_stun_handle_packet (reply_buf, rlen, &answer))
291 {
292 //Process the answer
293 process_stun_reply (&answer, ah);
294 }
295 else
296 {
297 next_phase (ah);
298 }
299 }
300 }
301 else
302 {
303 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
304 "TIMEOUT while waiting for an answer\n");
305 if (ah->phase == AUTO_NAT_PUNCHED)
306 {
307 stop_stun();
308 }
309
310 next_phase (ah);
311 }
312}
313
314
315/**
316 * Create an IPv4 listen socket bound to our port.
317 *
318 * @return NULL on error
319 */
320static struct GNUNET_NETWORK_Handle *
321bind_v4 ()
322{
323 struct GNUNET_NETWORK_Handle *ls;
324 struct sockaddr_in sa4;
325 int eno;
326
327 memset (&sa4, 0, sizeof (sa4));
328 sa4.sin_family = AF_INET;
329 sa4.sin_port = htons (port);
330#if HAVE_SOCKADDR_IN_SIN_LEN
331 sa4.sin_len = sizeof (sa4);
332#endif
333 ls = GNUNET_NETWORK_socket_create (AF_INET,
334 SOCK_DGRAM,
335 0);
336 if (NULL == ls)
337 return NULL;
338 if (GNUNET_OK !=
339 GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
340 sizeof (sa4)))
341 {
342 eno = errno;
343 GNUNET_NETWORK_socket_close (ls);
344 errno = eno;
345 return NULL;
346 }
347 return ls;
348}
349
350
351static void
352request_callback (void *cls,
353 enum GNUNET_NAT_StatusCode result)
354{
355 // struct GNUNET_NAT_AutoHandle *ah = cls;
356
357 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
358 "Request callback: stop and quit\n");
359 stop_stun ();
360
361 // next_phase (ah); FIXME this always will be NULL, as called in test_stun()
362}
363
364
365/**
366 * Function called by NAT to report the outcome of the nat-test.
367 * Clean up and update GUI.
368 *
369 * @param cls the auto handle
370 * @param success currently always #GNUNET_OK
371 * @param emsg NULL on success, otherwise an error message
372 */
373static void
374result_callback (void *cls,
375 enum GNUNET_NAT_StatusCode ret)
376{
377 struct GNUNET_NAT_AutoHandle *ah = cls;
378
379 if (GNUNET_NAT_ERROR_SUCCESS == ret)
380 GNUNET_NAT_test_stop (ah->tst);
381 ah->tst = NULL;
382 ah->ret = ret;
383 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
384 GNUNET_NAT_ERROR_SUCCESS == ret
385 ? _("NAT traversal with ICMP Server succeeded.\n")
386 : _("NAT traversal with ICMP Server failed.\n"));
387 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "ENABLE_ICMP_SERVER",
388 GNUNET_NAT_ERROR_SUCCESS == ret ? "NO" : "YES");
389 next_phase (ah);
390}
391
392
393/**
394 * Main function for the connection reversal test.
395 *
396 * @param cls the `struct GNUNET_NAT_AutoHandle`
397 */
398static void
399reversal_test (void *cls)
400{
401 struct GNUNET_NAT_AutoHandle *ah = cls;
402
403 ah->task = NULL;
404 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
405 _("Testing connection reversal with ICMP server.\n"));
406 GNUNET_RESOLVER_connect (ah->cfg);
407 ah->tst = GNUNET_NAT_test_start (ah->cfg, GNUNET_YES, 0, 0, TIMEOUT,
408 &result_callback, ah);
409}
410
411
412/**
413 * Set our external IPv4 address based on the UPnP.
414 *
415 *
416 * @param cls closure with our setup context
417 * @param addr the address, NULL on errors
418 * @param emsg NULL on success, otherwise an error message
419 */
420static void
421set_external_ipv4 (void *cls,
422 const struct in_addr *addr,
423 enum GNUNET_NAT_StatusCode ret)
424{
425 struct GNUNET_NAT_AutoHandle *ah = cls;
426 char buf[INET_ADDRSTRLEN];
427
428 ah->eh = NULL;
429 ah->ret = ret;
430 if (GNUNET_NAT_ERROR_SUCCESS != ret)
431 {
432 next_phase (ah);
433 return;
434 }
435 /* enable 'behind nat' */
436 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
437 _("Detected external IP `%s'\n"),
438 inet_ntop (AF_INET,
439 addr,
440 buf,
441 sizeof (buf)));
442 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "BEHIND_NAT", "YES");
443
444 /* set external IP address */
445 if (NULL == inet_ntop (AF_INET, addr, buf, sizeof (buf)))
446 {
447 GNUNET_break (0);
448 /* actually, this should never happen, as the caller already executed just
449 * this check, but for consistency (eg: future changes in the caller)
450 * we still need to report this error...
451 */
452 ah->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID;
453 next_phase (ah);
454 return;
455 }
456 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "EXTERNAL_ADDRESS",
457 buf);
458 ah->upnp_set_external_address = GNUNET_YES;
459 next_phase (ah);
460}
461
462
463/**
464 * Determine our external IPv4 address.
465 *
466 * @param ah auto setup context
467 */
468static void
469test_external_ip (struct GNUNET_NAT_AutoHandle *ah)
470{
471 if (GNUNET_NAT_ERROR_SUCCESS != ah->ret)
472 next_phase (ah);
473
474 // FIXME: CPS?
475 /* try to detect external IP */
476 ah->eh = GNUNET_NAT_mini_get_external_ipv4 (TIMEOUT,
477 &set_external_ipv4, ah);
478}
479
480
481/**
482 * Determine our external IPv4 address and port using an external STUN server
483 *
484 * @param ah auto setup context
485 */
486static void
487test_stun (struct GNUNET_NAT_AutoHandle *ah)
488{
489
490 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running STUN test\n");
491
492 /* Get port from the configuration */
493 if (GNUNET_OK !=
494 GNUNET_CONFIGURATION_get_value_number (ah->cfg,
495 "transport-udp",
496 "PORT",
497 &port))
498 {
499 port = 2086;
500 }
501
502 //Lets create the socket
503 lsock4 = bind_v4 ();
504 if (NULL == lsock4)
505 {
506 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
507 next_phase(ah);
508 return;
509 }
510 else
511 {
512 //Lets call our function now when it accepts
513 ltask4 = GNUNET_SCHEDULER_add_read_net (NAT_SERVER_TIMEOUT,
514 lsock4,
515 &do_udp_read,
516 ah);
517 }
518
519
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "STUN service listens on port %u\n",
522 (unsigned int) port);
523 if (GNUNET_NO ==
524 GNUNET_NAT_stun_make_request (stun_server,
525 stun_port,
526 lsock4,
527 &request_callback,
528 NULL))
529 {
530 /*An error happened*/
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "STUN error, stopping\n");
532 stop_stun ();
533 next_phase (ah);
534 }
535}
536
537
538/**
539 * Process list of local IP addresses. Find and set the
540 * one of the default interface.
541 *
542 * @param cls our `struct GNUNET_NAT_AutoHandle`
543 * @param name name of the interface (can be NULL for unknown)
544 * @param isDefault is this presumably the default interface
545 * @param addr address of this interface (can be NULL for unknown or unassigned)
546 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
547 * @param netmask the network mask (can be NULL for unknown or unassigned))
548 * @param addrlen length of the @a addr and @a broadcast_addr
549 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
550 */
551static int
552process_if (void *cls,
553 const char *name,
554 int isDefault,
555 const struct sockaddr *addr,
556 const struct sockaddr *broadcast_addr,
557 const struct sockaddr *netmask,
558 socklen_t addrlen)
559{
560 struct GNUNET_NAT_AutoHandle *ah = cls;
561 const struct sockaddr_in *in;
562 char buf[INET_ADDRSTRLEN];
563
564
565 if ( (sizeof (struct sockaddr_in6) == addrlen) &&
566 (0 != memcmp (&in6addr_loopback, &((const struct sockaddr_in6 *) addr)->sin6_addr,
567 sizeof (struct in6_addr))) &&
568 (! IN6_IS_ADDR_LINKLOCAL(&((const struct sockaddr_in6 *) addr)->sin6_addr)) )
569 {
570 ah->have_v6 = GNUNET_YES;
571 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
572 _("This system has a global IPv6 address, setting IPv6 to supported.\n"));
573
574 return GNUNET_OK;
575 }
576 if (addrlen != sizeof (struct sockaddr_in))
577 return GNUNET_OK;
578 in = (const struct sockaddr_in *) addr;
579
580
581 /* set internal IP address */
582 if (NULL == inet_ntop (AF_INET, &in->sin_addr, buf, sizeof (buf)))
583 {
584 GNUNET_break (0);
585 return GNUNET_OK;
586 }
587 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "INTERNAL_ADDRESS",
588 buf);
589 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
590 _("Detected internal network address `%s'.\n"),
591 buf);
592
593
594 ah->ret = GNUNET_NAT_ERROR_SUCCESS;
595
596 /* Check if our internal IP is the same as the External detect by STUN*/
597 if(ah->stun_ip && (strcmp(buf, ah->stun_ip) == 0) )
598 {
599 ah->internal_ip_is_public = GNUNET_YES;
600 GNUNET_log (GNUNET_ERROR_TYPE_INFO,"A internal IP is the sameas the external");
601 /* No need to continue*/
602 return GNUNET_SYSERR;
603 }
604
605 /* no need to continue iteration if we found the default */
606 if (!isDefault)
607 return GNUNET_OK;
608 else
609 return GNUNET_SYSERR;
610}
611
612
613/**
614 * Determine our local IP addresses; detect internal IP & IPv6-support
615 *
616 * @param ah auto setup context
617 */
618static void
619test_local_ip (struct GNUNET_NAT_AutoHandle *ah)
620{
621 ah->have_v6 = GNUNET_NO;
622 ah->ret = GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO; // reset to success if any of the IFs in below iterator has a valid IP
623 GNUNET_OS_network_interfaces_list (&process_if, ah);
624
625 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "DISABLEV6",
626 (GNUNET_YES == ah->have_v6) ? "NO" : "YES");
627 next_phase (ah);
628}
629
630
631/**
632 * We got disconnected from the NAT server. Stop
633 * waiting for a reply.
634 *
635 * @param cls the `struct GNUNET_NAT_AutoHandle`
636 * @param error error code
637 */
638static void
639mq_error_handler (void *cls,
640 enum GNUNET_MQ_Error error)
641{
642 struct GNUNET_NAT_AutoHandle *ah = cls;
643
644 GNUNET_MQ_destroy (ah->mq);
645 ah->mq = NULL;
646 /* wait a bit first? */
647 next_phase (ah);
648}
649
650
651/**
652 * Test if NAT has been punched
653 *
654 * @param ah auto setup context
655 */
656static void
657test_nat_punched (struct GNUNET_NAT_AutoHandle *ah)
658{
659 struct GNUNET_NAT_TestMessage *msg;
660 struct GNUNET_MQ_Envelope *env;
661
662 if (! ah->stun_ip)
663 {
664 LOG (GNUNET_ERROR_TYPE_INFO,
665 "We don't have a STUN IP");
666 next_phase (ah);
667 return;
668 }
669
670 LOG (GNUNET_ERROR_TYPE_INFO,
671 "Asking gnunet-nat-server to connect to `%s'\n",
672 ah->stun_ip);
673 ah->mq = GNUNET_CLIENT_connecT (ah->cfg,
674 "gnunet-nat-server",
675 NULL,
676 &mq_error_handler,
677 ah);
678 if (NULL == ah->mq)
679 {
680 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
681 _("Failed to connect to `gnunet-nat-server'\n"));
682 next_phase (ah);
683 return;
684 }
685 env = GNUNET_MQ_msg (msg,
686 GNUNET_MESSAGE_TYPE_NAT_TEST);
687 msg->dst_ipv4 = inet_addr (ah->stun_ip);
688 msg->dport = htons (ah->stun_port);
689 msg->data = port;
690 msg->is_tcp = htonl ((uint32_t) GNUNET_NO);
691 GNUNET_MQ_send (ah->mq,
692 env);
693 if (NULL != ltask4)
694 {
695 GNUNET_SCHEDULER_cancel (ltask4);
696 ltask4 = GNUNET_SCHEDULER_add_read_net (NAT_SERVER_TIMEOUT,
697 lsock4,
698 &do_udp_read,
699 ah);
700 }
701}
702
703
704/**
705 * Test if UPnPC works.
706 *
707 * @param ah auto setup context
708 */
709static void
710test_upnpc (struct GNUNET_NAT_AutoHandle *ah)
711{
712
713 int have_upnpc;
714
715 if (GNUNET_NAT_ERROR_SUCCESS != ah->ret)
716 next_phase (ah);
717
718 // test if upnpc is available
719 have_upnpc = (GNUNET_SYSERR !=
720 GNUNET_OS_check_helper_binary ("upnpc", GNUNET_NO, NULL));
721 //FIXME: test if upnpc is actually working, that is, if transports start to work once we use UPnP
722 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
723 (have_upnpc)
724 ? _("upnpc found, enabling its use\n")
725 : _("upnpc not found\n"));
726 GNUNET_CONFIGURATION_set_value_string (ah->cfg, "nat", "ENABLE_UPNP",
727 (GNUNET_YES == have_upnpc) ? "YES" : "NO");
728 next_phase (ah);
729
730}
731
732
733/**
734 * Test if ICMP server is working
735 *
736 * @param ah auto setup context
737 */
738static void
739test_icmp_server (struct GNUNET_NAT_AutoHandle *ah)
740{
741
742 int ext_ip;
743 int nated;
744 int binary;
745 char *tmp;
746 char *helper;
747 ext_ip = GNUNET_NO;
748 nated = GNUNET_NO;
749 binary = GNUNET_NO;
750
751 tmp = NULL;
752 helper = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
753 if ( (GNUNET_OK ==
754 GNUNET_CONFIGURATION_get_value_string (ah->cfg,
755 "nat",
756 "EXTERNAL_ADDRESS",
757 &tmp)) &&
758 (0 < strlen (tmp)) )
759 {
760 ext_ip = GNUNET_OK;
761 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
762 _("test_icmp_server not possible, as we have no public IPv4 address\n"));
763 }
764 else
765 goto err;
766
767 if (GNUNET_YES ==
768 GNUNET_CONFIGURATION_get_value_yesno (ah->cfg,
769 "nat",
770 "BEHIND_NAT"))
771 {
772 nated = GNUNET_YES;
773 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
774 _("test_icmp_server not possible, as we are not behind NAT\n"));
775 }
776 else
777 goto err;
778
779 if (GNUNET_YES ==
780 GNUNET_OS_check_helper_binary (helper,
781 GNUNET_YES,
782 "-d 127.0.0.1" ))
783 {
784 binary = GNUNET_OK; // use localhost as source for that one udp-port, ok for testing
785 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
786 _("No working gnunet-helper-nat-server found\n"));
787 }
788err:
789 GNUNET_free_non_null (tmp);
790 GNUNET_free (helper);
791
792 if ( (GNUNET_OK == ext_ip) &&
793 (GNUNET_YES == nated) &&
794 (GNUNET_OK == binary) )
795 ah->task = GNUNET_SCHEDULER_add_now (&reversal_test,
796 ah);
797 else
798 next_phase (ah);
799}
800
801
802/**
803 * Test if ICMP client is working
804 *
805 * @param ah auto setup context
806 */
807static void
808test_icmp_client (struct GNUNET_NAT_AutoHandle *ah)
809{
810 char *tmp;
811 char *helper;
812
813 tmp = NULL;
814 helper = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
815 if ( (GNUNET_OK ==
816 GNUNET_CONFIGURATION_get_value_string (ah->cfg,
817 "nat",
818 "INTERNAL_ADDRESS",
819 &tmp)) &&
820 (0 < strlen (tmp)) )
821 {
822 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
823 _("test_icmp_client not possible, as we have no internal IPv4 address\n"));
824 }
825 else
826 goto err;
827
828 if (GNUNET_YES !=
829 GNUNET_CONFIGURATION_get_value_yesno (ah->cfg,
830 "nat",
831 "BEHIND_NAT"))
832 {
833 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
834 _("test_icmp_server not possible, as we are not behind NAT\n"));
835 }
836 else
837 goto err;
838
839 if (GNUNET_YES ==
840 GNUNET_OS_check_helper_binary (helper,
841 GNUNET_YES,
842 "-d 127.0.0.1 127.0.0.2 42"))
843 {
844 // none of these parameters are actually used in privilege testing mode
845 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
846 _("No working gnunet-helper-nat-server found\n"));
847 }
848err:
849 GNUNET_free_non_null (tmp);
850 GNUNET_free (helper);
851
852 next_phase (ah);
853}
854
855
856/**
857 * Run the next phase of the auto test.
858 */
859static void
860next_phase (struct GNUNET_NAT_AutoHandle *ah)
861{
862 struct GNUNET_CONFIGURATION_Handle *diff;
863
864 ah->phase++;
865 switch (ah->phase)
866 {
867 case AUTO_INIT:
868 GNUNET_assert (0);
869 break;
870 case AUTO_EXTERNAL_IP:
871 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
872 "Will run AUTO_EXTERNAL_IP\n");
873 test_external_ip (ah);
874 break;
875 case AUTO_STUN:
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
877 "Will run AUTO_STUN\n");
878 test_stun (ah);
879 break;
880 case AUTO_LOCAL_IP:
881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
882 "Will run AUTO_LOCAL_IP\n");
883 test_local_ip (ah);
884 break;
885 case AUTO_NAT_PUNCHED:
886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
887 "Will run AUTO_NAT_PUNCHED\n");
888 test_nat_punched (ah);
889 break;
890 case AUTO_UPNPC:
891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
892 "Will run AUTO_UPNPC\n");
893 test_upnpc (ah);
894 break;
895 case AUTO_ICMP_SERVER:
896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897 "Will run AUTO_ICMP_SERVER\n");
898 test_icmp_server (ah);
899 break;
900 case AUTO_ICMP_CLIENT:
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902 "Will run AUTO_ICMP_CLIENT\n");
903 test_icmp_client (ah);
904 break;
905 case AUTO_DONE:
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
907 "Done with tests\n");
908 if (!ah->internal_ip_is_public)
909 {
910 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
911 "nat",
912 "BEHIND_NAT",
913 "YES");
914
915 if (ah->connected_back)
916 {
917 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
918 "nat",
919 "PUNCHED_NAT",
920 "YES");
921 }
922 else
923 {
924 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
925 "nat",
926 "PUNCHED_NAT",
927 "NO");
928 }
929
930 if (ah->stun_ip)
931 {
932 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
933 "nat",
934 "EXTERNAL_ADDRESS",
935 ah->stun_ip);
936 if (ah->connected_back)
937 {
938 ah->type = GNUNET_NAT_TYPE_STUN_PUNCHED_NAT;
939 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
940 "nat",
941 "USE_STUN",
942 "YES");
943 }
944 else
945 {
946 ah->type = GNUNET_NAT_TYPE_UNREACHABLE_NAT;
947 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
948 "nat",
949 "USE_STUN",
950 "NO");
951 }
952
953 }
954 if (0 != ah->stun_port)
955 {
956 GNUNET_CONFIGURATION_set_value_number (ah->cfg,
957 "transport-udp",
958 "ADVERTISED_PORT",
959 ah->stun_port);
960 }
961
962 }
963 else
964 {
965 //The internal IP is the same as public, but we didn't got a incoming connection
966 if (ah->connected_back)
967 {
968 ah->type = GNUNET_NAT_TYPE_NO_NAT;
969 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
970 "nat",
971 "BEHIND_NAT",
972 "NO");
973 }
974 else
975 {
976 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
977 "nat",
978 "BEHIND_NAT",
979 "YES");
980 ah->type = GNUNET_NAT_TYPE_UNREACHABLE_NAT;
981 if (ah->stun_ip)
982 {
983 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
984 "nat",
985 "EXTERNAL_ADDRESS",
986 ah->stun_ip);
987 }
988 if (0 != ah->stun_port)
989 {
990 GNUNET_CONFIGURATION_set_value_number (ah->cfg,
991 "transport-udp",
992 "ADVERTISED_PORT",
993 ah->stun_port);
994
995 }
996 }
997 }
998
999 diff = GNUNET_CONFIGURATION_get_diff (ah->initial_cfg,
1000 ah->cfg);
1001
1002
1003 ah->fin_cb (ah->fin_cb_cls,
1004 diff,
1005 ah->ret,
1006 ah->type);
1007 GNUNET_CONFIGURATION_destroy (diff);
1008 GNUNET_NAT_autoconfig_cancel (ah);
1009 }
1010}
1011
1012
1013/**
1014 * Start auto-configuration routine. The resolver service should
1015 * be available when this function is called.
1016 *
1017 * @param cfg initial configuration
1018 * @param cb function to call with autoconfiguration result
1019 * @param cb_cls closure for @a cb
1020 * @return handle to cancel operation
1021 */
1022struct GNUNET_NAT_AutoHandle *
1023GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
1024 GNUNET_NAT_AutoResultCallback cb,
1025 void *cb_cls)
1026{
1027 struct GNUNET_NAT_AutoHandle *ah;
1028
1029 ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
1030 ah->fin_cb = cb;
1031 ah->fin_cb_cls = cb_cls;
1032 ah->ret = GNUNET_NAT_ERROR_SUCCESS;
1033 ah->cfg = GNUNET_CONFIGURATION_dup (cfg);
1034 ah->initial_cfg = GNUNET_CONFIGURATION_dup (cfg);
1035
1036 /* never use loopback addresses if user wanted autoconfiguration */
1037 GNUNET_CONFIGURATION_set_value_string (ah->cfg,
1038 "nat",
1039 "USE_LOCALADDR",
1040 "NO");
1041
1042 next_phase (ah);
1043 return ah;
1044}
1045
1046
1047/**
1048 * Abort autoconfiguration.
1049 *
1050 * @param ah handle for operation to abort
1051 */
1052void
1053GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
1054{
1055 if (NULL != ah->tst)
1056 {
1057 GNUNET_NAT_test_stop (ah->tst);
1058 ah->tst = NULL;
1059 }
1060 if (NULL != ah->eh)
1061 {
1062 GNUNET_NAT_mini_get_external_ipv4_cancel (ah->eh);
1063 ah->eh = NULL;
1064 }
1065 if (NULL != ah->mq)
1066 {
1067 GNUNET_MQ_destroy (ah->mq);
1068 ah->mq = NULL;
1069 }
1070 if (NULL != ah->task)
1071 {
1072 GNUNET_SCHEDULER_cancel (ah->task);
1073 ah->task = NULL;
1074 }
1075 GNUNET_CONFIGURATION_destroy (ah->cfg);
1076 GNUNET_CONFIGURATION_destroy (ah->initial_cfg);
1077 GNUNET_free (ah);
1078}
1079
1080
1081/* end of nat_auto.c */