aboutsummaryrefslogtreecommitdiff
path: root/src/nat-auto/gnunet-service-nat-auto_legacy.c
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/gnunet-service-nat-auto_legacy.c
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/gnunet-service-nat-auto_legacy.c')
-rw-r--r--src/nat-auto/gnunet-service-nat-auto_legacy.c1081
1 files changed, 1081 insertions, 0 deletions
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 */