aboutsummaryrefslogtreecommitdiff
path: root/src/setup/gnunet-setup-transport.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/setup/gnunet-setup-transport.c')
-rw-r--r--src/setup/gnunet-setup-transport.c483
1 files changed, 379 insertions, 104 deletions
diff --git a/src/setup/gnunet-setup-transport.c b/src/setup/gnunet-setup-transport.c
index d8b25c29..0b8f47e6 100644
--- a/src/setup/gnunet-setup-transport.c
+++ b/src/setup/gnunet-setup-transport.c
@@ -1,6 +1,6 @@
1/* 1/*
2 This file is part of GNUnet. 2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors) 3 (C) 2010, 2012 Christian Grothoff (and other contributing authors)
4 4
5 GNUnet is free software; you can redistribute it and/or modify 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 6 it under the terms of the GNU General Public License as published
@@ -22,8 +22,15 @@
22 * @file src/setup/gnunet-setup-transport.c 22 * @file src/setup/gnunet-setup-transport.c
23 * @brief support for transport (NAT) configuration 23 * @brief support for transport (NAT) configuration
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - cummulate collected information in the context
28 * - implement and refine existing network setup tests
29 * - if NAT detected and all traversal methods fail and no IPv6,
30 * set transport plugin ports to 0
25 */ 31 */
26#include "gnunet-setup.h" 32#include "gnunet-setup.h"
33#include "gnunet-setup-transport.h"
27#include <gnunet/gnunet_util_lib.h> 34#include <gnunet/gnunet_util_lib.h>
28#include <gnunet/gnunet_resolver_service.h> 35#include <gnunet/gnunet_resolver_service.h>
29#include <gnunet/gnunet_nat_lib.h> 36#include <gnunet/gnunet_nat_lib.h>
@@ -31,19 +38,105 @@
31/** 38/**
32 * How long do we wait for the NAT test to report success? 39 * How long do we wait for the NAT test to report success?
33 */ 40 */
34#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) 41#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
35 42
36/** 43/**
37 * Handle to the active NAT test. 44 * Phases of the auto configuration.
38 */ 45 */
39static struct GNUNET_NAT_Test *tst; 46enum AutoPhase
47{
48 /**
49 * Initial start value.
50 */
51 AUTO_INIT = 0,
52
53 /**
54 * Test if we are online.
55 */
56 AUTO_ONLINE = 1,
57
58 /**
59 * Test our external IP.
60 */
61 AUTO_EXTERNAL_IP,
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
40 95
41/** 96/**
42 * Task identifier for the timeout. 97 * Context for the autoconfig test.
43 */ 98 */
44static GNUNET_SCHEDULER_TaskIdentifier tsk; 99struct GNUNET_SetupAutoContext
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_SetupAutoConfigFinished fin_cb;
111
112 /**
113 * Closure for '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 * Task identifier for the timeout.
124 */
125 GNUNET_SCHEDULER_TaskIdentifier tsk;
126
127 /**
128 * Where are we in the test?
129 */
130 enum AutoPhase phase;
131
132};
45 133
46static struct GNUNET_OS_Process *resolver; 134
135/**
136 * Run the next phase of the auto test.
137 */
138static void
139next_phase (struct GNUNET_SetupAutoContext *ac);
47 140
48 141
49/** 142/**
@@ -78,16 +171,14 @@ update_icmp_server_enable_button (int on)
78static void 171static void
79result_callback (void *cls, int success) 172result_callback (void *cls, int success)
80{ 173{
81 GNUNET_SCHEDULER_cancel (tsk); 174 struct GNUNET_SetupAutoContext *ac = cls;
82 tsk = GNUNET_SCHEDULER_NO_TASK; 175
83 GNUNET_NAT_test_stop (tst); 176 GNUNET_SCHEDULER_cancel (ac->tsk);
84 tst = NULL; 177 ac->tsk = GNUNET_SCHEDULER_NO_TASK;
85 if (NULL != resolver) 178 GNUNET_NAT_test_stop (ac->tst);
86 { 179 ac->tst = NULL;
87 GNUNET_break (0 == GNUNET_OS_process_kill (resolver, SIGTERM));
88 GNUNET_OS_process_destroy (resolver);
89 }
90 update_icmp_server_enable_button (success); 180 update_icmp_server_enable_button (success);
181 next_phase (ac);
91} 182}
92 183
93 184
@@ -95,17 +186,20 @@ result_callback (void *cls, int success)
95 * Function called if NAT failed to confirm success. 186 * Function called if NAT failed to confirm success.
96 * Clean up and update GUI (with failure). 187 * Clean up and update GUI (with failure).
97 * 188 *
98 * @param cls closure (unused) 189 * @param cls closure with setup context
99 * @param tc scheduler callback 190 * @param tc scheduler callback
100 */ 191 */
101static void 192static void
102fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 193fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
103{ 194{
104 GNUNET_assert (NULL != tst); 195 struct GNUNET_SetupAutoContext *ac = cls;
105 tsk = GNUNET_SCHEDULER_NO_TASK; 196
106 GNUNET_NAT_test_stop (tst); 197 GNUNET_assert (NULL != ac->tst);
107 tst = NULL; 198 ac->tsk = GNUNET_SCHEDULER_NO_TASK;
199 GNUNET_NAT_test_stop (ac->tst);
200 ac->tst = NULL;
108 update_icmp_server_enable_button (GNUNET_NO); 201 update_icmp_server_enable_button (GNUNET_NO);
202 next_phase (ac);
109} 203}
110 204
111 205
@@ -118,32 +212,92 @@ fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
118static void 212static void
119reversal_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) 213reversal_test (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
120{ 214{
121 int *ok = cls; 215 struct GNUNET_SetupAutoContext *ac = cls;
122 216
123 GNUNET_assert (NULL != cfg); 217 GNUNET_assert (NULL != cfg);
124 GNUNET_RESOLVER_connect (cfg); 218 GNUNET_RESOLVER_connect (cfg);
125 tst = GNUNET_NAT_test_start (cfg, GNUNET_YES, 0, 0, &result_callback, ok); 219 ac->tst = GNUNET_NAT_test_start (cfg, GNUNET_YES, 0, 0, &result_callback, ac);
126 if (NULL == tst) 220 if (NULL == ac->tst)
127 { 221 {
128 *ok = GNUNET_SYSERR; 222 next_phase (ac);
129 return; 223 return;
130 } 224 }
131 tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, ok); 225 ac->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, ac);
132} 226}
133 227
228
134/** 229/**
135 * Test if connection reversal (ICMP method) works. 230 * Test if we are online at all.
231 *
232 * @param ac auto setup context
136 */ 233 */
137static void 234static void
138test_connection_reversal () 235test_online (struct GNUNET_SetupAutoContext *ac)
139{ 236{
140 if (NULL != resolver) 237 // FIXME: not implemented
141 return; /* test already active!? */ 238 next_phase (ac);
142 resolver = 239}
143 GNUNET_OS_start_process (GNUNET_YES, GNUNET_OS_INHERIT_STD_ALL, 240
144 NULL, NULL, "gnunet-service-resolver", 241
145 "gnunet-service-resolver", NULL); 242/**
146 GNUNET_SCHEDULER_add_now (&reversal_test, NULL); 243 * Set our external IPv4 address.
244 *
245 * @param cls closure with our setup context
246 * @param addr the address, NULL on errors
247 */
248static void
249set_external_ipv4 (void *cls, const struct in_addr *addr)
250{
251 struct GNUNET_SetupAutoContext *ac = cls;
252 char buf[INET_ADDRSTRLEN];
253 GObject *o;
254
255 ac->eh = NULL;
256 if (NULL == addr)
257 {
258 next_phase (ac);
259 return;
260 }
261 /* enable 'behind nat' */
262 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
263 _("Detected external IP `%s'\n"),
264 inet_ntop (AF_INET,
265 addr,
266 buf,
267 sizeof (buf)));
268 if (NULL != cfg)
269 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "BEHIND_NAT", "YES");
270 o = GNUNET_SETUP_get_object ("GNUNET_setup_transport_nat_checkbutton");
271 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (o), TRUE);
272
273 /* set external IP address */
274 if (NULL == inet_ntop (AF_INET, addr, buf, sizeof (buf)))
275 {
276 GNUNET_break (0);
277 next_phase (ac);
278 return;
279 }
280 if (NULL != cfg)
281 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "EXTERNAL_ADDRESS",
282 buf);
283 o = GNUNET_SETUP_get_object ("GNUNET_setup_transport_external_ip_address_entry");
284 gtk_entry_set_text (GTK_ENTRY (o), buf);
285 next_phase (ac);
286}
287
288
289/**
290 * Determine our external IPv4 address.
291 *
292 * @param ac auto setup context
293 */
294static void
295test_external_ip (struct GNUNET_SetupAutoContext *ac)
296{
297 // FIXME: CPS?
298 /* try to detect external IP */
299 ac->eh = GNUNET_NAT_mini_get_external_ipv4 (TIMEOUT,
300 &set_external_ipv4, ac);
147} 301}
148 302
149 303
@@ -151,7 +305,7 @@ test_connection_reversal ()
151 * Process list of local IP addresses. Find and set the 305 * Process list of local IP addresses. Find and set the
152 * one of the default interface. 306 * one of the default interface.
153 * 307 *
154 * @param cls closure (not used) 308 * @param cls pointer to int to store if we have a non-local IPv6 address
155 * @param name name of the interface (can be NULL for unknown) 309 * @param name name of the interface (can be NULL for unknown)
156 * @param isDefault is this presumably the default interface 310 * @param isDefault is this presumably the default interface
157 * @param addr address of this interface (can be NULL for unknown or unassigned) 311 * @param addr address of this interface (can be NULL for unknown or unassigned)
@@ -165,12 +319,21 @@ nipo (void *cls, const char *name, int isDefault, const struct sockaddr *addr,
165 const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, 319 const struct sockaddr *broadcast_addr, const struct sockaddr *netmask,
166 socklen_t addrlen) 320 socklen_t addrlen)
167{ 321{
322 int *have_v6 = cls;
168 const struct sockaddr_in *in; 323 const struct sockaddr_in *in;
169 char buf[INET_ADDRSTRLEN]; 324 char buf[INET_ADDRSTRLEN];
170 GtkEntry *entry; 325 GtkEntry *entry;
171 326
172 if (!isDefault) 327 if (!isDefault)
173 return GNUNET_OK; 328 return GNUNET_OK;
329 if ( (sizeof (struct sockaddr_in6) == addrlen) &&
330 (0 != memcmp (&in6addr_loopback, addr,
331 addrlen)) &&
332 (! IN6_IS_ADDR_LINKLOCAL(addr)) )
333 {
334 *have_v6 = GNUNET_YES;
335 return GNUNET_OK;
336 }
174 if (addrlen != sizeof (struct sockaddr_in)) 337 if (addrlen != sizeof (struct sockaddr_in))
175 return GNUNET_OK; 338 return GNUNET_OK;
176 in = (const struct sockaddr_in *) addr; 339 in = (const struct sockaddr_in *) addr;
@@ -185,11 +348,6 @@ nipo (void *cls, const char *name, int isDefault, const struct sockaddr *addr,
185 entry = 348 entry =
186 GTK_ENTRY (GNUNET_SETUP_get_object 349 GTK_ENTRY (GNUNET_SETUP_get_object
187 ("GNUNET_setup_transport_internal_ip_entry")); 350 ("GNUNET_setup_transport_internal_ip_entry"));
188 if (entry == NULL)
189 {
190 GNUNET_break (0);
191 return GNUNET_SYSERR;
192 }
193 gtk_entry_set_text (entry, buf); 351 gtk_entry_set_text (entry, buf);
194 /* no need to continue iteration */ 352 /* no need to continue iteration */
195 return GNUNET_SYSERR; 353 return GNUNET_SYSERR;
@@ -197,80 +355,80 @@ nipo (void *cls, const char *name, int isDefault, const struct sockaddr *addr,
197 355
198 356
199/** 357/**
200 * Set our external IPv4 address. 358 * Determine our local IP addresses; detect internal IP & IPv6-support
201 * 359 *
202 * @param cls closure 360 * @param ac auto setup context
203 * @param addr the address, NULL on errors
204 */ 361 */
205static void 362static void
206set_external_ipv4 (void *cls, const struct in_addr *addr) 363test_local_ip (struct GNUNET_SetupAutoContext *ac)
207{ 364{
208 char buf[INET_ADDRSTRLEN];
209 GObject *o;
210 GtkEntry *entry;
211 GtkToggleButton *button; 365 GtkToggleButton *button;
366 int have_v6;
367
368 have_v6 = GNUNET_NO;
369 GNUNET_OS_network_interfaces_list (&nipo, &have_v6);
370 button = GTK_TOGGLE_BUTTON (GNUNET_SETUP_get_object ("GNUNET_setup_transport_disable_ipv6_checkbutton"));
371 gtk_toggle_button_set_active (button,
372 (GNUNET_YES == have_v6) ? FALSE : TRUE);
373 if (NULL != cfg)
374 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "DISABLEV6",
375 (GNUNET_YES == have_v6) ? "NO" : "YES");
376 next_phase (ac);
377}
212 378
213 if (NULL != addr) 379
214 { 380/**
215 /* enable 'behind nat' */ 381 * Test if NAT has been punched
216 if (NULL != cfg) 382 *
217 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "BEHIND_NAT", "YES"); 383 * @param ac auto setup context
218 o = GNUNET_SETUP_get_object ("GNUNET_setup_transport_nat_checkbutton"); 384 */
219 if (NULL != o) 385static void
220 { 386test_nat_punched (struct GNUNET_SetupAutoContext *ac)
221 button = GTK_TOGGLE_BUTTON (o); 387{
222 if (button == NULL) 388 // FIXME: not implemented
223 { 389 next_phase (ac);
224 GNUNET_break (0);
225 return;
226 }
227 gtk_toggle_button_set_active (button, TRUE);
228 }
229
230 /* set external IP address */
231 if (NULL == inet_ntop (AF_INET, addr, buf, sizeof (buf)))
232 {
233 GNUNET_break (0);
234 return;
235 }
236 if (NULL != cfg)
237 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "EXTERNAL_ADDRESS",
238 buf);
239 o = GNUNET_SETUP_get_object
240 ("GNUNET_setup_transport_external_ip_address_entry");
241 if (NULL != o)
242 {
243 entry = GTK_ENTRY (o);
244 if (entry == NULL)
245 {
246 GNUNET_break (0);
247 return;
248 }
249 gtk_entry_set_text (entry, buf);
250 }
251 }
252} 390}
253 391
254 392
255/** 393/**
256 * User asked for autoconfiguration. Try the full program. 394 * Test if UPnPC works.
395 *
396 * @param ac auto setup context
257 */ 397 */
258void 398static void
259GNUNET_setup_transport_autoconfig_button_clicked_cb () 399test_upnpc (struct GNUNET_SetupAutoContext *ac)
260{ 400{
401 int have_upnpc;
261 GtkToggleButton *button; 402 GtkToggleButton *button;
262 int hns;
263 int hnc;
264 char *tmp;
265 403
266 /* try to detect external IP */ 404 /* test if upnpc is available */
267 (void) GNUNET_NAT_mini_get_external_ipv4 (TIMEOUT, &set_external_ipv4, NULL); 405 button = GTK_TOGGLE_BUTTON (GNUNET_SETUP_get_object ("GNUNET_setup_transport_upnp_enable_checkbutton"));
268 /* Try to detect internal IP */ 406 have_upnpc = (GNUNET_SYSERR !=
269 GNUNET_OS_network_interfaces_list (&nipo, NULL); 407 GNUNET_OS_check_helper_binary ("upnpc"));
408 /* FIXME: test if upnpc is actually working, that is, if transports
409 start to work once we use UPnP */
410 gtk_toggle_button_set_active (button,
411 have_upnpc
412 ? TRUE
413 : FALSE);
414 if (NULL != cfg)
415 GNUNET_CONFIGURATION_set_value_string (cfg, "nat", "ENABLE_UPNP",
416 (GNUNET_YES == have_upnpc) ? "YES" : "NO");
417 next_phase (ac);
418}
270 419
271 /* FIXME: do more: test if UPnP works */
272 420
273 /* test gnunet-helper-nat-server */ 421/**
422 * Test if ICMP server is working
423 *
424 * @param ac auto setup context
425 */
426static void
427test_icmp_server (struct GNUNET_SetupAutoContext *ac)
428{
429 int hns;
430 char *tmp;
431
274 tmp = NULL; 432 tmp = NULL;
275 hns = 433 hns =
276 ((GNUNET_OK == 434 ((GNUNET_OK ==
@@ -282,9 +440,24 @@ GNUNET_setup_transport_autoconfig_button_clicked_cb ()
282 GNUNET_OS_check_helper_binary ("gnunet-helper-nat-server"))); 440 GNUNET_OS_check_helper_binary ("gnunet-helper-nat-server")));
283 GNUNET_free_non_null (tmp); 441 GNUNET_free_non_null (tmp);
284 if (hns) 442 if (hns)
285 test_connection_reversal (); 443 GNUNET_SCHEDULER_add_now (&reversal_test, ac);
444 else
445 next_phase (ac);
446}
447
448
449/**
450 * Test if ICMP client is working
451 *
452 * @param ac auto setup context
453 */
454static void
455test_icmp_client (struct GNUNET_SetupAutoContext *ac)
456{
457 GtkToggleButton *button;
458 int hnc;
459 char *tmp;
286 460
287 /* test gnunet-helper-nat-client */
288 tmp = NULL; 461 tmp = NULL;
289 hnc = 462 hnc =
290 ((GNUNET_OK == 463 ((GNUNET_OK ==
@@ -298,12 +471,114 @@ GNUNET_setup_transport_autoconfig_button_clicked_cb ()
298 button = 471 button =
299 GTK_TOGGLE_BUTTON (GNUNET_SETUP_get_object 472 GTK_TOGGLE_BUTTON (GNUNET_SETUP_get_object
300 ("GNUNET_setup_transport_icmp_client_enable_checkbutton")); 473 ("GNUNET_setup_transport_icmp_client_enable_checkbutton"));
301 if (button == NULL) 474 gtk_toggle_button_set_active (button, hnc ? TRUE : FALSE);
475 next_phase (ac);
476}
477
478
479/**
480 * User asked for autoconfiguration. Try the full program.
481 *
482 * @param fin_cb function to call when done
483 * @param fin_cb_cls closure for 'fin_cb'
484 * @return handle for the operation
485 */
486struct GNUNET_SetupAutoContext *
487GNUNET_setup_transport_autoconfig_start (GNUNET_SetupAutoConfigFinished fin_cb,
488 void *fin_cb_cls)
489{
490 struct GNUNET_SetupAutoContext *ac;
491
492 ac = GNUNET_malloc (sizeof (struct GNUNET_SetupAutoContext));
493 ac->fin_cb = fin_cb;
494 ac->fin_cb_cls = fin_cb_cls;
495
496 /* never use loopback addresses if user wanted autoconfiguration */
497 GNUNET_CONFIGURATION_set_value_string (cfg, "nat",
498 "USE_LOCALADDR",
499 "NO");
500 next_phase (ac);
501 return ac;
502}
503
504
505/**
506 * Run the next phase of the auto test.
507 */
508static void
509next_phase (struct GNUNET_SetupAutoContext *ac)
510{
511 ac->phase++;
512 switch (ac->phase)
302 { 513 {
303 GNUNET_break (0); 514 case AUTO_INIT:
515 GNUNET_assert (0);
516 break;
517 case AUTO_ONLINE:
518 test_online (ac);
519 break;
520 case AUTO_EXTERNAL_IP:
521 test_external_ip (ac);
522 break;
523 case AUTO_LOCAL_IP:
524 test_local_ip (ac);
525 break;
526 case AUTO_NAT_PUNCHED:
527 test_nat_punched (ac);
528 break;
529 case AUTO_UPNPC:
530 test_upnpc (ac);
531 break;
532 case AUTO_ICMP_SERVER:
533 test_icmp_server (ac);
534 break;
535 case AUTO_ICMP_CLIENT:
536 test_icmp_client (ac);
537 break;
538 case AUTO_DONE:
539 ac->fin_cb (ac->fin_cb_cls);
540 GNUNET_free (ac);
304 return; 541 return;
305 } 542 }
306 gtk_toggle_button_set_active (button, hnc ? TRUE : FALSE);
307} 543}
308 544
545
546/**
547 * Autoconfiguration test is finished, clear the block so
548 * that it can be run again.
549 *
550 * @param cls pointer to the location that needs to be NULLed
551 */
552static void
553clear_ac (void *cls)
554{
555 struct GNUNET_SetupAutoContext **acp = cls;
556
557 *acp = NULL;
558 gtk_widget_set_sensitive (GTK_WIDGET (GNUNET_SETUP_get_object ("GNUNET_setup_transport_autoconfig_button")),
559 TRUE);
560}
561
562
563/**
564 * User asked for autoconfiguration. Try the full program
565 */
566void
567GNUNET_setup_transport_autoconfig_button_clicked_cb ()
568{
569 static struct GNUNET_SetupAutoContext *ac;
570
571 /* make sure only one test is running at a time */
572 if (NULL != ac)
573 {
574 GNUNET_break (0);
575 return;
576 }
577 gtk_widget_set_sensitive (GTK_WIDGET (GNUNET_SETUP_get_object ("GNUNET_setup_transport_autoconfig_button")),
578 FALSE);
579 ac = GNUNET_setup_transport_autoconfig_start (&clear_ac,
580 &ac);
581}
582
583
309/* end of gnunet-setup-transport.c */ 584/* end of gnunet-setup-transport.c */