diff options
author | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2016-12-27 16:43:48 +0100 |
---|---|---|
committer | Schanzenbach, Martin <mschanzenbach@posteo.de> | 2016-12-27 16:43:48 +0100 |
commit | 43b34377e10d329075327104e4a295ee9d3c53b4 (patch) | |
tree | 29819274064fba2cfa159ce94fe1862d0ae82969 | |
parent | b0937948acc28e39ac2ed53799dbc63bad8b2936 (diff) | |
parent | 9ba4c1d15e6bcb20c47dff1067ab76e86d7c0f8a (diff) | |
download | gnunet-43b34377e10d329075327104e4a295ee9d3c53b4.tar.gz gnunet-43b34377e10d329075327104e4a295ee9d3c53b4.zip |
Merge remote-tracking branch 'origin/master' into credentials
-rw-r--r-- | doc/man/gnunet-nat.1 | 52 | ||||
-rw-r--r-- | src/include/gnunet_configuration_lib.h | 2 | ||||
-rw-r--r-- | src/include/gnunet_nat_service.h | 10 | ||||
-rw-r--r-- | src/nat/Makefile.am | 1 | ||||
-rw-r--r-- | src/nat/gnunet-nat-server.c | 44 | ||||
-rw-r--r-- | src/nat/gnunet-nat.c | 108 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat.c | 1392 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_mini.c | 763 | ||||
-rw-r--r-- | src/nat/gnunet-service-nat_mini.h | 127 | ||||
-rw-r--r-- | src/nat/nat.h | 2 | ||||
-rw-r--r-- | src/nat/nat_api.c | 27 | ||||
-rw-r--r-- | src/nat/nat_api_stun.c | 4 | ||||
-rw-r--r-- | src/nat/nat_stun.h | 21 | ||||
-rw-r--r-- | src/util/util.conf | 10 |
14 files changed, 2219 insertions, 344 deletions
diff --git a/doc/man/gnunet-nat.1 b/doc/man/gnunet-nat.1 index a43223fa8..2ba236399 100644 --- a/doc/man/gnunet-nat.1 +++ b/doc/man/gnunet-nat.1 | |||
@@ -39,10 +39,6 @@ Assuming we are listening at ADDRESS for connection reversal requests. | |||
39 | Ask the peer at ADDRESS for connection reversal, using the local address for the target address of the reversal. | 39 | Ask the peer at ADDRESS for connection reversal, using the local address for the target address of the reversal. |
40 | 40 | ||
41 | .B | 41 | .B |
42 | .IP "\-L, \-\-listen" | ||
43 | Listen for connection reversal requests. | ||
44 | |||
45 | .B | ||
46 | .IP "\-p PORT, \-\-port=PORT" | 42 | .IP "\-p PORT, \-\-port=PORT" |
47 | Use PORT as our external port for advertising for incoming requests. | 43 | Use PORT as our external port for advertising for incoming requests. |
48 | 44 | ||
@@ -58,6 +54,54 @@ Use TCP. | |||
58 | .IP "\-u, \-\-udp" | 54 | .IP "\-u, \-\-udp" |
59 | Use UDP. | 55 | Use UDP. |
60 | 56 | ||
57 | .B | ||
58 | .IP "\-w, \-\-write" | ||
59 | Write configuration to configuration file, useful in combination with autoconfiguration (\-a). | ||
60 | |||
61 | .B | ||
62 | .IP "\-W, \-\-watch" | ||
63 | Watch for connection reversal requests. | ||
64 | |||
65 | .SH EXAMPLES | ||
66 | .PP | ||
67 | |||
68 | \fBBasic examples\fR | ||
69 | |||
70 | We are bound to "0.0.0.0:8080" on UDP and want to obtain all applicable IP addresses: | ||
71 | |||
72 | # gnunet-nat -i 0.0.0.0:8080 -u | ||
73 | |||
74 | We are bound to "::0" on port 8080 on TCP and want to obtain all applicable IP addresses: | ||
75 | |||
76 | # gnunet-nat -i '[::0]':8080 -t | ||
77 | |||
78 | We are bound to "127.0.0.1:8080" on UDP and want to obtain all applicable IP addresses: | ||
79 | |||
80 | # gnunet-nat -i 127.0.0.1:8080 -u | ||
81 | |||
82 | \fBICMP-based NAT traversal:\fR | ||
83 | |||
84 | Watch for connection reversal request: | ||
85 | |||
86 | # gnunet-nat FIXME | ||
87 | |||
88 | Initiate connection reversal request: | ||
89 | |||
90 | # gnunet-nat FIXME | ||
91 | |||
92 | \fBSTUN-based XXX:\fR | ||
93 | |||
94 | XXX: | ||
95 | |||
96 | # gnunet-nat FIXME -s | ||
97 | |||
98 | \fBAutomatic configuration:\fR | ||
99 | |||
100 | Probe and write result to configuration: | ||
101 | |||
102 | # gnunet-nat -aw | ||
103 | |||
104 | |||
61 | .SH BUGS | 105 | .SH BUGS |
62 | Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org> | 106 | Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <gnunet\-developers@gnu.org> |
63 | 107 | ||
diff --git a/src/include/gnunet_configuration_lib.h b/src/include/gnunet_configuration_lib.h index 945f3ca59..746dea61f 100644 --- a/src/include/gnunet_configuration_lib.h +++ b/src/include/gnunet_configuration_lib.h | |||
@@ -89,7 +89,7 @@ GNUNET_CONFIGURATION_load (struct GNUNET_CONFIGURATION_Handle *cfg, | |||
89 | 89 | ||
90 | /** | 90 | /** |
91 | * Load default configuration. This function will parse the | 91 | * Load default configuration. This function will parse the |
92 | * defaults from the given defaults_d directory. | 92 | * defaults from the given @a defaults_d directory. |
93 | * | 93 | * |
94 | * @param cfg configuration to update | 94 | * @param cfg configuration to update |
95 | * @param defaults_d directory with the defaults | 95 | * @param defaults_d directory with the defaults |
diff --git a/src/include/gnunet_nat_service.h b/src/include/gnunet_nat_service.h index b66b44240..4df17b531 100644 --- a/src/include/gnunet_nat_service.h +++ b/src/include/gnunet_nat_service.h | |||
@@ -83,7 +83,7 @@ enum GNUNET_NAT_AddressClass | |||
83 | /** | 83 | /** |
84 | * Addresses useful in the local wired network, | 84 | * Addresses useful in the local wired network, |
85 | * i.e. a MAC. Sensitive, but obvious to people nearby. | 85 | * i.e. a MAC. Sensitive, but obvious to people nearby. |
86 | 86 | * | |
87 | * Useful for broadcasts. | 87 | * Useful for broadcasts. |
88 | */ | 88 | */ |
89 | GNUNET_NAT_AC_LAN = 8, | 89 | GNUNET_NAT_AC_LAN = 8, |
@@ -114,11 +114,13 @@ enum GNUNET_NAT_AddressClass | |||
114 | GNUNET_NAT_AC_LOOPBACK = 64, | 114 | GNUNET_NAT_AC_LOOPBACK = 64, |
115 | 115 | ||
116 | /** | 116 | /** |
117 | * Addresses that should be our global external IP address | 117 | * Addresses that should be our external IP address |
118 | * on the outside of a NAT. Might be incorrectly determined. | 118 | * on the outside of a NAT. Might be incorrectly determined. |
119 | * Used as a bit in combination with #GNUNET_NAT_AC_GLOBAL. | 119 | * Used as a bit in combination with #GNUNET_NAT_AC_GLOBAL, |
120 | * or in case of double-NAT with | ||
121 | * #GNUNET_NAT_AC_LAN. | ||
120 | */ | 122 | */ |
121 | GNUNET_NAT_AC_GLOBAL_EXTERN = 128, | 123 | GNUNET_NAT_AC_EXTERN = 128, |
122 | 124 | ||
123 | /** | 125 | /** |
124 | * Bitmask for "any" address. | 126 | * Bitmask for "any" address. |
diff --git a/src/nat/Makefile.am b/src/nat/Makefile.am index c62a8d2cf..1dd8e44b9 100644 --- a/src/nat/Makefile.am +++ b/src/nat/Makefile.am | |||
@@ -98,6 +98,7 @@ libgnunetnatnew_la_LDFLAGS = \ | |||
98 | gnunet_service_nat_SOURCES = \ | 98 | gnunet_service_nat_SOURCES = \ |
99 | gnunet-service-nat.c \ | 99 | gnunet-service-nat.c \ |
100 | gnunet-service-nat_stun.c gnunet-service-nat_stun.h \ | 100 | gnunet-service-nat_stun.c gnunet-service-nat_stun.h \ |
101 | gnunet-service-nat_mini.c gnunet-service-nat_mini.h \ | ||
101 | gnunet-service-nat_helper.c gnunet-service-nat_helper.h | 102 | gnunet-service-nat_helper.c gnunet-service-nat_helper.h |
102 | gnunet_service_nat_LDADD = \ | 103 | gnunet_service_nat_LDADD = \ |
103 | $(top_builddir)/src/util/libgnunetutil.la \ | 104 | $(top_builddir)/src/util/libgnunetutil.la \ |
diff --git a/src/nat/gnunet-nat-server.c b/src/nat/gnunet-nat-server.c index 6722deefb..1692a8ef1 100644 --- a/src/nat/gnunet-nat-server.c +++ b/src/nat/gnunet-nat-server.c | |||
@@ -42,8 +42,7 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; | |||
42 | 42 | ||
43 | 43 | ||
44 | /** | 44 | /** |
45 | * Try contacting the peer using autonomous | 45 | * Try contacting the peer using autonomous NAT traveral method. |
46 | * NAT traveral method. | ||
47 | * | 46 | * |
48 | * @param dst_ipv4 IPv4 address to send the fake ICMP message | 47 | * @param dst_ipv4 IPv4 address to send the fake ICMP message |
49 | * @param dport destination port to include in ICMP message | 48 | * @param dport destination port to include in ICMP message |
@@ -78,7 +77,7 @@ try_anat (uint32_t dst_ipv4, | |||
78 | 77 | ||
79 | 78 | ||
80 | /** | 79 | /** |
81 | * Closure for 'tcp_send'. | 80 | * Closure for #tcp_send. |
82 | */ | 81 | */ |
83 | struct TcpContext | 82 | struct TcpContext |
84 | { | 83 | { |
@@ -98,7 +97,7 @@ struct TcpContext | |||
98 | * Task called by the scheduler once we can do the TCP send | 97 | * Task called by the scheduler once we can do the TCP send |
99 | * (or once we failed to connect...). | 98 | * (or once we failed to connect...). |
100 | * | 99 | * |
101 | * @param cls the 'struct TcpContext' | 100 | * @param cls the `struct TcpContext` |
102 | */ | 101 | */ |
103 | static void | 102 | static void |
104 | tcp_send (void *cls) | 103 | tcp_send (void *cls) |
@@ -182,7 +181,7 @@ try_send_tcp (uint32_t dst_ipv4, | |||
182 | 181 | ||
183 | /** | 182 | /** |
184 | * Try to send @a data to the | 183 | * Try to send @a data to the |
185 | * IP @a dst_ipv4' at port @a dport via UDP. | 184 | * IP @a dst_ipv4 at port @a dport via UDP. |
186 | * | 185 | * |
187 | * @param dst_ipv4 target IP | 186 | * @param dst_ipv4 target IP |
188 | * @param dport target port | 187 | * @param dport target port |
@@ -313,12 +312,13 @@ run (void *cls, | |||
313 | }; | 312 | }; |
314 | 313 | ||
315 | cfg = c; | 314 | cfg = c; |
316 | if ((args[0] == NULL) || (1 != SSCANF (args[0], "%u", &port)) || (0 == port) | 315 | if ( (NULL == args[0]) || |
317 | || (65536 <= port)) | 316 | (1 != SSCANF (args[0], "%u", &port)) || |
317 | (0 == port) || | ||
318 | (65536 <= port) ) | ||
318 | { | 319 | { |
319 | FPRINTF (stderr, | 320 | FPRINTF (stderr, |
320 | _ | 321 | _("Please pass valid port number as the first argument! (got `%s')\n"), |
321 | ("Please pass valid port number as the first argument! (got `%s')\n"), | ||
322 | args[0]); | 322 | args[0]); |
323 | return; | 323 | return; |
324 | } | 324 | } |
@@ -332,10 +332,14 @@ run (void *cls, | |||
332 | in4.sin_len = sizeof (in4); | 332 | in4.sin_len = sizeof (in4); |
333 | in6.sin6_len = sizeof (in6); | 333 | in6.sin6_len = sizeof (in6); |
334 | #endif | 334 | #endif |
335 | server = | 335 | server = GNUNET_SERVER_create (NULL, |
336 | GNUNET_SERVER_create (NULL, NULL, (struct sockaddr * const *) sa, slen, | 336 | NULL, |
337 | GNUNET_TIME_UNIT_SECONDS, GNUNET_YES); | 337 | (struct sockaddr * const *) sa, |
338 | GNUNET_SERVER_add_handlers (server, handlers); | 338 | slen, |
339 | GNUNET_TIME_UNIT_SECONDS, | ||
340 | GNUNET_YES); | ||
341 | GNUNET_SERVER_add_handlers (server, | ||
342 | handlers); | ||
339 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | 343 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, |
340 | NULL); | 344 | NULL); |
341 | } | 345 | } |
@@ -355,13 +359,19 @@ main (int argc, char *const argv[]) | |||
355 | GNUNET_GETOPT_OPTION_END | 359 | GNUNET_GETOPT_OPTION_END |
356 | }; | 360 | }; |
357 | 361 | ||
358 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | 362 | if (GNUNET_OK != |
363 | GNUNET_STRINGS_get_utf8_args (argc, argv, | ||
364 | &argc, &argv)) | ||
359 | return 2; | 365 | return 2; |
360 | 366 | ||
361 | if (GNUNET_OK != | 367 | if (GNUNET_OK != |
362 | GNUNET_PROGRAM_run (argc, argv, "gnunet-nat-server [options] PORT", | 368 | GNUNET_PROGRAM_run (argc, |
363 | _("GNUnet NAT traversal test helper daemon"), options, | 369 | argv, |
364 | &run, NULL)) | 370 | "gnunet-nat-server [options] PORT", |
371 | _("GNUnet NAT traversal test helper daemon"), | ||
372 | options, | ||
373 | &run, | ||
374 | NULL)) | ||
365 | { | 375 | { |
366 | GNUNET_free ((void*) argv); | 376 | GNUNET_free ((void*) argv); |
367 | return 1; | 377 | return 1; |
diff --git a/src/nat/gnunet-nat.c b/src/nat/gnunet-nat.c index 10921150d..4d0ed5723 100644 --- a/src/nat/gnunet-nat.c +++ b/src/nat/gnunet-nat.c | |||
@@ -59,6 +59,22 @@ static int listen_reversal; | |||
59 | static int use_tcp; | 59 | static int use_tcp; |
60 | 60 | ||
61 | /** | 61 | /** |
62 | * If we do auto-configuration, should we write the result | ||
63 | * to a file? | ||
64 | */ | ||
65 | static int write_cfg; | ||
66 | |||
67 | /** | ||
68 | * Configuration filename. | ||
69 | */ | ||
70 | static const char *cfg_file; | ||
71 | |||
72 | /** | ||
73 | * Original configuration. | ||
74 | */ | ||
75 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
76 | |||
77 | /** | ||
62 | * Protocol to use. | 78 | * Protocol to use. |
63 | */ | 79 | */ |
64 | static uint8_t proto; | 80 | static uint8_t proto; |
@@ -149,9 +165,16 @@ auto_conf_iter (void *cls, | |||
149 | const char *option, | 165 | const char *option, |
150 | const char *value) | 166 | const char *value) |
151 | { | 167 | { |
168 | struct GNUNET_CONFIGURATION_Handle *new_cfg = cls; | ||
169 | |||
152 | PRINTF ("%s: %s\n", | 170 | PRINTF ("%s: %s\n", |
153 | option, | 171 | option, |
154 | value); | 172 | value); |
173 | if (NULL != new_cfg) | ||
174 | GNUNET_CONFIGURATION_set_value_string (new_cfg, | ||
175 | section, | ||
176 | option, | ||
177 | value); | ||
155 | } | 178 | } |
156 | 179 | ||
157 | 180 | ||
@@ -172,6 +195,7 @@ auto_config_cb (void *cls, | |||
172 | { | 195 | { |
173 | const char *nat_type; | 196 | const char *nat_type; |
174 | char unknown_type[64]; | 197 | char unknown_type[64]; |
198 | struct GNUNET_CONFIGURATION_Handle *new_cfg; | ||
175 | 199 | ||
176 | ah = NULL; | 200 | ah = NULL; |
177 | switch (type) | 201 | switch (type) |
@@ -196,19 +220,69 @@ auto_config_cb (void *cls, | |||
196 | break; | 220 | break; |
197 | } | 221 | } |
198 | 222 | ||
199 | PRINTF ("NAT status: %s/%s\n", | 223 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, |
200 | GNUNET_NAT_status2string (result), | 224 | "NAT status: %s/%s\n", |
201 | nat_type); | 225 | GNUNET_NAT_status2string (result), |
226 | nat_type); | ||
227 | |||
228 | /* Shortcut: if there are no changes suggested, bail out early. */ | ||
229 | if (GNUNET_NO == | ||
230 | GNUNET_CONFIGURATION_is_dirty (diff)) | ||
231 | { | ||
232 | test_finished (); | ||
233 | return; | ||
234 | } | ||
202 | 235 | ||
236 | /* Apply diff to original configuration and show changes | ||
237 | to the user */ | ||
238 | new_cfg = write_cfg ? GNUNET_CONFIGURATION_dup (cfg) : NULL; | ||
239 | |||
203 | if (NULL != diff) | 240 | if (NULL != diff) |
204 | { | 241 | { |
205 | PRINTF ("SUGGESTED CHANGES:\n"); | 242 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, |
243 | _("Suggested configuration changes:\n")); | ||
206 | GNUNET_CONFIGURATION_iterate_section_values (diff, | 244 | GNUNET_CONFIGURATION_iterate_section_values (diff, |
207 | "nat", | 245 | "nat", |
208 | &auto_conf_iter, | 246 | &auto_conf_iter, |
209 | NULL); | 247 | new_cfg); |
210 | } | 248 | } |
211 | // FIXME: have option to save config | 249 | |
250 | /* If desired, write configuration to file; we write only the | ||
251 | changes to the defaults to keep things compact. */ | ||
252 | if ( (write_cfg) && | ||
253 | (NULL != diff) ) | ||
254 | { | ||
255 | struct GNUNET_CONFIGURATION_Handle *def_cfg; | ||
256 | |||
257 | GNUNET_CONFIGURATION_set_value_string (new_cfg, | ||
258 | "ARM", | ||
259 | "CONFIG", | ||
260 | NULL); | ||
261 | def_cfg = GNUNET_CONFIGURATION_create (); | ||
262 | GNUNET_break (GNUNET_OK == | ||
263 | GNUNET_CONFIGURATION_load (def_cfg, | ||
264 | NULL)); | ||
265 | if (GNUNET_OK != | ||
266 | GNUNET_CONFIGURATION_write_diffs (def_cfg, | ||
267 | new_cfg, | ||
268 | cfg_file)) | ||
269 | { | ||
270 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
271 | _("Failed to write configuration to `%s'\n"), | ||
272 | cfg_file); | ||
273 | global_ret = 1; | ||
274 | } | ||
275 | else | ||
276 | { | ||
277 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
278 | _("Wrote updated configuration to `%s'\n"), | ||
279 | cfg_file); | ||
280 | } | ||
281 | GNUNET_CONFIGURATION_destroy (def_cfg); | ||
282 | } | ||
283 | |||
284 | if (NULL != new_cfg) | ||
285 | GNUNET_CONFIGURATION_destroy (new_cfg); | ||
212 | test_finished (); | 286 | test_finished (); |
213 | } | 287 | } |
214 | 288 | ||
@@ -385,8 +459,11 @@ run (void *cls, | |||
385 | struct sockaddr_in extern_sa; | 459 | struct sockaddr_in extern_sa; |
386 | struct sockaddr *local_sa; | 460 | struct sockaddr *local_sa; |
387 | struct sockaddr *remote_sa; | 461 | struct sockaddr *remote_sa; |
388 | size_t local_len; | 462 | socklen_t local_len; |
389 | size_t remote_len; | 463 | size_t remote_len; |
464 | |||
465 | cfg_file = cfgfile; | ||
466 | cfg = c; | ||
390 | 467 | ||
391 | if (use_tcp && use_udp) | 468 | if (use_tcp && use_udp) |
392 | { | 469 | { |
@@ -450,9 +527,9 @@ run (void *cls, | |||
450 | } | 527 | } |
451 | if (NULL != local_addr) | 528 | if (NULL != local_addr) |
452 | { | 529 | { |
453 | local_len = GNUNET_STRINGS_parse_socket_addr (local_addr, | 530 | local_len = (socklen_t) GNUNET_STRINGS_parse_socket_addr (local_addr, |
454 | &af, | 531 | &af, |
455 | &local_sa); | 532 | &local_sa); |
456 | if (0 == local_len) | 533 | if (0 == local_len) |
457 | { | 534 | { |
458 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | 535 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, |
@@ -611,14 +688,11 @@ main (int argc, | |||
611 | gettext_noop ("which external IP and port should be used to test"), | 688 | gettext_noop ("which external IP and port should be used to test"), |
612 | GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr }, | 689 | GNUNET_YES, &GNUNET_GETOPT_set_string, &extern_addr }, |
613 | {'i', "in", "ADDRESS", | 690 | {'i', "in", "ADDRESS", |
614 | gettext_noop ("which IP and port are we locally using to listen to for connection reversals"), | 691 | gettext_noop ("which IP and port are we locally using to bind/listen to"), |
615 | GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr }, | 692 | GNUNET_YES, &GNUNET_GETOPT_set_string, &local_addr }, |
616 | {'r', "remote", "ADDRESS", | 693 | {'r', "remote", "ADDRESS", |
617 | gettext_noop ("which remote IP and port should be asked for connection reversal"), | 694 | gettext_noop ("which remote IP and port should be asked for connection reversal"), |
618 | GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr }, | 695 | GNUNET_YES, &GNUNET_GETOPT_set_string, &remote_addr }, |
619 | {'L', "listen", NULL, | ||
620 | gettext_noop ("listen for connection reversal requests"), | ||
621 | GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal }, | ||
622 | {'p', "port", NULL, | 696 | {'p', "port", NULL, |
623 | gettext_noop ("port to use to advertise"), | 697 | gettext_noop ("port to use to advertise"), |
624 | GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port }, | 698 | GNUNET_YES, &GNUNET_GETOPT_set_uint, &adv_port }, |
@@ -631,6 +705,12 @@ main (int argc, | |||
631 | {'u', "udp", NULL, | 705 | {'u', "udp", NULL, |
632 | gettext_noop ("use UDP"), | 706 | gettext_noop ("use UDP"), |
633 | GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, | 707 | GNUNET_NO, &GNUNET_GETOPT_set_one, &use_udp }, |
708 | {'w', "write", NULL, | ||
709 | gettext_noop ("write configuration file (for autoconfiguration)"), | ||
710 | GNUNET_NO, &GNUNET_GETOPT_set_one, &write_cfg }, | ||
711 | {'W', "watch", NULL, | ||
712 | gettext_noop ("watch for connection reversal requests"), | ||
713 | GNUNET_NO, &GNUNET_GETOPT_set_one, &listen_reversal }, | ||
634 | GNUNET_GETOPT_OPTION_END | 714 | GNUNET_GETOPT_OPTION_END |
635 | }; | 715 | }; |
636 | 716 | ||
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c index 4ad6c8d2c..762175437 100644 --- a/src/nat/gnunet-service-nat.c +++ b/src/nat/gnunet-service-nat.c | |||
@@ -28,8 +28,11 @@ | |||
28 | * knowledge about the local network topology. | 28 | * knowledge about the local network topology. |
29 | * | 29 | * |
30 | * TODO: | 30 | * TODO: |
31 | * - implement UPnPC/PMP-based NAT traversal | 31 | * - test ICMP based NAT traversal |
32 | * - implement autoconfig | 32 | * - implement "more" autoconfig: |
33 | * re-work gnunet-nat-server & integrate! | ||
34 | * - implement & test STUN processing to classify NAT; | ||
35 | * basically, open port & try different methods. | ||
33 | * - implement NEW logic for external IP detection | 36 | * - implement NEW logic for external IP detection |
34 | */ | 37 | */ |
35 | #include "platform.h" | 38 | #include "platform.h" |
@@ -40,6 +43,7 @@ | |||
40 | #include "gnunet_statistics_service.h" | 43 | #include "gnunet_statistics_service.h" |
41 | #include "gnunet_nat_service.h" | 44 | #include "gnunet_nat_service.h" |
42 | #include "gnunet-service-nat_stun.h" | 45 | #include "gnunet-service-nat_stun.h" |
46 | #include "gnunet-service-nat_mini.h" | ||
43 | #include "gnunet-service-nat_helper.h" | 47 | #include "gnunet-service-nat_helper.h" |
44 | #include "nat.h" | 48 | #include "nat.h" |
45 | #include <gcrypt.h> | 49 | #include <gcrypt.h> |
@@ -51,6 +55,49 @@ | |||
51 | */ | 55 | */ |
52 | #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | 56 | #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) |
53 | 57 | ||
58 | /** | ||
59 | * How long do we wait until we forcefully terminate autoconfiguration? | ||
60 | */ | ||
61 | #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
62 | |||
63 | /** | ||
64 | * How long do we wait until we re-try running `external-ip` if the | ||
65 | * command failed to terminate nicely? | ||
66 | */ | ||
67 | #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
68 | |||
69 | /** | ||
70 | * How long do we wait until we re-try running `external-ip` if the | ||
71 | * command failed (but terminated)? | ||
72 | */ | ||
73 | #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30) | ||
74 | |||
75 | /** | ||
76 | * How long do we wait until we re-try running `external-ip` if the | ||
77 | * command succeeded? | ||
78 | */ | ||
79 | #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Information we track per client address. | ||
84 | */ | ||
85 | struct ClientAddress | ||
86 | { | ||
87 | /** | ||
88 | * Network address used by the client. | ||
89 | */ | ||
90 | struct sockaddr_storage ss; | ||
91 | |||
92 | /** | ||
93 | * Handle to active UPnP request where we asked upnpc to open | ||
94 | * a port at the NAT. NULL if we do not have such a request | ||
95 | * pending. | ||
96 | */ | ||
97 | struct GNUNET_NAT_MiniHandle *mh; | ||
98 | |||
99 | }; | ||
100 | |||
54 | 101 | ||
55 | /** | 102 | /** |
56 | * Internal data structure we track for each of our clients. | 103 | * Internal data structure we track for each of our clients. |
@@ -81,7 +128,7 @@ struct ClientHandle | |||
81 | /** | 128 | /** |
82 | * Array of addresses used by the service. | 129 | * Array of addresses used by the service. |
83 | */ | 130 | */ |
84 | struct sockaddr **addrs; | 131 | struct ClientAddress *caddrs; |
85 | 132 | ||
86 | /** | 133 | /** |
87 | * What does this client care about? | 134 | * What does this client care about? |
@@ -89,7 +136,7 @@ struct ClientHandle | |||
89 | enum GNUNET_NAT_RegisterFlags flags; | 136 | enum GNUNET_NAT_RegisterFlags flags; |
90 | 137 | ||
91 | /** | 138 | /** |
92 | * Is any of the @e addrs in a reserved subnet for NAT? | 139 | * Is any of the @e caddrs in a reserved subnet for NAT? |
93 | */ | 140 | */ |
94 | int natted_address; | 141 | int natted_address; |
95 | 142 | ||
@@ -101,8 +148,9 @@ struct ClientHandle | |||
101 | 148 | ||
102 | /** | 149 | /** |
103 | * Number of addresses that this service is bound to. | 150 | * Number of addresses that this service is bound to. |
151 | * Length of the @e caddrs array. | ||
104 | */ | 152 | */ |
105 | uint16_t num_addrs; | 153 | uint16_t num_caddrs; |
106 | 154 | ||
107 | /** | 155 | /** |
108 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. | 156 | * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP. |
@@ -187,6 +235,80 @@ struct StunExternalIP | |||
187 | 235 | ||
188 | 236 | ||
189 | /** | 237 | /** |
238 | * Context for autoconfiguration operations. | ||
239 | */ | ||
240 | struct AutoconfigContext | ||
241 | { | ||
242 | /** | ||
243 | * Kept in a DLL. | ||
244 | */ | ||
245 | struct AutoconfigContext *prev; | ||
246 | |||
247 | /** | ||
248 | * Kept in a DLL. | ||
249 | */ | ||
250 | struct AutoconfigContext *next; | ||
251 | |||
252 | /** | ||
253 | * Which client asked the question. | ||
254 | */ | ||
255 | struct ClientHandle *ch; | ||
256 | |||
257 | /** | ||
258 | * Configuration we are creating. | ||
259 | */ | ||
260 | struct GNUNET_CONFIGURATION_Handle *c; | ||
261 | |||
262 | /** | ||
263 | * Original configuration (for diffing). | ||
264 | */ | ||
265 | struct GNUNET_CONFIGURATION_Handle *orig; | ||
266 | |||
267 | /** | ||
268 | * Timeout task to force termination. | ||
269 | */ | ||
270 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
271 | |||
272 | /** | ||
273 | * What type of system are we on? | ||
274 | */ | ||
275 | char *system_type; | ||
276 | |||
277 | /** | ||
278 | * Handle to activity to probe for our external IP. | ||
279 | */ | ||
280 | struct GNUNET_NAT_ExternalHandle *probe_external; | ||
281 | |||
282 | /** | ||
283 | * #GNUNET_YES if upnpc should be used, | ||
284 | * #GNUNET_NO if upnpc should not be used, | ||
285 | * #GNUNET_SYSERR if we should simply not change the option. | ||
286 | */ | ||
287 | int enable_upnpc; | ||
288 | |||
289 | /** | ||
290 | * Status code to return to the client. | ||
291 | */ | ||
292 | enum GNUNET_NAT_StatusCode status_code; | ||
293 | |||
294 | /** | ||
295 | * NAT type to return to the client. | ||
296 | */ | ||
297 | enum GNUNET_NAT_Type type; | ||
298 | }; | ||
299 | |||
300 | |||
301 | /** | ||
302 | * DLL of our autoconfiguration operations. | ||
303 | */ | ||
304 | static struct AutoconfigContext *ac_head; | ||
305 | |||
306 | /** | ||
307 | * DLL of our autoconfiguration operations. | ||
308 | */ | ||
309 | static struct AutoconfigContext *ac_tail; | ||
310 | |||
311 | /** | ||
190 | * Timeout to use when STUN data is considered stale. | 312 | * Timeout to use when STUN data is considered stale. |
191 | */ | 313 | */ |
192 | static struct GNUNET_TIME_Relative stun_stale_timeout; | 314 | static struct GNUNET_TIME_Relative stun_stale_timeout; |
@@ -236,6 +358,29 @@ static struct StunExternalIP *se_head; | |||
236 | */ | 358 | */ |
237 | static struct StunExternalIP *se_tail; | 359 | static struct StunExternalIP *se_tail; |
238 | 360 | ||
361 | /** | ||
362 | * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled, | ||
363 | * #GNUNET_SYSERR if configuration enabled but binary is unavailable. | ||
364 | */ | ||
365 | static int enable_upnp; | ||
366 | |||
367 | /** | ||
368 | * Task run to obtain our external IP (if #enable_upnp is set | ||
369 | * and if we find we have a NATed IP address). | ||
370 | */ | ||
371 | static struct GNUNET_SCHEDULER_Task *probe_external_ip_task; | ||
372 | |||
373 | /** | ||
374 | * Handle to our operation to run `external-ip`. | ||
375 | */ | ||
376 | static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op; | ||
377 | |||
378 | /** | ||
379 | * What is our external IP address as claimed by `external-ip`? | ||
380 | * 0 for unknown. | ||
381 | */ | ||
382 | static struct in_addr mini_external_ipv4; | ||
383 | |||
239 | 384 | ||
240 | /** | 385 | /** |
241 | * Free the DLL starting at #lal_head. | 386 | * Free the DLL starting at #lal_head. |
@@ -322,7 +467,9 @@ match_ipv4 (const char *network, | |||
322 | uint8_t bits) | 467 | uint8_t bits) |
323 | { | 468 | { |
324 | struct in_addr net; | 469 | struct in_addr net; |
325 | 470 | ||
471 | if (0 == ip->s_addr) | ||
472 | return GNUNET_YES; | ||
326 | if (0 == bits) | 473 | if (0 == bits) |
327 | return GNUNET_YES; | 474 | return GNUNET_YES; |
328 | GNUNET_assert (1 == inet_pton (AF_INET, | 475 | GNUNET_assert (1 == inet_pton (AF_INET, |
@@ -355,6 +502,10 @@ match_ipv6 (const char *network, | |||
355 | network, | 502 | network, |
356 | &net)); | 503 | &net)); |
357 | memset (&mask, 0, sizeof (mask)); | 504 | memset (&mask, 0, sizeof (mask)); |
505 | if (0 == memcmp (&mask, | ||
506 | ip, | ||
507 | sizeof (mask))) | ||
508 | return GNUNET_YES; | ||
358 | off = 0; | 509 | off = 0; |
359 | while (bits > 8) | 510 | while (bits > 8) |
360 | { | 511 | { |
@@ -411,6 +562,634 @@ is_nat_v6 (const struct in6_addr *ip) | |||
411 | 562 | ||
412 | 563 | ||
413 | /** | 564 | /** |
565 | * Closure for #ifc_proc. | ||
566 | */ | ||
567 | struct IfcProcContext | ||
568 | { | ||
569 | |||
570 | /** | ||
571 | * Head of DLL of local addresses. | ||
572 | */ | ||
573 | struct LocalAddressList *lal_head; | ||
574 | |||
575 | /** | ||
576 | * Tail of DLL of local addresses. | ||
577 | */ | ||
578 | struct LocalAddressList *lal_tail; | ||
579 | |||
580 | }; | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Callback function invoked for each interface found. Adds them | ||
585 | * to our new address list. | ||
586 | * | ||
587 | * @param cls a `struct IfcProcContext *` | ||
588 | * @param name name of the interface (can be NULL for unknown) | ||
589 | * @param isDefault is this presumably the default interface | ||
590 | * @param addr address of this interface (can be NULL for unknown or unassigned) | ||
591 | * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) | ||
592 | * @param netmask the network mask (can be NULL for unknown or unassigned) | ||
593 | * @param addrlen length of the address | ||
594 | * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort | ||
595 | */ | ||
596 | static int | ||
597 | ifc_proc (void *cls, | ||
598 | const char *name, | ||
599 | int isDefault, | ||
600 | const struct sockaddr *addr, | ||
601 | const struct sockaddr *broadcast_addr, | ||
602 | const struct sockaddr *netmask, | ||
603 | socklen_t addrlen) | ||
604 | { | ||
605 | struct IfcProcContext *ifc_ctx = cls; | ||
606 | struct LocalAddressList *lal; | ||
607 | size_t alen; | ||
608 | const struct in_addr *ip4; | ||
609 | const struct in6_addr *ip6; | ||
610 | enum GNUNET_NAT_AddressClass ac; | ||
611 | |||
612 | switch (addr->sa_family) | ||
613 | { | ||
614 | case AF_INET: | ||
615 | alen = sizeof (struct sockaddr_in); | ||
616 | ip4 = &((const struct sockaddr_in *) addr)->sin_addr; | ||
617 | if (match_ipv4 ("127.0.0.0", ip4, 8)) | ||
618 | ac = GNUNET_NAT_AC_LOOPBACK; | ||
619 | else if (is_nat_v4 (ip4)) | ||
620 | ac = GNUNET_NAT_AC_LAN; | ||
621 | else | ||
622 | ac = GNUNET_NAT_AC_GLOBAL; | ||
623 | break; | ||
624 | case AF_INET6: | ||
625 | alen = sizeof (struct sockaddr_in6); | ||
626 | ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr; | ||
627 | if (match_ipv6 ("::1", ip6, 128)) | ||
628 | ac = GNUNET_NAT_AC_LOOPBACK; | ||
629 | else if (is_nat_v6 (ip6)) | ||
630 | ac = GNUNET_NAT_AC_LAN; | ||
631 | else | ||
632 | ac = GNUNET_NAT_AC_GLOBAL; | ||
633 | if ( (ip6->s6_addr[11] == 0xFF) && | ||
634 | (ip6->s6_addr[12] == 0xFE) ) | ||
635 | { | ||
636 | /* contains a MAC, be extra careful! */ | ||
637 | ac |= GNUNET_NAT_AC_PRIVATE; | ||
638 | } | ||
639 | break; | ||
640 | #if AF_UNIX | ||
641 | case AF_UNIX: | ||
642 | GNUNET_break (0); | ||
643 | return GNUNET_OK; | ||
644 | #endif | ||
645 | default: | ||
646 | GNUNET_break (0); | ||
647 | return GNUNET_OK; | ||
648 | } | ||
649 | lal = GNUNET_malloc (sizeof (*lal)); | ||
650 | lal->af = addr->sa_family; | ||
651 | lal->ac = ac; | ||
652 | GNUNET_memcpy (&lal->addr, | ||
653 | addr, | ||
654 | alen); | ||
655 | GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head, | ||
656 | ifc_ctx->lal_tail, | ||
657 | lal); | ||
658 | return GNUNET_OK; | ||
659 | } | ||
660 | |||
661 | |||
662 | /** | ||
663 | * Notify client about a change in the list of addresses this peer | ||
664 | * has. | ||
665 | * | ||
666 | * @param ac address class of the entry in the list that changed | ||
667 | * @param ch client to contact | ||
668 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
669 | * @param addr the address that changed | ||
670 | * @param addr_len number of bytes in @a addr | ||
671 | */ | ||
672 | static void | ||
673 | notify_client (enum GNUNET_NAT_AddressClass ac, | ||
674 | struct ClientHandle *ch, | ||
675 | int add, | ||
676 | const void *addr, | ||
677 | size_t addr_len) | ||
678 | { | ||
679 | struct GNUNET_MQ_Envelope *env; | ||
680 | struct GNUNET_NAT_AddressChangeNotificationMessage *msg; | ||
681 | |||
682 | env = GNUNET_MQ_msg_extra (msg, | ||
683 | addr_len, | ||
684 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | ||
685 | msg->add_remove = htonl (add); | ||
686 | msg->addr_class = htonl (ac); | ||
687 | GNUNET_memcpy (&msg[1], | ||
688 | addr, | ||
689 | addr_len); | ||
690 | GNUNET_MQ_send (ch->mq, | ||
691 | env); | ||
692 | } | ||
693 | |||
694 | |||
695 | /** | ||
696 | * Check if we should bother to notify this client about this | ||
697 | * address change, and if so, do it. | ||
698 | * | ||
699 | * @param delta the entry in the list that changed | ||
700 | * @param ch client to check | ||
701 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
702 | */ | ||
703 | static void | ||
704 | check_notify_client (struct LocalAddressList *delta, | ||
705 | struct ClientHandle *ch, | ||
706 | int add) | ||
707 | { | ||
708 | size_t alen; | ||
709 | struct sockaddr_in v4; | ||
710 | struct sockaddr_in6 v6; | ||
711 | |||
712 | if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) | ||
713 | return; | ||
714 | switch (delta->af) | ||
715 | { | ||
716 | case AF_INET: | ||
717 | alen = sizeof (struct sockaddr_in); | ||
718 | GNUNET_memcpy (&v4, | ||
719 | &delta->addr, | ||
720 | alen); | ||
721 | for (unsigned int i=0;i<ch->num_caddrs;i++) | ||
722 | { | ||
723 | const struct sockaddr_in *c4; | ||
724 | |||
725 | if (AF_INET != ch->caddrs[i].ss.ss_family) | ||
726 | return; /* IPv4 not relevant */ | ||
727 | c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss; | ||
728 | if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) && | ||
729 | (0 != c4->sin_addr.s_addr) && | ||
730 | (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) ) | ||
731 | continue; /* bound to loopback, but this is not loopback */ | ||
732 | if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) && | ||
733 | (0 != c4->sin_addr.s_addr) && | ||
734 | match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) ) | ||
735 | continue; /* bound to non-loopback, but this is loopback */ | ||
736 | if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) && | ||
737 | (0 != c4->sin_addr.s_addr) && | ||
738 | (! is_nat_v4 (&v4.sin_addr)) ) | ||
739 | continue; /* based on external-IP, but this IP is not | ||
740 | from private address range. */ | ||
741 | if ( (0 != memcmp (&v4.sin_addr, | ||
742 | &c4->sin_addr, | ||
743 | sizeof (struct in_addr))) && | ||
744 | (0 != c4->sin_addr.s_addr) && | ||
745 | ( (! is_nat_v4 (&c4->sin_addr)) || | ||
746 | (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) ) | ||
747 | continue; /* this IP is not from private address range, | ||
748 | and IP does not match. */ | ||
749 | |||
750 | /* OK, IP seems relevant, notify client */ | ||
751 | v4.sin_port = c4->sin_port; | ||
752 | notify_client (delta->ac, | ||
753 | ch, | ||
754 | add, | ||
755 | &v4, | ||
756 | alen); | ||
757 | } | ||
758 | break; | ||
759 | case AF_INET6: | ||
760 | alen = sizeof (struct sockaddr_in6); | ||
761 | GNUNET_memcpy (&v6, | ||
762 | &delta->addr, | ||
763 | alen); | ||
764 | for (unsigned int i=0;i<ch->num_caddrs;i++) | ||
765 | { | ||
766 | const struct sockaddr_in6 *c6; | ||
767 | |||
768 | if (AF_INET6 != ch->caddrs[i].ss.ss_family) | ||
769 | return; /* IPv4 not relevant */ | ||
770 | c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss; | ||
771 | if ( match_ipv6 ("::1", &c6->sin6_addr, 128) && | ||
772 | (0 != memcmp (&c6->sin6_addr, | ||
773 | &in6addr_any, | ||
774 | sizeof (struct in6_addr))) && | ||
775 | (! match_ipv6 ("::1", &v6.sin6_addr, 128)) ) | ||
776 | continue; /* bound to loopback, but this is not loopback */ | ||
777 | if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) && | ||
778 | (0 != memcmp (&c6->sin6_addr, | ||
779 | &in6addr_any, | ||
780 | sizeof (struct in6_addr))) && | ||
781 | match_ipv6 ("::1", &v6.sin6_addr, 128) ) | ||
782 | continue; /* bound to non-loopback, but this is loopback */ | ||
783 | if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) && | ||
784 | (0 != memcmp (&c6->sin6_addr, | ||
785 | &in6addr_any, | ||
786 | sizeof (struct in6_addr))) && | ||
787 | (! is_nat_v6 (&v6.sin6_addr)) ) | ||
788 | continue; /* based on external-IP, but this IP is not | ||
789 | from private address range. */ | ||
790 | if ( (0 != memcmp (&v6.sin6_addr, | ||
791 | &c6->sin6_addr, | ||
792 | sizeof (struct in6_addr))) && | ||
793 | (0 != memcmp (&c6->sin6_addr, | ||
794 | &in6addr_any, | ||
795 | sizeof (struct in6_addr))) && | ||
796 | (! is_nat_v6 (&c6->sin6_addr)) ) | ||
797 | continue; /* this IP is not from private address range, | ||
798 | and IP does not match. */ | ||
799 | if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) && | ||
800 | (0 != memcmp (&c6->sin6_addr, | ||
801 | &in6addr_any, | ||
802 | sizeof (struct in6_addr))) && | ||
803 | (0 != memcmp (&v6.sin6_addr, | ||
804 | &c6->sin6_addr, | ||
805 | sizeof (struct in6_addr))) && | ||
806 | (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) ) | ||
807 | continue; /* client bound to link-local, and the other address | ||
808 | does not match and is not an external IP */ | ||
809 | |||
810 | /* OK, IP seems relevant, notify client */ | ||
811 | v6.sin6_port = c6->sin6_port; | ||
812 | notify_client (delta->ac, | ||
813 | ch, | ||
814 | add, | ||
815 | &v6, | ||
816 | alen); | ||
817 | } | ||
818 | break; | ||
819 | default: | ||
820 | GNUNET_break (0); | ||
821 | return; | ||
822 | } | ||
823 | } | ||
824 | |||
825 | |||
826 | /** | ||
827 | * Notify all clients about a change in the list | ||
828 | * of addresses this peer has. | ||
829 | * | ||
830 | * @param delta the entry in the list that changed | ||
831 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
832 | */ | ||
833 | static void | ||
834 | notify_clients (struct LocalAddressList *delta, | ||
835 | int add) | ||
836 | { | ||
837 | for (struct ClientHandle *ch = ch_head; | ||
838 | NULL != ch; | ||
839 | ch = ch->next) | ||
840 | check_notify_client (delta, | ||
841 | ch, | ||
842 | add); | ||
843 | } | ||
844 | |||
845 | |||
846 | /** | ||
847 | * Tell relevant client about a change in our external | ||
848 | * IPv4 address. | ||
849 | * | ||
850 | * @param v4 the external address that changed | ||
851 | * @param ch client to check if it cares and possibly notify | ||
852 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
853 | */ | ||
854 | static void | ||
855 | check_notify_client_external_ipv4_change (const struct in_addr *v4, | ||
856 | struct ClientHandle *ch, | ||
857 | int add) | ||
858 | { | ||
859 | struct sockaddr_in sa; | ||
860 | uint16_t port; | ||
861 | uint16_t bport; | ||
862 | |||
863 | /* (1) check if client cares. */ | ||
864 | if (! ch->natted_address) | ||
865 | return; | ||
866 | if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags)) | ||
867 | return; | ||
868 | bport = 0; | ||
869 | for (unsigned int i=0;i<ch->num_caddrs;i++) | ||
870 | { | ||
871 | const struct sockaddr_storage *ss = &ch->caddrs[i].ss; | ||
872 | |||
873 | if (AF_INET != ss->ss_family) | ||
874 | continue; | ||
875 | bport = ntohs (((const struct sockaddr_in *) ss)->sin_port); | ||
876 | } | ||
877 | if (0 == bport) | ||
878 | return; /* IPv6-only */ | ||
879 | |||
880 | /* (2) figure out external port, build sockaddr */ | ||
881 | port = ch->adv_port; | ||
882 | if (0 == port) | ||
883 | port = bport; | ||
884 | memset (&sa, | ||
885 | 0, | ||
886 | sizeof (sa)); | ||
887 | sa.sin_family = AF_INET; | ||
888 | sa.sin_addr = *v4; | ||
889 | sa.sin_port = htons (port); | ||
890 | |||
891 | /* (3) notify client of change */ | ||
892 | notify_client (is_nat_v4 (v4) | ||
893 | ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN_PRIVATE | ||
894 | : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL, | ||
895 | ch, | ||
896 | add, | ||
897 | &sa, | ||
898 | sizeof (sa)); | ||
899 | } | ||
900 | |||
901 | |||
902 | /** | ||
903 | * Tell relevant clients about a change in our external | ||
904 | * IPv4 address. | ||
905 | * | ||
906 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | ||
907 | * @param v4 the external address that changed | ||
908 | */ | ||
909 | static void | ||
910 | notify_clients_external_ipv4_change (int add, | ||
911 | const struct in_addr *v4) | ||
912 | { | ||
913 | for (struct ClientHandle *ch = ch_head; | ||
914 | NULL != ch; | ||
915 | ch = ch->next) | ||
916 | check_notify_client_external_ipv4_change (v4, | ||
917 | ch, | ||
918 | add); | ||
919 | } | ||
920 | |||
921 | |||
922 | /** | ||
923 | * Task used to run `external-ip` to get our external IPv4 | ||
924 | * address and pass it to NATed clients if possible. | ||
925 | * | ||
926 | * @param cls NULL | ||
927 | */ | ||
928 | static void | ||
929 | run_external_ip (void *cls); | ||
930 | |||
931 | |||
932 | /** | ||
933 | * We learn our current external IP address. If it changed, | ||
934 | * notify all of our applicable clients. Also re-schedule | ||
935 | * #run_external_ip with an appropriate timeout. | ||
936 | * | ||
937 | * @param cls NULL | ||
938 | * @param addr the address, NULL on errors | ||
939 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
940 | */ | ||
941 | static void | ||
942 | handle_external_ip (void *cls, | ||
943 | const struct in_addr *addr, | ||
944 | enum GNUNET_NAT_StatusCode result) | ||
945 | { | ||
946 | char buf[INET_ADDRSTRLEN]; | ||
947 | |||
948 | probe_external_ip_op = NULL; | ||
949 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
950 | probe_external_ip_task | ||
951 | = GNUNET_SCHEDULER_add_delayed ((NULL == addr) | ||
952 | ? EXTERN_IP_RETRY_FAILURE | ||
953 | : EXTERN_IP_RETRY_SUCCESS, | ||
954 | &run_external_ip, | ||
955 | NULL); | ||
956 | switch (result) | ||
957 | { | ||
958 | case GNUNET_NAT_ERROR_SUCCESS: | ||
959 | if (addr->s_addr == mini_external_ipv4.s_addr) | ||
960 | return; /* not change */ | ||
961 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
962 | "Our external IP is now %s\n", | ||
963 | inet_ntop (AF_INET, | ||
964 | addr, | ||
965 | buf, | ||
966 | sizeof (buf))); | ||
967 | if (0 != mini_external_ipv4.s_addr) | ||
968 | notify_clients_external_ipv4_change (GNUNET_NO, | ||
969 | &mini_external_ipv4); | ||
970 | mini_external_ipv4 = *addr; | ||
971 | notify_clients_external_ipv4_change (GNUNET_YES, | ||
972 | &mini_external_ipv4); | ||
973 | break; | ||
974 | default: | ||
975 | if (0 != mini_external_ipv4.s_addr) | ||
976 | notify_clients_external_ipv4_change (GNUNET_NO, | ||
977 | &mini_external_ipv4); | ||
978 | mini_external_ipv4.s_addr = 0; | ||
979 | break; | ||
980 | } | ||
981 | } | ||
982 | |||
983 | |||
984 | /** | ||
985 | * Task used to run `external-ip` to get our external IPv4 | ||
986 | * address and pass it to NATed clients if possible. | ||
987 | * | ||
988 | * @param cls NULL | ||
989 | */ | ||
990 | static void | ||
991 | run_external_ip (void *cls) | ||
992 | { | ||
993 | probe_external_ip_task | ||
994 | = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT, | ||
995 | &run_external_ip, | ||
996 | NULL); | ||
997 | if (NULL != probe_external_ip_op) | ||
998 | { | ||
999 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
1000 | probe_external_ip_op = NULL; | ||
1001 | } | ||
1002 | probe_external_ip_op | ||
1003 | = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip, | ||
1004 | NULL); | ||
1005 | } | ||
1006 | |||
1007 | |||
1008 | /** | ||
1009 | * Task we run periodically to scan for network interfaces. | ||
1010 | * | ||
1011 | * @param cls NULL | ||
1012 | */ | ||
1013 | static void | ||
1014 | run_scan (void *cls) | ||
1015 | { | ||
1016 | struct IfcProcContext ifc_ctx; | ||
1017 | int found; | ||
1018 | int have_nat; | ||
1019 | |||
1020 | scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, | ||
1021 | &run_scan, | ||
1022 | NULL); | ||
1023 | memset (&ifc_ctx, | ||
1024 | 0, | ||
1025 | sizeof (ifc_ctx)); | ||
1026 | GNUNET_OS_network_interfaces_list (&ifc_proc, | ||
1027 | &ifc_ctx); | ||
1028 | /* remove addresses that disappeared */ | ||
1029 | for (struct LocalAddressList *lal = lal_head; | ||
1030 | NULL != lal; | ||
1031 | lal = lal->next) | ||
1032 | { | ||
1033 | found = GNUNET_NO; | ||
1034 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | ||
1035 | NULL != pos; | ||
1036 | pos = pos->next) | ||
1037 | { | ||
1038 | if ( (pos->af == lal->af) && | ||
1039 | (0 == memcmp (&lal->addr, | ||
1040 | &pos->addr, | ||
1041 | (AF_INET == lal->af) | ||
1042 | ? sizeof (struct sockaddr_in) | ||
1043 | : sizeof (struct sockaddr_in6))) ) | ||
1044 | found = GNUNET_YES; | ||
1045 | } | ||
1046 | if (GNUNET_NO == found) | ||
1047 | notify_clients (lal, | ||
1048 | GNUNET_NO); | ||
1049 | } | ||
1050 | |||
1051 | /* add addresses that appeared */ | ||
1052 | have_nat = GNUNET_NO; | ||
1053 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | ||
1054 | NULL != pos; | ||
1055 | pos = pos->next) | ||
1056 | { | ||
1057 | found = GNUNET_NO; | ||
1058 | if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac)) | ||
1059 | have_nat = GNUNET_YES; | ||
1060 | for (struct LocalAddressList *lal = lal_head; | ||
1061 | NULL != lal; | ||
1062 | lal = lal->next) | ||
1063 | { | ||
1064 | if ( (pos->af == lal->af) && | ||
1065 | (0 == memcmp (&lal->addr, | ||
1066 | &pos->addr, | ||
1067 | (AF_INET == lal->af) | ||
1068 | ? sizeof (struct sockaddr_in) | ||
1069 | : sizeof (struct sockaddr_in6))) ) | ||
1070 | found = GNUNET_YES; | ||
1071 | } | ||
1072 | if (GNUNET_NO == found) | ||
1073 | notify_clients (pos, | ||
1074 | GNUNET_YES); | ||
1075 | } | ||
1076 | if ( (GNUNET_YES == have_nat) && | ||
1077 | (GNUNET_YES == enable_upnp) && | ||
1078 | (NULL == probe_external_ip_task) && | ||
1079 | (NULL == probe_external_ip_op) ) | ||
1080 | { | ||
1081 | probe_external_ip_task | ||
1082 | = GNUNET_SCHEDULER_add_now (&run_external_ip, | ||
1083 | NULL); | ||
1084 | } | ||
1085 | if ( (GNUNET_NO == have_nat) && | ||
1086 | (GNUNET_YES == enable_upnp) ) | ||
1087 | { | ||
1088 | if (NULL != probe_external_ip_task) | ||
1089 | { | ||
1090 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); | ||
1091 | probe_external_ip_task = NULL; | ||
1092 | } | ||
1093 | if (NULL != probe_external_ip_op) | ||
1094 | { | ||
1095 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); | ||
1096 | probe_external_ip_op = NULL; | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | destroy_lal (); | ||
1101 | lal_head = ifc_ctx.lal_head; | ||
1102 | lal_tail = ifc_ctx.lal_tail; | ||
1103 | } | ||
1104 | |||
1105 | |||
1106 | /** | ||
1107 | * Function called whenever our set of external addresses | ||
1108 | * as created by `upnpc` changes. | ||
1109 | * | ||
1110 | * @param cls closure with our `struct ClientHandle *` | ||
1111 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
1112 | * the previous (now invalid) one, #GNUNET_SYSERR indicates an error | ||
1113 | * @param addr either the previous or the new public IP address | ||
1114 | * @param addrlen actual length of the @a addr | ||
1115 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
1116 | */ | ||
1117 | static void | ||
1118 | upnp_addr_change_cb (void *cls, | ||
1119 | int add_remove, | ||
1120 | const struct sockaddr *addr, | ||
1121 | socklen_t addrlen, | ||
1122 | enum GNUNET_NAT_StatusCode result) | ||
1123 | { | ||
1124 | struct ClientHandle *ch = cls; | ||
1125 | enum GNUNET_NAT_AddressClass ac; | ||
1126 | |||
1127 | switch (result) | ||
1128 | { | ||
1129 | case GNUNET_NAT_ERROR_SUCCESS: | ||
1130 | GNUNET_assert (NULL != addr); | ||
1131 | break; | ||
1132 | case GNUNET_NAT_ERROR_UPNPC_FAILED: | ||
1133 | case GNUNET_NAT_ERROR_UPNPC_TIMEOUT: | ||
1134 | case GNUNET_NAT_ERROR_IPC_FAILURE: | ||
1135 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1136 | "Running upnpc failed: %d\n", | ||
1137 | result); | ||
1138 | return; | ||
1139 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND: | ||
1140 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1141 | "external-ip binary not found\n"); | ||
1142 | return; | ||
1143 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED: | ||
1144 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1145 | "external-ip binary could not be run\n"); | ||
1146 | return; | ||
1147 | case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED: | ||
1148 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1149 | "upnpc failed to create port mapping\n"); | ||
1150 | return; | ||
1151 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: | ||
1152 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1153 | "Invalid output from upnpc\n"); | ||
1154 | return; | ||
1155 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: | ||
1156 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1157 | "Invalid address returned by upnpc\n"); | ||
1158 | return; | ||
1159 | default: | ||
1160 | GNUNET_break (0); /* should not be possible */ | ||
1161 | return; | ||
1162 | } | ||
1163 | switch (addr->sa_family) | ||
1164 | { | ||
1165 | case AF_INET: | ||
1166 | ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr) | ||
1167 | ? GNUNET_NAT_AC_LAN_PRIVATE | ||
1168 | : GNUNET_NAT_AC_EXTERN; | ||
1169 | break; | ||
1170 | case AF_INET6: | ||
1171 | ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr) | ||
1172 | ? GNUNET_NAT_AC_LAN_PRIVATE | ||
1173 | : GNUNET_NAT_AC_EXTERN; | ||
1174 | break; | ||
1175 | default: | ||
1176 | GNUNET_break (0); | ||
1177 | return; | ||
1178 | } | ||
1179 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1180 | "upnp external address %s: %s\n", | ||
1181 | add_remove ? "added" : "removed", | ||
1182 | GNUNET_a2s (addr, | ||
1183 | addrlen)); | ||
1184 | notify_client (ac, | ||
1185 | ch, | ||
1186 | add_remove, | ||
1187 | addr, | ||
1188 | addrlen); | ||
1189 | } | ||
1190 | |||
1191 | |||
1192 | /** | ||
414 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. | 1193 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client. |
415 | * We remember the client for updates upon future NAT events. | 1194 | * We remember the client for updates upon future NAT events. |
416 | * | 1195 | * |
@@ -426,7 +1205,7 @@ handle_register (void *cls, | |||
426 | size_t left; | 1205 | size_t left; |
427 | 1206 | ||
428 | if ( (0 != ch->proto) || | 1207 | if ( (0 != ch->proto) || |
429 | (NULL != ch->addrs) ) | 1208 | (NULL != ch->caddrs) ) |
430 | { | 1209 | { |
431 | /* double registration not allowed */ | 1210 | /* double registration not allowed */ |
432 | GNUNET_break (0); | 1211 | GNUNET_break (0); |
@@ -438,15 +1217,17 @@ handle_register (void *cls, | |||
438 | ch->flags = message->flags; | 1217 | ch->flags = message->flags; |
439 | ch->proto = message->proto; | 1218 | ch->proto = message->proto; |
440 | ch->adv_port = ntohs (message->adv_port); | 1219 | ch->adv_port = ntohs (message->adv_port); |
441 | ch->num_addrs = ntohs (message->adv_port); | 1220 | ch->num_caddrs = ntohs (message->num_addrs); |
442 | ch->addrs = GNUNET_new_array (ch->num_addrs, | 1221 | ch->caddrs = GNUNET_new_array (ch->num_caddrs, |
443 | struct sockaddr *); | 1222 | struct ClientAddress); |
444 | left = ntohs (message->header.size) - sizeof (*message); | 1223 | left = ntohs (message->header.size) - sizeof (*message); |
445 | off = (const char *) &message[1]; | 1224 | off = (const char *) &message[1]; |
446 | for (unsigned int i=0;i<ch->num_addrs;i++) | 1225 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
447 | { | 1226 | { |
448 | size_t alen; | 1227 | size_t alen; |
449 | const struct sockaddr *sa = (const struct sockaddr *) off; | 1228 | const struct sockaddr *sa = (const struct sockaddr *) off; |
1229 | uint16_t port; | ||
1230 | int is_nat; | ||
450 | 1231 | ||
451 | if (sizeof (sa_family_t) > left) | 1232 | if (sizeof (sa_family_t) > left) |
452 | { | 1233 | { |
@@ -454,6 +1235,7 @@ handle_register (void *cls, | |||
454 | GNUNET_SERVICE_client_drop (ch->client); | 1235 | GNUNET_SERVICE_client_drop (ch->client); |
455 | return; | 1236 | return; |
456 | } | 1237 | } |
1238 | is_nat = GNUNET_NO; | ||
457 | switch (sa->sa_family) | 1239 | switch (sa->sa_family) |
458 | { | 1240 | { |
459 | case AF_INET: | 1241 | case AF_INET: |
@@ -462,7 +1244,8 @@ handle_register (void *cls, | |||
462 | 1244 | ||
463 | alen = sizeof (struct sockaddr_in); | 1245 | alen = sizeof (struct sockaddr_in); |
464 | if (is_nat_v4 (&s4->sin_addr)) | 1246 | if (is_nat_v4 (&s4->sin_addr)) |
465 | ch->natted_address = GNUNET_YES; | 1247 | is_nat = GNUNET_YES; |
1248 | port = ntohs (s4->sin_port); | ||
466 | } | 1249 | } |
467 | break; | 1250 | break; |
468 | case AF_INET6: | 1251 | case AF_INET6: |
@@ -471,12 +1254,14 @@ handle_register (void *cls, | |||
471 | 1254 | ||
472 | alen = sizeof (struct sockaddr_in6); | 1255 | alen = sizeof (struct sockaddr_in6); |
473 | if (is_nat_v6 (&s6->sin6_addr)) | 1256 | if (is_nat_v6 (&s6->sin6_addr)) |
474 | ch->natted_address = GNUNET_YES; | 1257 | is_nat = GNUNET_YES; |
1258 | port = ntohs (s6->sin6_port); | ||
475 | } | 1259 | } |
476 | break; | 1260 | break; |
477 | #if AF_UNIX | 1261 | #if AF_UNIX |
478 | case AF_UNIX: | 1262 | case AF_UNIX: |
479 | alen = sizeof (struct sockaddr_un); | 1263 | alen = sizeof (struct sockaddr_un); |
1264 | port = 0; | ||
480 | break; | 1265 | break; |
481 | #endif | 1266 | #endif |
482 | default: | 1267 | default: |
@@ -484,13 +1269,45 @@ handle_register (void *cls, | |||
484 | GNUNET_SERVICE_client_drop (ch->client); | 1269 | GNUNET_SERVICE_client_drop (ch->client); |
485 | return; | 1270 | return; |
486 | } | 1271 | } |
1272 | /* store address */ | ||
487 | GNUNET_assert (alen <= left); | 1273 | GNUNET_assert (alen <= left); |
488 | ch->addrs[i] = GNUNET_malloc (alen); | 1274 | GNUNET_assert (alen <= sizeof (struct sockaddr_storage)); |
489 | GNUNET_memcpy (ch->addrs[i], | 1275 | GNUNET_memcpy (&ch->caddrs[i].ss, |
490 | sa, | 1276 | sa, |
491 | alen); | 1277 | alen); |
1278 | |||
1279 | /* If applicable, try UPNPC NAT punching */ | ||
1280 | if ( (is_nat) && | ||
1281 | (enable_upnp) && | ||
1282 | ( (IPPROTO_TCP == ch->proto) || | ||
1283 | (IPPROTO_UDP == ch->proto) ) ) | ||
1284 | { | ||
1285 | ch->natted_address = GNUNET_YES; | ||
1286 | ch->caddrs[i].mh | ||
1287 | = GNUNET_NAT_mini_map_start (port, | ||
1288 | IPPROTO_TCP == ch->proto, | ||
1289 | &upnp_addr_change_cb, | ||
1290 | ch); | ||
1291 | } | ||
1292 | |||
492 | off += alen; | 1293 | off += alen; |
493 | } | 1294 | } |
1295 | /* Actually send IP address list to client */ | ||
1296 | for (struct LocalAddressList *lal = lal_head; | ||
1297 | NULL != lal; | ||
1298 | lal = lal->next) | ||
1299 | { | ||
1300 | check_notify_client (lal, | ||
1301 | ch, | ||
1302 | GNUNET_YES); | ||
1303 | } | ||
1304 | /* Also consider IPv4 determined by `external-ip` */ | ||
1305 | if (0 != mini_external_ipv4.s_addr) | ||
1306 | { | ||
1307 | check_notify_client_external_ipv4_change (&mini_external_ipv4, | ||
1308 | ch, | ||
1309 | GNUNET_YES); | ||
1310 | } | ||
494 | GNUNET_SERVICE_client_continue (ch->client); | 1311 | GNUNET_SERVICE_client_continue (ch->client); |
495 | } | 1312 | } |
496 | 1313 | ||
@@ -551,7 +1368,7 @@ notify_clients_stun_change (const struct sockaddr_in *ip, | |||
551 | sizeof (v4), | 1368 | sizeof (v4), |
552 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | 1369 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); |
553 | msg->add_remove = htonl ((int32_t) add); | 1370 | msg->add_remove = htonl ((int32_t) add); |
554 | msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN | | 1371 | msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN | |
555 | GNUNET_NAT_AC_GLOBAL); | 1372 | GNUNET_NAT_AC_GLOBAL); |
556 | GNUNET_memcpy (&msg[1], | 1373 | GNUNET_memcpy (&msg[1], |
557 | &v4, | 1374 | &v4, |
@@ -826,344 +1643,311 @@ check_autoconfig_request (void *cls, | |||
826 | 1643 | ||
827 | 1644 | ||
828 | /** | 1645 | /** |
829 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from | 1646 | * Stop all pending activities with respect to the @a ac |
830 | * client. | ||
831 | * | 1647 | * |
832 | * @param cls client who sent the message | 1648 | * @param ac autoconfiguration to terminate activities for |
833 | * @param message the message received | ||
834 | */ | 1649 | */ |
835 | static void | 1650 | static void |
836 | handle_autoconfig_request (void *cls, | 1651 | terminate_ac_activities (struct AutoconfigContext *ac) |
837 | const struct GNUNET_NAT_AutoconfigRequestMessage *message) | ||
838 | { | 1652 | { |
839 | struct ClientHandle *ch = cls; | 1653 | if (NULL != ac->probe_external) |
840 | size_t left = ntohs (message->header.size) - sizeof (*message); | ||
841 | struct GNUNET_CONFIGURATION_Handle *c; | ||
842 | |||
843 | c = GNUNET_CONFIGURATION_create (); | ||
844 | if (GNUNET_OK != | ||
845 | GNUNET_CONFIGURATION_deserialize (c, | ||
846 | (const char *) &message[1], | ||
847 | left, | ||
848 | GNUNET_NO)) | ||
849 | { | 1654 | { |
850 | GNUNET_break (0); | 1655 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external); |
851 | GNUNET_SERVICE_client_drop (ch->client); | 1656 | ac->probe_external = NULL; |
852 | return; | 1657 | } |
1658 | if (NULL != ac->timeout_task) | ||
1659 | { | ||
1660 | GNUNET_SCHEDULER_cancel (ac->timeout_task); | ||
1661 | ac->timeout_task = NULL; | ||
853 | } | 1662 | } |
854 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
855 | "Received REQUEST_AUTO_CONFIG message from client\n"); | ||
856 | // FIXME: actually handle request... | ||
857 | GNUNET_CONFIGURATION_destroy (c); | ||
858 | GNUNET_SERVICE_client_continue (ch->client); | ||
859 | } | 1663 | } |
860 | 1664 | ||
861 | 1665 | ||
862 | /** | 1666 | /** |
863 | * Task run during shutdown. | 1667 | * Finish handling the autoconfiguration request and send |
1668 | * the response to the client. | ||
864 | * | 1669 | * |
865 | * @param cls unused | 1670 | * @param cls the `struct AutoconfigContext` to conclude |
866 | */ | 1671 | */ |
867 | static void | 1672 | static void |
868 | shutdown_task (void *cls) | 1673 | conclude_autoconfig_request (void *cls) |
869 | { | 1674 | { |
870 | struct StunExternalIP *se; | 1675 | struct AutoconfigContext *ac = cls; |
1676 | struct ClientHandle *ch = ac->ch; | ||
1677 | struct GNUNET_NAT_AutoconfigResultMessage *arm; | ||
1678 | struct GNUNET_MQ_Envelope *env; | ||
1679 | size_t c_size; | ||
1680 | char *buf; | ||
1681 | struct GNUNET_CONFIGURATION_Handle *diff; | ||
1682 | |||
1683 | ac->timeout_task = NULL; | ||
1684 | terminate_ac_activities (ac); | ||
1685 | |||
1686 | /* Send back response */ | ||
1687 | diff = GNUNET_CONFIGURATION_get_diff (ac->orig, | ||
1688 | ac->c); | ||
1689 | buf = GNUNET_CONFIGURATION_serialize (diff, | ||
1690 | &c_size); | ||
1691 | GNUNET_CONFIGURATION_destroy (diff); | ||
1692 | env = GNUNET_MQ_msg_extra (arm, | ||
1693 | c_size, | ||
1694 | GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT); | ||
1695 | arm->status_code = htonl ((uint32_t) ac->status_code); | ||
1696 | arm->type = htonl ((uint32_t) ac->type); | ||
1697 | GNUNET_memcpy (&arm[1], | ||
1698 | buf, | ||
1699 | c_size); | ||
1700 | GNUNET_free (buf); | ||
1701 | GNUNET_MQ_send (ch->mq, | ||
1702 | env); | ||
871 | 1703 | ||
872 | while (NULL != (se = se_head)) | 1704 | /* clean up */ |
873 | { | 1705 | GNUNET_free (ac->system_type); |
874 | GNUNET_CONTAINER_DLL_remove (se_head, | 1706 | GNUNET_CONFIGURATION_destroy (ac->orig); |
875 | se_tail, | 1707 | GNUNET_CONFIGURATION_destroy (ac->c); |
876 | se); | 1708 | GNUNET_CONTAINER_DLL_remove (ac_head, |
877 | GNUNET_SCHEDULER_cancel (se->timeout_task); | 1709 | ac_tail, |
878 | GNUNET_free (se); | 1710 | ac); |
879 | } | 1711 | GNUNET_free (ac); |
880 | if (NULL != scan_task) | 1712 | GNUNET_SERVICE_client_continue (ch->client); |
881 | { | ||
882 | GNUNET_SCHEDULER_cancel (scan_task); | ||
883 | scan_task = NULL; | ||
884 | } | ||
885 | if (NULL != stats) | ||
886 | { | ||
887 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | ||
888 | stats = NULL; | ||
889 | } | ||
890 | destroy_lal (); | ||
891 | } | 1713 | } |
892 | 1714 | ||
893 | 1715 | ||
894 | /** | 1716 | /** |
895 | * Closure for #ifc_proc. | 1717 | * Check if all autoconfiguration operations have concluded, |
1718 | * and if they have, send the result back to the client. | ||
1719 | * | ||
1720 | * @param ac autoconfiguation context to check | ||
896 | */ | 1721 | */ |
897 | struct IfcProcContext | 1722 | static void |
1723 | check_autoconfig_finished (struct AutoconfigContext *ac) | ||
898 | { | 1724 | { |
899 | 1725 | if (NULL != ac->probe_external) | |
900 | /** | 1726 | return; |
901 | * Head of DLL of local addresses. | 1727 | GNUNET_SCHEDULER_cancel (ac->timeout_task); |
902 | */ | 1728 | ac->timeout_task |
903 | struct LocalAddressList *lal_head; | 1729 | = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request, |
904 | 1730 | ac); | |
905 | /** | 1731 | } |
906 | * Tail of DLL of local addresses. | ||
907 | */ | ||
908 | struct LocalAddressList *lal_tail; | ||
909 | |||
910 | }; | ||
911 | 1732 | ||
912 | 1733 | ||
913 | /** | 1734 | /** |
914 | * Callback function invoked for each interface found. Adds them | 1735 | * Update ENABLE_UPNPC configuration option. |
915 | * to our new address list. | ||
916 | * | 1736 | * |
917 | * @param cls a `struct IfcProcContext *` | 1737 | * @param ac autoconfiguration to update |
918 | * @param name name of the interface (can be NULL for unknown) | ||
919 | * @param isDefault is this presumably the default interface | ||
920 | * @param addr address of this interface (can be NULL for unknown or unassigned) | ||
921 | * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) | ||
922 | * @param netmask the network mask (can be NULL for unknown or unassigned) | ||
923 | * @param addrlen length of the address | ||
924 | * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort | ||
925 | */ | 1738 | */ |
926 | static int | 1739 | static void |
927 | ifc_proc (void *cls, | 1740 | update_enable_upnpc_option (struct AutoconfigContext *ac) |
928 | const char *name, | ||
929 | int isDefault, | ||
930 | const struct sockaddr *addr, | ||
931 | const struct sockaddr *broadcast_addr, | ||
932 | const struct sockaddr *netmask, | ||
933 | socklen_t addrlen) | ||
934 | { | 1741 | { |
935 | struct IfcProcContext *ifc_ctx = cls; | 1742 | switch (ac->enable_upnpc) |
936 | struct LocalAddressList *lal; | ||
937 | size_t alen; | ||
938 | const struct in_addr *ip4; | ||
939 | const struct in6_addr *ip6; | ||
940 | enum GNUNET_NAT_AddressClass ac; | ||
941 | |||
942 | switch (addr->sa_family) | ||
943 | { | 1743 | { |
944 | case AF_INET: | 1744 | case GNUNET_YES: |
945 | alen = sizeof (struct sockaddr_in); | 1745 | GNUNET_CONFIGURATION_set_value_string (ac->c, |
946 | ip4 = &((const struct sockaddr_in *) addr)->sin_addr; | 1746 | "NAT", |
947 | if (match_ipv4 ("127.0.0.0", ip4, 8)) | 1747 | "ENABLE_UPNP", |
948 | ac = GNUNET_NAT_AC_LOOPBACK; | 1748 | "YES"); |
949 | else if (is_nat_v4 (ip4)) | ||
950 | ac = GNUNET_NAT_AC_LAN; | ||
951 | else | ||
952 | ac = GNUNET_NAT_AC_GLOBAL; | ||
953 | break; | 1749 | break; |
954 | case AF_INET6: | 1750 | case GNUNET_NO: |
955 | alen = sizeof (struct sockaddr_in6); | 1751 | GNUNET_CONFIGURATION_set_value_string (ac->c, |
956 | ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr; | 1752 | "NAT", |
957 | if (match_ipv6 ("::1", ip6, 128)) | 1753 | "ENABLE_UPNP", |
958 | ac = GNUNET_NAT_AC_LOOPBACK; | 1754 | "NO"); |
959 | else if (is_nat_v6 (ip6)) | 1755 | break; |
960 | ac = GNUNET_NAT_AC_LAN; | 1756 | case GNUNET_SYSERR: |
961 | else | 1757 | /* We are unsure, do not change option */ |
962 | ac = GNUNET_NAT_AC_GLOBAL; | ||
963 | if ( (ip6->s6_addr[11] == 0xFF) && | ||
964 | (ip6->s6_addr[12] == 0xFE) ) | ||
965 | { | ||
966 | /* contains a MAC, be extra careful! */ | ||
967 | ac |= GNUNET_NAT_AC_PRIVATE; | ||
968 | } | ||
969 | break; | 1758 | break; |
970 | #if AF_UNIX | ||
971 | case AF_UNIX: | ||
972 | GNUNET_break (0); | ||
973 | return GNUNET_OK; | ||
974 | #endif | ||
975 | default: | ||
976 | GNUNET_break (0); | ||
977 | return GNUNET_OK; | ||
978 | } | 1759 | } |
979 | lal = GNUNET_malloc (sizeof (*lal)); | ||
980 | lal->af = addr->sa_family; | ||
981 | lal->ac = ac; | ||
982 | GNUNET_memcpy (&lal->addr, | ||
983 | addr, | ||
984 | alen); | ||
985 | GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head, | ||
986 | ifc_ctx->lal_tail, | ||
987 | lal); | ||
988 | return GNUNET_OK; | ||
989 | } | 1760 | } |
990 | 1761 | ||
991 | 1762 | ||
992 | /** | 1763 | /** |
993 | * Notify client about a change in the list | 1764 | * Handle result from external IP address probe during |
994 | * of addresses this peer has. | 1765 | * autoconfiguration. |
995 | * | 1766 | * |
996 | * @param delta the entry in the list that changed | 1767 | * @param cls our `struct AutoconfigContext` |
997 | * @param ch client to contact | 1768 | * @param addr the address, NULL on errors |
998 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | 1769 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code |
999 | * @param addr the address that changed | ||
1000 | * @param addr_len number of bytes in @a addr | ||
1001 | */ | 1770 | */ |
1002 | static void | 1771 | static void |
1003 | notify_client (struct LocalAddressList *delta, | 1772 | auto_external_result_cb (void *cls, |
1004 | struct ClientHandle *ch, | 1773 | const struct in_addr *addr, |
1005 | int add, | 1774 | enum GNUNET_NAT_StatusCode result) |
1006 | const void *addr, | ||
1007 | size_t addr_len) | ||
1008 | { | 1775 | { |
1009 | struct GNUNET_MQ_Envelope *env; | 1776 | struct AutoconfigContext *ac = cls; |
1010 | struct GNUNET_NAT_AddressChangeNotificationMessage *msg; | ||
1011 | 1777 | ||
1012 | env = GNUNET_MQ_msg_extra (msg, | 1778 | ac->probe_external = NULL; |
1013 | addr_len, | 1779 | switch (result) |
1014 | GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE); | 1780 | { |
1015 | msg->add_remove = htonl (add); | 1781 | case GNUNET_NAT_ERROR_SUCCESS: |
1016 | msg->addr_class = htonl (delta->ac); | 1782 | ac->enable_upnpc = GNUNET_YES; |
1017 | GNUNET_memcpy (&msg[1], | 1783 | break; |
1018 | addr, | 1784 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: |
1019 | addr_len); | 1785 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: |
1020 | GNUNET_MQ_send (ch->mq, | 1786 | case GNUNET_NAT_ERROR_IPC_FAILURE: |
1021 | env); | 1787 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1022 | } | 1788 | "Disabling UPNPC: %d\n", |
1789 | (int) result); | ||
1790 | ac->enable_upnpc = GNUNET_NO; /* did not work */ | ||
1791 | break; | ||
1792 | default: | ||
1793 | GNUNET_break (0); /* unexpected */ | ||
1794 | ac->enable_upnpc = GNUNET_SYSERR; | ||
1795 | break; | ||
1796 | } | ||
1797 | update_enable_upnpc_option (ac); | ||
1798 | check_autoconfig_finished (ac); | ||
1799 | } | ||
1023 | 1800 | ||
1024 | 1801 | ||
1025 | /** | 1802 | /** |
1026 | * Notify all clients about a change in the list | 1803 | * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from |
1027 | * of addresses this peer has. | 1804 | * client. |
1028 | * | 1805 | * |
1029 | * @param delta the entry in the list that changed | 1806 | * @param cls client who sent the message |
1030 | * @param add #GNUNET_YES to add, #GNUNET_NO to remove | 1807 | * @param message the message received |
1031 | */ | 1808 | */ |
1032 | static void | 1809 | static void |
1033 | notify_clients (struct LocalAddressList *delta, | 1810 | handle_autoconfig_request (void *cls, |
1034 | int add) | 1811 | const struct GNUNET_NAT_AutoconfigRequestMessage *message) |
1035 | { | 1812 | { |
1036 | for (struct ClientHandle *ch = ch_head; | 1813 | struct ClientHandle *ch = cls; |
1037 | NULL != ch; | 1814 | size_t left = ntohs (message->header.size) - sizeof (*message); |
1038 | ch = ch->next) | 1815 | struct LocalAddressList *lal; |
1816 | struct AutoconfigContext *ac; | ||
1817 | |||
1818 | ac = GNUNET_new (struct AutoconfigContext); | ||
1819 | ac->status_code = GNUNET_NAT_ERROR_SUCCESS; | ||
1820 | ac->ch = ch; | ||
1821 | ac->c = GNUNET_CONFIGURATION_create (); | ||
1822 | if (GNUNET_OK != | ||
1823 | GNUNET_CONFIGURATION_deserialize (ac->c, | ||
1824 | (const char *) &message[1], | ||
1825 | left, | ||
1826 | GNUNET_NO)) | ||
1039 | { | 1827 | { |
1040 | size_t alen; | 1828 | GNUNET_break (0); |
1041 | struct sockaddr_in v4; | 1829 | GNUNET_SERVICE_client_drop (ch->client); |
1042 | struct sockaddr_in6 v6; | 1830 | GNUNET_CONFIGURATION_destroy (ac->c); |
1043 | 1831 | GNUNET_free (ac); | |
1044 | if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES)) | 1832 | return; |
1045 | continue; | 1833 | } |
1046 | switch (delta->af) | 1834 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1835 | "Received REQUEST_AUTO_CONFIG message from client\n"); | ||
1836 | |||
1837 | if (GNUNET_OK != | ||
1838 | GNUNET_CONFIGURATION_get_value_string (ac->c, | ||
1839 | "PEER", | ||
1840 | "SYSTEM_TYPE", | ||
1841 | &ac->system_type)) | ||
1842 | ac->system_type = GNUNET_strdup ("UNKNOWN"); | ||
1843 | |||
1844 | GNUNET_CONTAINER_DLL_insert (ac_head, | ||
1845 | ac_tail, | ||
1846 | ac); | ||
1847 | ac->orig | ||
1848 | = GNUNET_CONFIGURATION_dup (ac->c); | ||
1849 | ac->timeout_task | ||
1850 | = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT, | ||
1851 | &conclude_autoconfig_request, | ||
1852 | ac); | ||
1853 | ac->enable_upnpc = GNUNET_SYSERR; /* undecided */ | ||
1854 | |||
1855 | /* Probe for upnpc */ | ||
1856 | if (GNUNET_SYSERR == | ||
1857 | GNUNET_OS_check_helper_binary ("upnpc", | ||
1858 | GNUNET_NO, | ||
1859 | NULL)) | ||
1860 | { | ||
1861 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1862 | _("UPnP client `upnpc` command not found, disabling UPnP\n")); | ||
1863 | ac->enable_upnpc = GNUNET_NO; | ||
1864 | } | ||
1865 | else | ||
1866 | { | ||
1867 | for (lal = lal_head; NULL != lal; lal = lal->next) | ||
1868 | if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN)) | ||
1869 | /* we are behind NAT, useful to try upnpc */ | ||
1870 | ac->enable_upnpc = GNUNET_YES; | ||
1871 | } | ||
1872 | if (GNUNET_YES == ac->enable_upnpc) | ||
1873 | { | ||
1874 | /* If we are a mobile device, always leave it on as the network | ||
1875 | may change to one that supports UPnP anytime. If we are | ||
1876 | stationary, check if our network actually supports UPnP, and if | ||
1877 | not, disable it. */ | ||
1878 | if ( (0 == strcasecmp (ac->system_type, | ||
1879 | "INFRASTRUCTURE")) || | ||
1880 | (0 == strcasecmp (ac->system_type, | ||
1881 | "DESKTOP")) ) | ||
1047 | { | 1882 | { |
1048 | case AF_INET: | 1883 | /* Check if upnpc gives us an external IP */ |
1049 | alen = sizeof (struct sockaddr_in); | 1884 | ac->probe_external |
1050 | GNUNET_memcpy (&v4, | 1885 | = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb, |
1051 | &delta->addr, | 1886 | ac); |
1052 | alen); | ||
1053 | for (unsigned int i=0;i<ch->num_addrs;i++) | ||
1054 | { | ||
1055 | const struct sockaddr_in *c4; | ||
1056 | |||
1057 | if (AF_INET != ch->addrs[i]->sa_family) | ||
1058 | continue; /* IPv4 not relevant */ | ||
1059 | c4 = (const struct sockaddr_in *) ch->addrs[i]; | ||
1060 | v4.sin_port = c4->sin_port; | ||
1061 | notify_client (delta, | ||
1062 | ch, | ||
1063 | add, | ||
1064 | &v4, | ||
1065 | alen); | ||
1066 | } | ||
1067 | break; | ||
1068 | case AF_INET6: | ||
1069 | alen = sizeof (struct sockaddr_in6); | ||
1070 | GNUNET_memcpy (&v6, | ||
1071 | &delta->addr, | ||
1072 | alen); | ||
1073 | for (unsigned int i=0;i<ch->num_addrs;i++) | ||
1074 | { | ||
1075 | const struct sockaddr_in6 *c6; | ||
1076 | |||
1077 | if (AF_INET6 != ch->addrs[i]->sa_family) | ||
1078 | continue; /* IPv4 not relevant */ | ||
1079 | c6 = (const struct sockaddr_in6 *) ch->addrs[i]; | ||
1080 | v6.sin6_port = c6->sin6_port; | ||
1081 | notify_client (delta, | ||
1082 | ch, | ||
1083 | add, | ||
1084 | &v6, | ||
1085 | alen); | ||
1086 | } | ||
1087 | break; | ||
1088 | default: | ||
1089 | GNUNET_break (0); | ||
1090 | continue; | ||
1091 | } | 1887 | } |
1092 | } | 1888 | } |
1889 | if (NULL == ac->probe_external) | ||
1890 | update_enable_upnpc_option (ac); | ||
1891 | |||
1892 | /* Finally, check if we are already done */ | ||
1893 | check_autoconfig_finished (ac); | ||
1093 | } | 1894 | } |
1094 | 1895 | ||
1095 | 1896 | ||
1096 | /** | 1897 | /** |
1097 | * Task we run periodically to scan for network interfaces. | 1898 | * Task run during shutdown. |
1098 | * | 1899 | * |
1099 | * @param cls NULL | 1900 | * @param cls unused |
1100 | */ | 1901 | */ |
1101 | static void | 1902 | static void |
1102 | run_scan (void *cls) | 1903 | shutdown_task (void *cls) |
1103 | { | 1904 | { |
1104 | struct IfcProcContext ifc_ctx; | 1905 | struct StunExternalIP *se; |
1105 | int found; | 1906 | struct AutoconfigContext *ac; |
1106 | 1907 | ||
1107 | scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ, | 1908 | while (NULL != (ac = ac_head)) |
1108 | &run_scan, | ||
1109 | NULL); | ||
1110 | memset (&ifc_ctx, | ||
1111 | 0, | ||
1112 | sizeof (ifc_ctx)); | ||
1113 | GNUNET_OS_network_interfaces_list (&ifc_proc, | ||
1114 | &ifc_ctx); | ||
1115 | for (struct LocalAddressList *lal = lal_head; | ||
1116 | NULL != lal; | ||
1117 | lal = lal->next) | ||
1118 | { | 1909 | { |
1119 | found = GNUNET_NO; | 1910 | GNUNET_CONTAINER_DLL_remove (ac_head, |
1120 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | 1911 | ac_tail, |
1121 | NULL != pos; | 1912 | ac); |
1122 | pos = pos->next) | 1913 | terminate_ac_activities (ac); |
1123 | { | 1914 | GNUNET_free (ac); |
1124 | if ( (pos->af == lal->af) && | ||
1125 | (0 == memcmp (&lal->addr, | ||
1126 | &pos->addr, | ||
1127 | (AF_INET == lal->af) | ||
1128 | ? sizeof (struct sockaddr_in) | ||
1129 | : sizeof (struct sockaddr_in6))) ) | ||
1130 | found = GNUNET_YES; | ||
1131 | } | ||
1132 | if (GNUNET_NO == found) | ||
1133 | notify_clients (lal, | ||
1134 | GNUNET_NO); | ||
1135 | } | 1915 | } |
1136 | 1916 | while (NULL != (se = se_head)) | |
1137 | for (struct LocalAddressList *pos = ifc_ctx.lal_head; | ||
1138 | NULL != pos; | ||
1139 | pos = pos->next) | ||
1140 | { | 1917 | { |
1141 | found = GNUNET_NO; | 1918 | GNUNET_CONTAINER_DLL_remove (se_head, |
1142 | for (struct LocalAddressList *lal = lal_head; | 1919 | se_tail, |
1143 | NULL != lal; | 1920 | se); |
1144 | lal = lal->next) | 1921 | GNUNET_SCHEDULER_cancel (se->timeout_task); |
1145 | { | 1922 | GNUNET_free (se); |
1146 | if ( (pos->af == lal->af) && | 1923 | } |
1147 | (0 == memcmp (&lal->addr, | 1924 | if (NULL != probe_external_ip_task) |
1148 | &pos->addr, | 1925 | { |
1149 | (AF_INET == lal->af) | 1926 | GNUNET_SCHEDULER_cancel (probe_external_ip_task); |
1150 | ? sizeof (struct sockaddr_in) | 1927 | probe_external_ip_task = NULL; |
1151 | : sizeof (struct sockaddr_in6))) ) | 1928 | } |
1152 | found = GNUNET_YES; | 1929 | if (NULL != probe_external_ip_op) |
1153 | } | 1930 | { |
1154 | if (GNUNET_NO == found) | 1931 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op); |
1155 | notify_clients (pos, | 1932 | probe_external_ip_op = NULL; |
1156 | GNUNET_YES); | 1933 | } |
1934 | if (NULL != scan_task) | ||
1935 | { | ||
1936 | GNUNET_SCHEDULER_cancel (scan_task); | ||
1937 | scan_task = NULL; | ||
1938 | } | ||
1939 | if (NULL != stats) | ||
1940 | { | ||
1941 | GNUNET_STATISTICS_destroy (stats, | ||
1942 | GNUNET_NO); | ||
1943 | stats = NULL; | ||
1157 | } | 1944 | } |
1158 | |||
1159 | destroy_lal (); | 1945 | destroy_lal (); |
1160 | lal_head = ifc_ctx.lal_head; | ||
1161 | lal_tail = ifc_ctx.lal_tail; | ||
1162 | } | 1946 | } |
1163 | 1947 | ||
1164 | 1948 | ||
1165 | /** | 1949 | /** |
1166 | * Handle network size estimate clients. | 1950 | * Setup NAT service. |
1167 | * | 1951 | * |
1168 | * @param cls closure | 1952 | * @param cls closure |
1169 | * @param c configuration to use | 1953 | * @param c configuration to use |
@@ -1181,6 +1965,26 @@ run (void *cls, | |||
1181 | "STUN_STALE", | 1965 | "STUN_STALE", |
1182 | &stun_stale_timeout)) | 1966 | &stun_stale_timeout)) |
1183 | stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; | 1967 | stun_stale_timeout = GNUNET_TIME_UNIT_HOURS; |
1968 | |||
1969 | /* Check for UPnP */ | ||
1970 | enable_upnp | ||
1971 | = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1972 | "NAT", | ||
1973 | "ENABLE_UPNP"); | ||
1974 | if (GNUNET_YES == enable_upnp) | ||
1975 | { | ||
1976 | /* check if it works */ | ||
1977 | if (GNUNET_SYSERR == | ||
1978 | GNUNET_OS_check_helper_binary ("upnpc", | ||
1979 | GNUNET_NO, | ||
1980 | NULL)) | ||
1981 | { | ||
1982 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1983 | _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n")); | ||
1984 | enable_upnp = GNUNET_SYSERR; | ||
1985 | } | ||
1986 | } | ||
1987 | |||
1184 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | 1988 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, |
1185 | NULL); | 1989 | NULL); |
1186 | stats = GNUNET_STATISTICS_create ("nat", | 1990 | stats = GNUNET_STATISTICS_create ("nat", |
@@ -1232,9 +2036,15 @@ client_disconnect_cb (void *cls, | |||
1232 | GNUNET_CONTAINER_DLL_remove (ch_head, | 2036 | GNUNET_CONTAINER_DLL_remove (ch_head, |
1233 | ch_tail, | 2037 | ch_tail, |
1234 | ch); | 2038 | ch); |
1235 | for (unsigned int i=0;i<ch->num_addrs;i++) | 2039 | for (unsigned int i=0;i<ch->num_caddrs;i++) |
1236 | GNUNET_free_non_null (ch->addrs[i]); | 2040 | { |
1237 | GNUNET_free_non_null (ch->addrs); | 2041 | if (NULL != ch->caddrs[i].mh) |
2042 | { | ||
2043 | GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh); | ||
2044 | ch->caddrs[i].mh = NULL; | ||
2045 | } | ||
2046 | } | ||
2047 | GNUNET_free_non_null (ch->caddrs); | ||
1238 | GNUNET_free (ch); | 2048 | GNUNET_free (ch); |
1239 | } | 2049 | } |
1240 | 2050 | ||
diff --git a/src/nat/gnunet-service-nat_mini.c b/src/nat/gnunet-service-nat_mini.c new file mode 100644 index 000000000..e5b9d021b --- /dev/null +++ b/src/nat/gnunet-service-nat_mini.c | |||
@@ -0,0 +1,763 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014, 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/gnunet-service-nat_mini.c | ||
23 | * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_nat_service.h" | ||
29 | #include "gnunet-service-nat_mini.h" | ||
30 | #include "nat.h" | ||
31 | |||
32 | #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) | ||
33 | |||
34 | /** | ||
35 | * How long do we give upnpc to create a mapping? | ||
36 | */ | ||
37 | #define MAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15) | ||
38 | |||
39 | /** | ||
40 | * How long do we give upnpc to remove a mapping? | ||
41 | */ | ||
42 | #define UNMAP_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) | ||
43 | |||
44 | /** | ||
45 | * How often do we check for changes in the mapping? | ||
46 | */ | ||
47 | #define MAP_REFRESH_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
48 | |||
49 | |||
50 | /* ************************* external-ip calling ************************ */ | ||
51 | |||
52 | /** | ||
53 | * Opaque handle to cancel "GNUNET_NAT_mini_get_external_ipv4" operation. | ||
54 | */ | ||
55 | struct GNUNET_NAT_ExternalHandle | ||
56 | { | ||
57 | |||
58 | /** | ||
59 | * Function to call with the result. | ||
60 | */ | ||
61 | GNUNET_NAT_IPCallback cb; | ||
62 | |||
63 | /** | ||
64 | * Closure for @e cb. | ||
65 | */ | ||
66 | void *cb_cls; | ||
67 | |||
68 | /** | ||
69 | * Read task. | ||
70 | */ | ||
71 | struct GNUNET_SCHEDULER_Task *task; | ||
72 | |||
73 | /** | ||
74 | * Handle to `external-ip` process. | ||
75 | */ | ||
76 | struct GNUNET_OS_Process *eip; | ||
77 | |||
78 | /** | ||
79 | * Handle to stdout pipe of `external-ip`. | ||
80 | */ | ||
81 | struct GNUNET_DISK_PipeHandle *opipe; | ||
82 | |||
83 | /** | ||
84 | * Read handle of @e opipe. | ||
85 | */ | ||
86 | const struct GNUNET_DISK_FileHandle *r; | ||
87 | |||
88 | /** | ||
89 | * Number of bytes in @e buf that are valid. | ||
90 | */ | ||
91 | size_t off; | ||
92 | |||
93 | /** | ||
94 | * Destination of our read operation (output of 'external-ip'). | ||
95 | */ | ||
96 | char buf[17]; | ||
97 | |||
98 | /** | ||
99 | * Error code for better debugging and user feedback | ||
100 | */ | ||
101 | enum GNUNET_NAT_StatusCode ret; | ||
102 | }; | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Read the output of `external-ip` into `buf`. When complete, parse | ||
107 | * the address and call our callback. | ||
108 | * | ||
109 | * @param cls the `struct GNUNET_NAT_ExternalHandle` | ||
110 | */ | ||
111 | static void | ||
112 | read_external_ipv4 (void *cls) | ||
113 | { | ||
114 | struct GNUNET_NAT_ExternalHandle *eh = cls; | ||
115 | ssize_t ret; | ||
116 | struct in_addr addr; | ||
117 | |||
118 | eh->task = NULL; | ||
119 | ret = GNUNET_DISK_file_read (eh->r, | ||
120 | &eh->buf[eh->off], | ||
121 | sizeof (eh->buf) - eh->off); | ||
122 | if (ret > 0) | ||
123 | { | ||
124 | /* try to read more */ | ||
125 | eh->off += ret; | ||
126 | eh->task | ||
127 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
128 | eh->r, | ||
129 | &read_external_ipv4, | ||
130 | eh); | ||
131 | return; | ||
132 | } | ||
133 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID; | ||
134 | if ( (eh->off > 7) && | ||
135 | (eh->buf[eh->off - 1] == '\n') ) | ||
136 | { | ||
137 | eh->buf[eh->off - 1] = '\0'; | ||
138 | if (1 == inet_pton (AF_INET, | ||
139 | eh->buf, | ||
140 | &addr)) | ||
141 | { | ||
142 | if (0 == addr.s_addr) | ||
143 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID; /* got 0.0.0.0 */ | ||
144 | else | ||
145 | eh->ret = GNUNET_NAT_ERROR_SUCCESS; | ||
146 | } | ||
147 | } | ||
148 | eh->cb (eh->cb_cls, | ||
149 | (GNUNET_NAT_ERROR_SUCCESS == eh->ret) ? &addr : NULL, | ||
150 | eh->ret); | ||
151 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (eh); | ||
152 | } | ||
153 | |||
154 | |||
155 | /** | ||
156 | * (Asynchronously) signal error invoking `external-ip` to client. | ||
157 | * | ||
158 | * @param cls the `struct GNUNET_NAT_ExternalHandle` (freed) | ||
159 | */ | ||
160 | static void | ||
161 | signal_external_ip_error (void *cls) | ||
162 | { | ||
163 | struct GNUNET_NAT_ExternalHandle *eh = cls; | ||
164 | |||
165 | eh->task = NULL; | ||
166 | eh->cb (eh->cb_cls, | ||
167 | NULL, | ||
168 | eh->ret); | ||
169 | GNUNET_free (eh); | ||
170 | } | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Try to get the external IPv4 address of this peer. | ||
175 | * | ||
176 | * @param cb function to call with result | ||
177 | * @param cb_cls closure for @a cb | ||
178 | * @return handle for cancellation (can only be used until @a cb is called), never NULL | ||
179 | */ | ||
180 | struct GNUNET_NAT_ExternalHandle * | ||
181 | GNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb, | ||
182 | void *cb_cls) | ||
183 | { | ||
184 | struct GNUNET_NAT_ExternalHandle *eh; | ||
185 | |||
186 | eh = GNUNET_new (struct GNUNET_NAT_ExternalHandle); | ||
187 | eh->cb = cb; | ||
188 | eh->cb_cls = cb_cls; | ||
189 | eh->ret = GNUNET_NAT_ERROR_SUCCESS; | ||
190 | if (GNUNET_SYSERR == | ||
191 | GNUNET_OS_check_helper_binary ("external-ip", | ||
192 | GNUNET_NO, | ||
193 | NULL)) | ||
194 | { | ||
195 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
196 | _("`external-ip' command not found\n")); | ||
197 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND; | ||
198 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, | ||
199 | eh); | ||
200 | return eh; | ||
201 | } | ||
202 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
203 | "Running `external-ip' to determine our external IP\n"); | ||
204 | eh->opipe = GNUNET_DISK_pipe (GNUNET_YES, | ||
205 | GNUNET_YES, | ||
206 | GNUNET_NO, | ||
207 | GNUNET_YES); | ||
208 | if (NULL == eh->opipe) | ||
209 | { | ||
210 | eh->ret = GNUNET_NAT_ERROR_IPC_FAILURE; | ||
211 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, | ||
212 | eh); | ||
213 | return eh; | ||
214 | } | ||
215 | eh->eip = | ||
216 | GNUNET_OS_start_process (GNUNET_NO, | ||
217 | 0, | ||
218 | NULL, | ||
219 | eh->opipe, | ||
220 | NULL, | ||
221 | "external-ip", | ||
222 | "external-ip", | ||
223 | NULL); | ||
224 | if (NULL == eh->eip) | ||
225 | { | ||
226 | GNUNET_DISK_pipe_close (eh->opipe); | ||
227 | eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED; | ||
228 | eh->task = GNUNET_SCHEDULER_add_now (&signal_external_ip_error, | ||
229 | eh); | ||
230 | return eh; | ||
231 | } | ||
232 | GNUNET_DISK_pipe_close_end (eh->opipe, | ||
233 | GNUNET_DISK_PIPE_END_WRITE); | ||
234 | eh->r = GNUNET_DISK_pipe_handle (eh->opipe, | ||
235 | GNUNET_DISK_PIPE_END_READ); | ||
236 | eh->task | ||
237 | = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
238 | eh->r, | ||
239 | &read_external_ipv4, | ||
240 | eh); | ||
241 | return eh; | ||
242 | } | ||
243 | |||
244 | |||
245 | /** | ||
246 | * Cancel operation. | ||
247 | * | ||
248 | * @param eh operation to cancel | ||
249 | */ | ||
250 | void | ||
251 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct GNUNET_NAT_ExternalHandle *eh) | ||
252 | { | ||
253 | if (NULL != eh->eip) | ||
254 | { | ||
255 | (void) GNUNET_OS_process_kill (eh->eip, | ||
256 | SIGKILL); | ||
257 | GNUNET_OS_process_destroy (eh->eip); | ||
258 | } | ||
259 | if (NULL != eh->opipe) | ||
260 | { | ||
261 | GNUNET_DISK_pipe_close (eh->opipe); | ||
262 | eh->opipe = NULL; | ||
263 | } | ||
264 | if (NULL != eh->task) | ||
265 | { | ||
266 | GNUNET_SCHEDULER_cancel (eh->task); | ||
267 | eh->task = NULL; | ||
268 | } | ||
269 | GNUNET_free (eh); | ||
270 | } | ||
271 | |||
272 | |||
273 | /* ************************* upnpc calling ************************ */ | ||
274 | |||
275 | |||
276 | /** | ||
277 | * Handle to a mapping created with upnpc. | ||
278 | */ | ||
279 | struct GNUNET_NAT_MiniHandle | ||
280 | { | ||
281 | |||
282 | /** | ||
283 | * Function to call on mapping changes. | ||
284 | */ | ||
285 | GNUNET_NAT_MiniAddressCallback ac; | ||
286 | |||
287 | /** | ||
288 | * Closure for @e ac. | ||
289 | */ | ||
290 | void *ac_cls; | ||
291 | |||
292 | /** | ||
293 | * Command used to install the map. | ||
294 | */ | ||
295 | struct GNUNET_OS_CommandHandle *map_cmd; | ||
296 | |||
297 | /** | ||
298 | * Command used to refresh our map information. | ||
299 | */ | ||
300 | struct GNUNET_OS_CommandHandle *refresh_cmd; | ||
301 | |||
302 | /** | ||
303 | * Command used to remove the mapping. | ||
304 | */ | ||
305 | struct GNUNET_OS_CommandHandle *unmap_cmd; | ||
306 | |||
307 | /** | ||
308 | * Our current external mapping (if we have one). | ||
309 | */ | ||
310 | struct sockaddr_in current_addr; | ||
311 | |||
312 | /** | ||
313 | * We check the mapping periodically to see if it | ||
314 | * still works. This task triggers the check. | ||
315 | */ | ||
316 | struct GNUNET_SCHEDULER_Task *refresh_task; | ||
317 | |||
318 | /** | ||
319 | * Are we mapping TCP or UDP? | ||
320 | */ | ||
321 | int is_tcp; | ||
322 | |||
323 | /** | ||
324 | * Did we succeed with creating a mapping? | ||
325 | */ | ||
326 | int did_map; | ||
327 | |||
328 | /** | ||
329 | * Did we find our mapping during refresh scan? | ||
330 | */ | ||
331 | int found; | ||
332 | |||
333 | /** | ||
334 | * Which port are we mapping? | ||
335 | */ | ||
336 | uint16_t port; | ||
337 | |||
338 | }; | ||
339 | |||
340 | |||
341 | /** | ||
342 | * Run "upnpc -l" to find out if our mapping changed. | ||
343 | * | ||
344 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
345 | */ | ||
346 | static void | ||
347 | do_refresh (void *cls); | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Process the output from the "upnpc -r" command. | ||
352 | * | ||
353 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
354 | * @param line line of output, NULL at the end | ||
355 | */ | ||
356 | static void | ||
357 | process_map_output (void *cls, | ||
358 | const char *line); | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Run "upnpc -r" to map our internal port. | ||
363 | * | ||
364 | * @param mini our handle | ||
365 | */ | ||
366 | static void | ||
367 | run_upnpc_r (struct GNUNET_NAT_MiniHandle *mini) | ||
368 | { | ||
369 | char pstr[6]; | ||
370 | |||
371 | GNUNET_snprintf (pstr, | ||
372 | sizeof (pstr), | ||
373 | "%u", | ||
374 | (unsigned int) mini->port); | ||
375 | mini->map_cmd | ||
376 | = GNUNET_OS_command_run (&process_map_output, | ||
377 | mini, | ||
378 | MAP_TIMEOUT, | ||
379 | "upnpc", | ||
380 | "upnpc", | ||
381 | "-r", | ||
382 | pstr, | ||
383 | mini->is_tcp ? "tcp" : "udp", | ||
384 | NULL); | ||
385 | if (NULL == mini->map_cmd) | ||
386 | { | ||
387 | mini->ac (mini->ac_cls, | ||
388 | GNUNET_SYSERR, | ||
389 | NULL, | ||
390 | 0, | ||
391 | GNUNET_NAT_ERROR_UPNPC_FAILED); | ||
392 | return; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Process the output from "upnpc -l" to see if our | ||
399 | * external mapping changed. If so, do the notifications. | ||
400 | * | ||
401 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
402 | * @param line line of output, NULL at the end | ||
403 | */ | ||
404 | static void | ||
405 | process_refresh_output (void *cls, | ||
406 | const char *line) | ||
407 | { | ||
408 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
409 | char pstr[9]; | ||
410 | const char *s; | ||
411 | unsigned int nport; | ||
412 | struct in_addr exip; | ||
413 | |||
414 | if (NULL == line) | ||
415 | { | ||
416 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
417 | mini->refresh_cmd = NULL; | ||
418 | if (GNUNET_NO == mini->found) | ||
419 | { | ||
420 | /* mapping disappeared, try to re-create */ | ||
421 | if (GNUNET_YES == mini->did_map) | ||
422 | { | ||
423 | mini->ac (mini->ac_cls, | ||
424 | GNUNET_NO, | ||
425 | (const struct sockaddr *) &mini->current_addr, | ||
426 | sizeof (mini->current_addr), | ||
427 | GNUNET_NAT_ERROR_SUCCESS); | ||
428 | mini->did_map = GNUNET_NO; | ||
429 | } | ||
430 | run_upnpc_r (mini); | ||
431 | } | ||
432 | return; | ||
433 | } | ||
434 | if (! mini->did_map) | ||
435 | return; /* never mapped, won't find our mapping anyway */ | ||
436 | |||
437 | /* we're looking for output of the form: | ||
438 | * "ExternalIPAddress = 12.134.41.124" */ | ||
439 | |||
440 | s = strstr (line, | ||
441 | "ExternalIPAddress = "); | ||
442 | if (NULL != s) | ||
443 | { | ||
444 | s += strlen ("ExternalIPAddress = "); | ||
445 | if (1 != inet_pton (AF_INET, | ||
446 | s, | ||
447 | &exip)) | ||
448 | return; /* skip */ | ||
449 | if (exip.s_addr == mini->current_addr.sin_addr.s_addr) | ||
450 | return; /* no change */ | ||
451 | /* update mapping */ | ||
452 | mini->ac (mini->ac_cls, | ||
453 | GNUNET_NO, | ||
454 | (const struct sockaddr *) &mini->current_addr, | ||
455 | sizeof (mini->current_addr), | ||
456 | GNUNET_NAT_ERROR_SUCCESS); | ||
457 | mini->current_addr.sin_addr = exip; | ||
458 | mini->ac (mini->ac_cls, | ||
459 | GNUNET_YES, | ||
460 | (const struct sockaddr *) &mini->current_addr, | ||
461 | sizeof (mini->current_addr), | ||
462 | GNUNET_NAT_ERROR_SUCCESS); | ||
463 | return; | ||
464 | } | ||
465 | /* | ||
466 | * we're looking for output of the form: | ||
467 | * | ||
468 | * "0 TCP 3000->192.168.2.150:3000 'libminiupnpc' ''" | ||
469 | * "1 UDP 3001->192.168.2.150:3001 'libminiupnpc' ''" | ||
470 | * | ||
471 | * the pattern we look for is: | ||
472 | * | ||
473 | * "%s TCP PORT->STRING:OURPORT *" or | ||
474 | * "%s UDP PORT->STRING:OURPORT *" | ||
475 | */ | ||
476 | GNUNET_snprintf (pstr, | ||
477 | sizeof (pstr), | ||
478 | ":%u ", | ||
479 | mini->port); | ||
480 | if (NULL == (s = strstr (line, "->"))) | ||
481 | return; /* skip */ | ||
482 | if (NULL == strstr (s, pstr)) | ||
483 | return; /* skip */ | ||
484 | if (1 != | ||
485 | SSCANF (line, | ||
486 | (mini->is_tcp) ? "%*u TCP %u->%*s:%*u %*s" : | ||
487 | "%*u UDP %u->%*s:%*u %*s", &nport)) | ||
488 | return; /* skip */ | ||
489 | mini->found = GNUNET_YES; | ||
490 | if (nport == ntohs (mini->current_addr.sin_port)) | ||
491 | return; /* no change */ | ||
492 | |||
493 | /* external port changed, update mapping */ | ||
494 | mini->ac (mini->ac_cls, | ||
495 | GNUNET_NO, | ||
496 | (const struct sockaddr *) &mini->current_addr, | ||
497 | sizeof (mini->current_addr), | ||
498 | GNUNET_NAT_ERROR_SUCCESS); | ||
499 | mini->current_addr.sin_port = htons ((uint16_t) nport); | ||
500 | mini->ac (mini->ac_cls, | ||
501 | GNUNET_YES, | ||
502 | (const struct sockaddr *) &mini->current_addr, | ||
503 | sizeof (mini->current_addr), | ||
504 | GNUNET_NAT_ERROR_SUCCESS); | ||
505 | } | ||
506 | |||
507 | |||
508 | /** | ||
509 | * Run "upnpc -l" to find out if our mapping changed. | ||
510 | * | ||
511 | * @param cls the 'struct GNUNET_NAT_MiniHandle' | ||
512 | */ | ||
513 | static void | ||
514 | do_refresh (void *cls) | ||
515 | { | ||
516 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
517 | int ac; | ||
518 | |||
519 | mini->refresh_task | ||
520 | = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | ||
521 | &do_refresh, | ||
522 | mini); | ||
523 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
524 | "Running `upnpc' to check if our mapping still exists\n"); | ||
525 | mini->found = GNUNET_NO; | ||
526 | ac = GNUNET_NO; | ||
527 | if (NULL != mini->map_cmd) | ||
528 | { | ||
529 | /* took way too long, abort it! */ | ||
530 | GNUNET_OS_command_stop (mini->map_cmd); | ||
531 | mini->map_cmd = NULL; | ||
532 | ac = GNUNET_YES; | ||
533 | } | ||
534 | if (NULL != mini->refresh_cmd) | ||
535 | { | ||
536 | /* took way too long, abort it! */ | ||
537 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
538 | mini->refresh_cmd = NULL; | ||
539 | ac = GNUNET_YES; | ||
540 | } | ||
541 | mini->refresh_cmd | ||
542 | = GNUNET_OS_command_run (&process_refresh_output, | ||
543 | mini, | ||
544 | MAP_TIMEOUT, | ||
545 | "upnpc", | ||
546 | "upnpc", | ||
547 | "-l", | ||
548 | NULL); | ||
549 | if (GNUNET_YES == ac) | ||
550 | mini->ac (mini->ac_cls, | ||
551 | GNUNET_SYSERR, | ||
552 | NULL, | ||
553 | 0, | ||
554 | GNUNET_NAT_ERROR_UPNPC_TIMEOUT); | ||
555 | } | ||
556 | |||
557 | |||
558 | /** | ||
559 | * Process the output from the 'upnpc -r' command. | ||
560 | * | ||
561 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
562 | * @param line line of output, NULL at the end | ||
563 | */ | ||
564 | static void | ||
565 | process_map_output (void *cls, | ||
566 | const char *line) | ||
567 | { | ||
568 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
569 | const char *ipaddr; | ||
570 | char *ipa; | ||
571 | const char *pstr; | ||
572 | unsigned int port; | ||
573 | |||
574 | if (NULL == line) | ||
575 | { | ||
576 | GNUNET_OS_command_stop (mini->map_cmd); | ||
577 | mini->map_cmd = NULL; | ||
578 | if (GNUNET_YES != mini->did_map) | ||
579 | mini->ac (mini->ac_cls, | ||
580 | GNUNET_SYSERR, | ||
581 | NULL, | ||
582 | 0, | ||
583 | GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED); | ||
584 | if (NULL == mini->refresh_task) | ||
585 | mini->refresh_task | ||
586 | = GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | ||
587 | &do_refresh, | ||
588 | mini); | ||
589 | return; | ||
590 | } | ||
591 | /* | ||
592 | * The upnpc output we're after looks like this: | ||
593 | * | ||
594 | * "external 87.123.42.204:3000 TCP is redirected to internal 192.168.2.150:3000" | ||
595 | */ | ||
596 | if ((NULL == (ipaddr = strstr (line, " "))) || | ||
597 | (NULL == (pstr = strstr (ipaddr, ":"))) || | ||
598 | (1 != SSCANF (pstr + 1, "%u", &port))) | ||
599 | { | ||
600 | return; /* skip line */ | ||
601 | } | ||
602 | ipa = GNUNET_strdup (ipaddr + 1); | ||
603 | strstr (ipa, ":")[0] = '\0'; | ||
604 | if (1 != inet_pton (AF_INET, | ||
605 | ipa, | ||
606 | &mini->current_addr.sin_addr)) | ||
607 | { | ||
608 | GNUNET_free (ipa); | ||
609 | return; /* skip line */ | ||
610 | } | ||
611 | GNUNET_free (ipa); | ||
612 | |||
613 | mini->current_addr.sin_port = htons (port); | ||
614 | mini->current_addr.sin_family = AF_INET; | ||
615 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
616 | mini->current_addr.sin_len = sizeof (struct sockaddr_in); | ||
617 | #endif | ||
618 | mini->did_map = GNUNET_YES; | ||
619 | mini->ac (mini->ac_cls, | ||
620 | GNUNET_YES, | ||
621 | (const struct sockaddr *) &mini->current_addr, | ||
622 | sizeof (mini->current_addr), | ||
623 | GNUNET_NAT_ERROR_SUCCESS); | ||
624 | } | ||
625 | |||
626 | |||
627 | /** | ||
628 | * Start mapping the given port using (mini)upnpc. This function | ||
629 | * should typically not be used directly (it is used within the | ||
630 | * general-purpose #GNUNET_NAT_register() code). However, it can be | ||
631 | * used if specifically UPnP-based NAT traversal is to be used or | ||
632 | * tested. | ||
633 | * | ||
634 | * @param port port to map | ||
635 | * @param is_tcp #GNUNET_YES to map TCP, #GNUNET_NO for UDP | ||
636 | * @param ac function to call with mapping result | ||
637 | * @param ac_cls closure for @a ac | ||
638 | * @return NULL on error (no 'upnpc' installed) | ||
639 | */ | ||
640 | struct GNUNET_NAT_MiniHandle * | ||
641 | GNUNET_NAT_mini_map_start (uint16_t port, | ||
642 | int is_tcp, | ||
643 | GNUNET_NAT_MiniAddressCallback ac, | ||
644 | void *ac_cls) | ||
645 | { | ||
646 | struct GNUNET_NAT_MiniHandle *ret; | ||
647 | |||
648 | if (GNUNET_SYSERR == | ||
649 | GNUNET_OS_check_helper_binary ("upnpc", | ||
650 | GNUNET_NO, | ||
651 | NULL)) | ||
652 | { | ||
653 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
654 | _("`upnpc' command not found\n")); | ||
655 | ac (ac_cls, | ||
656 | GNUNET_SYSERR, | ||
657 | NULL, 0, | ||
658 | GNUNET_NAT_ERROR_UPNPC_NOT_FOUND); | ||
659 | return NULL; | ||
660 | } | ||
661 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
662 | "Running `upnpc' to install mapping\n"); | ||
663 | ret = GNUNET_new (struct GNUNET_NAT_MiniHandle); | ||
664 | ret->ac = ac; | ||
665 | ret->ac_cls = ac_cls; | ||
666 | ret->is_tcp = is_tcp; | ||
667 | ret->port = port; | ||
668 | ret->refresh_task = | ||
669 | GNUNET_SCHEDULER_add_delayed (MAP_REFRESH_FREQ, | ||
670 | &do_refresh, | ||
671 | ret); | ||
672 | run_upnpc_r (ret); | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | |||
677 | /** | ||
678 | * Process output from our 'unmap' command. | ||
679 | * | ||
680 | * @param cls the `struct GNUNET_NAT_MiniHandle` | ||
681 | * @param line line of output, NULL at the end | ||
682 | */ | ||
683 | static void | ||
684 | process_unmap_output (void *cls, | ||
685 | const char *line) | ||
686 | { | ||
687 | struct GNUNET_NAT_MiniHandle *mini = cls; | ||
688 | |||
689 | if (NULL == line) | ||
690 | { | ||
691 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
692 | "UPnP unmap done\n"); | ||
693 | GNUNET_OS_command_stop (mini->unmap_cmd); | ||
694 | mini->unmap_cmd = NULL; | ||
695 | GNUNET_free (mini); | ||
696 | return; | ||
697 | } | ||
698 | /* we don't really care about the output... */ | ||
699 | } | ||
700 | |||
701 | |||
702 | /** | ||
703 | * Remove a mapping created with (mini)upnpc. Calling | ||
704 | * this function will give 'upnpc' 1s to remove tha mapping, | ||
705 | * so while this function is non-blocking, a task will be | ||
706 | * left with the scheduler for up to 1s past this call. | ||
707 | * | ||
708 | * @param mini the handle | ||
709 | */ | ||
710 | void | ||
711 | GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini) | ||
712 | { | ||
713 | char pstr[6]; | ||
714 | |||
715 | if (NULL != mini->refresh_task) | ||
716 | { | ||
717 | GNUNET_SCHEDULER_cancel (mini->refresh_task); | ||
718 | mini->refresh_task = NULL; | ||
719 | } | ||
720 | if (NULL != mini->refresh_cmd) | ||
721 | { | ||
722 | GNUNET_OS_command_stop (mini->refresh_cmd); | ||
723 | mini->refresh_cmd = NULL; | ||
724 | } | ||
725 | if (NULL != mini->map_cmd) | ||
726 | { | ||
727 | GNUNET_OS_command_stop (mini->map_cmd); | ||
728 | mini->map_cmd = NULL; | ||
729 | } | ||
730 | if (GNUNET_NO == mini->did_map) | ||
731 | { | ||
732 | GNUNET_free (mini); | ||
733 | return; | ||
734 | } | ||
735 | mini->ac (mini->ac_cls, | ||
736 | GNUNET_NO, | ||
737 | (const struct sockaddr *) &mini->current_addr, | ||
738 | sizeof (mini->current_addr), | ||
739 | GNUNET_NAT_ERROR_SUCCESS); | ||
740 | /* Note: oddly enough, deletion uses the external port whereas | ||
741 | * addition uses the internal port; this rarely matters since they | ||
742 | * often are the same, but it might... */ | ||
743 | GNUNET_snprintf (pstr, | ||
744 | sizeof (pstr), | ||
745 | "%u", | ||
746 | (unsigned int) ntohs (mini->current_addr.sin_port)); | ||
747 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
748 | "Unmapping port %u with UPnP\n", | ||
749 | ntohs (mini->current_addr.sin_port)); | ||
750 | mini->unmap_cmd | ||
751 | = GNUNET_OS_command_run (&process_unmap_output, | ||
752 | mini, | ||
753 | UNMAP_TIMEOUT, | ||
754 | "upnpc", | ||
755 | "upnpc", | ||
756 | "-d", | ||
757 | pstr, | ||
758 | mini->is_tcp ? "tcp" : "udp", | ||
759 | NULL); | ||
760 | } | ||
761 | |||
762 | |||
763 | /* end of gnunet-service-nat_mini.c */ | ||
diff --git a/src/nat/gnunet-service-nat_mini.h b/src/nat/gnunet-service-nat_mini.h new file mode 100644 index 000000000..2c0dd3445 --- /dev/null +++ b/src/nat/gnunet-service-nat_mini.h | |||
@@ -0,0 +1,127 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014, 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/gnunet-service-nat_mini.c | ||
23 | * @brief functions for interaction with miniupnp; tested with miniupnpc 1.5 | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_NAT_MINI_H | ||
27 | #define GNUNET_SERVICE_NAT_MINI_H | ||
28 | |||
29 | |||
30 | /** | ||
31 | * Signature of a callback that is given an IP address. | ||
32 | * | ||
33 | * @param cls closure | ||
34 | * @param addr the address, NULL on errors | ||
35 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
36 | */ | ||
37 | typedef void | ||
38 | (*GNUNET_NAT_IPCallback) (void *cls, | ||
39 | const struct in_addr *addr, | ||
40 | enum GNUNET_NAT_StatusCode result); | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Opaque handle to cancel #GNUNET_NAT_mini_get_external_ipv4() operation. | ||
45 | */ | ||
46 | struct GNUNET_NAT_ExternalHandle; | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Try to get the external IPv4 address of this peer. | ||
51 | * | ||
52 | * @param cb function to call with result | ||
53 | * @param cb_cls closure for @a cb | ||
54 | * @return handle for cancellation (can only be used until @a cb is called), NULL on error | ||
55 | */ | ||
56 | struct GNUNET_NAT_ExternalHandle * | ||
57 | GNUNET_NAT_mini_get_external_ipv4_ (GNUNET_NAT_IPCallback cb, | ||
58 | void *cb_cls); | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Cancel operation. | ||
63 | * | ||
64 | * @param eh operation to cancel | ||
65 | */ | ||
66 | void | ||
67 | GNUNET_NAT_mini_get_external_ipv4_cancel_ (struct GNUNET_NAT_ExternalHandle *eh); | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Handle to a mapping created with upnpc. | ||
72 | */ | ||
73 | struct GNUNET_NAT_MiniHandle; | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Signature of the callback passed to #GNUNET_NAT_register() for | ||
78 | * a function to call whenever our set of 'valid' addresses changes. | ||
79 | * | ||
80 | * @param cls closure | ||
81 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
82 | * the previous (now invalid) one, #GNUNET_SYSERR indicates an error | ||
83 | * @param addr either the previous or the new public IP address | ||
84 | * @param addrlen actual length of the @a addr | ||
85 | * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code | ||
86 | */ | ||
87 | typedef void | ||
88 | (*GNUNET_NAT_MiniAddressCallback) (void *cls, | ||
89 | int add_remove, | ||
90 | const struct sockaddr *addr, | ||
91 | socklen_t addrlen, | ||
92 | enum GNUNET_NAT_StatusCode result); | ||
93 | |||
94 | |||
95 | /** | ||
96 | * Start mapping the given port using (mini)upnpc. This function | ||
97 | * should typically not be used directly (it is used within the | ||
98 | * general-purpose #GNUNET_NAT_register() code). However, it can be | ||
99 | * used if specifically UPnP-based NAT traversal is to be used or | ||
100 | * tested. | ||
101 | * | ||
102 | * @param port port to map | ||
103 | * @param is_tcp #GNUNET_YES to map TCP, #GNUNET_NO for UDP | ||
104 | * @param ac function to call with mapping result | ||
105 | * @param ac_cls closure for @a ac | ||
106 | * @return NULL on error | ||
107 | */ | ||
108 | struct GNUNET_NAT_MiniHandle * | ||
109 | GNUNET_NAT_mini_map_start (uint16_t port, | ||
110 | int is_tcp, | ||
111 | GNUNET_NAT_MiniAddressCallback ac, | ||
112 | void *ac_cls); | ||
113 | |||
114 | |||
115 | /** | ||
116 | * Remove a mapping created with (mini)upnpc. Calling | ||
117 | * this function will give 'upnpc' 1s to remove the mapping, | ||
118 | * so while this function is non-blocking, a task will be | ||
119 | * left with the scheduler for up to 1s past this call. | ||
120 | * | ||
121 | * @param mini the handle | ||
122 | */ | ||
123 | void | ||
124 | GNUNET_NAT_mini_map_stop (struct GNUNET_NAT_MiniHandle *mini); | ||
125 | |||
126 | |||
127 | #endif | ||
diff --git a/src/nat/nat.h b/src/nat/nat.h index 6df72c0ab..3356b19ce 100644 --- a/src/nat/nat.h +++ b/src/nat/nat.h | |||
@@ -78,7 +78,7 @@ enum GNUNET_NAT_RegisterFlags | |||
78 | 78 | ||
79 | /** | 79 | /** |
80 | * This client wants to be informed about changes to our | 80 | * This client wants to be informed about changes to our |
81 | * external addresses. | 81 | * applicable addresses. |
82 | */ | 82 | */ |
83 | GNUNET_NAT_RF_ADDRESSES = 1, | 83 | GNUNET_NAT_RF_ADDRESSES = 1, |
84 | 84 | ||
diff --git a/src/nat/nat_api.c b/src/nat/nat_api.c index 58ed3e675..481bc6fde 100644 --- a/src/nat/nat_api.c +++ b/src/nat/nat_api.c | |||
@@ -49,6 +49,11 @@ struct AddrEntry | |||
49 | struct AddrEntry *prev; | 49 | struct AddrEntry *prev; |
50 | 50 | ||
51 | /** | 51 | /** |
52 | * Address class of the address. | ||
53 | */ | ||
54 | enum GNUNET_NAT_AddressClass ac; | ||
55 | |||
56 | /** | ||
52 | * Number of bytes that follow. | 57 | * Number of bytes that follow. |
53 | */ | 58 | */ |
54 | socklen_t addrlen; | 59 | socklen_t addrlen; |
@@ -130,11 +135,25 @@ do_connect (void *cls); | |||
130 | static void | 135 | static void |
131 | reconnect (struct GNUNET_NAT_Handle *nh) | 136 | reconnect (struct GNUNET_NAT_Handle *nh) |
132 | { | 137 | { |
138 | struct AddrEntry *ae; | ||
139 | |||
133 | if (NULL != nh->mq) | 140 | if (NULL != nh->mq) |
134 | { | 141 | { |
135 | GNUNET_MQ_destroy (nh->mq); | 142 | GNUNET_MQ_destroy (nh->mq); |
136 | nh->mq = NULL; | 143 | nh->mq = NULL; |
137 | } | 144 | } |
145 | while (NULL != (ae = nh->ae_head)) | ||
146 | { | ||
147 | GNUNET_CONTAINER_DLL_remove (nh->ae_head, | ||
148 | nh->ae_tail, | ||
149 | ae); | ||
150 | nh->address_callback (nh->callback_cls, | ||
151 | GNUNET_NO, | ||
152 | ae->ac, | ||
153 | (const struct sockaddr *) &ae[1], | ||
154 | ae->addrlen); | ||
155 | GNUNET_free (ae); | ||
156 | } | ||
138 | nh->reconnect_delay | 157 | nh->reconnect_delay |
139 | = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay); | 158 | = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay); |
140 | nh->reconnect_task | 159 | nh->reconnect_task |
@@ -260,6 +279,7 @@ handle_address_change_notification (void *cls, | |||
260 | if (GNUNET_YES == ntohl (acn->add_remove)) | 279 | if (GNUNET_YES == ntohl (acn->add_remove)) |
261 | { | 280 | { |
262 | ae = GNUNET_malloc (sizeof (*ae) + alen); | 281 | ae = GNUNET_malloc (sizeof (*ae) + alen); |
282 | ae->ac = ac; | ||
263 | ae->addrlen = alen; | 283 | ae->addrlen = alen; |
264 | GNUNET_memcpy (&ae[1], | 284 | GNUNET_memcpy (&ae[1], |
265 | sa, | 285 | sa, |
@@ -331,6 +351,7 @@ do_connect (void *cls) | |||
331 | nh), | 351 | nh), |
332 | GNUNET_MQ_handler_end () | 352 | GNUNET_MQ_handler_end () |
333 | }; | 353 | }; |
354 | struct GNUNET_MQ_Envelope *env; | ||
334 | 355 | ||
335 | nh->reconnect_task = NULL; | 356 | nh->reconnect_task = NULL; |
336 | nh->mq = GNUNET_CLIENT_connecT (nh->cfg, | 357 | nh->mq = GNUNET_CLIENT_connecT (nh->cfg, |
@@ -339,7 +360,13 @@ do_connect (void *cls) | |||
339 | &mq_error_handler, | 360 | &mq_error_handler, |
340 | nh); | 361 | nh); |
341 | if (NULL == nh->mq) | 362 | if (NULL == nh->mq) |
363 | { | ||
342 | reconnect (nh); | 364 | reconnect (nh); |
365 | return; | ||
366 | } | ||
367 | env = GNUNET_MQ_msg_copy (nh->reg); | ||
368 | GNUNET_MQ_send (nh->mq, | ||
369 | env); | ||
343 | } | 370 | } |
344 | 371 | ||
345 | 372 | ||
diff --git a/src/nat/nat_api_stun.c b/src/nat/nat_api_stun.c index 8f5a5f8f6..7f2ef4eaf 100644 --- a/src/nat/nat_api_stun.c +++ b/src/nat/nat_api_stun.c | |||
@@ -199,9 +199,7 @@ stun_dns_callback (void *cls, | |||
199 | 199 | ||
200 | /** | 200 | /** |
201 | * Make Generic STUN request. Sends a generic stun request to the | 201 | * Make Generic STUN request. Sends a generic stun request to the |
202 | * server specified using the specified socket, possibly waiting for | 202 | * server specified using the specified socket. |
203 | * a reply and filling the 'reply' field with the externally visible | ||
204 | * address. | ||
205 | * | 203 | * |
206 | * @param server the address of the stun server | 204 | * @param server the address of the stun server |
207 | * @param port port of the stun server, in host byte order | 205 | * @param port port of the stun server, in host byte order |
diff --git a/src/nat/nat_stun.h b/src/nat/nat_stun.h index 4c6c178fb..3e4228875 100644 --- a/src/nat/nat_stun.h +++ b/src/nat/nat_stun.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2009, 2015 GNUnet e.V. | 3 | Copyright (C) 2009, 2015, 2016 GNUnet e.V. |
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 |
@@ -135,23 +135,24 @@ enum StunAttributes { | |||
135 | * @param msg the received message | 135 | * @param msg the received message |
136 | * @return the converted StunClass | 136 | * @return the converted StunClass |
137 | */ | 137 | */ |
138 | static int | 138 | static enum StunClasses |
139 | decode_class(int msg) | 139 | decode_class (int msg) |
140 | { | 140 | { |
141 | /* Sorry for the magic, but this maps the class according to rfc5245 */ | 141 | /* Sorry for the magic, but this maps the class according to rfc5245 */ |
142 | return ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); | 142 | return (enum StunClasses) ((msg & 0x0010) >> 4) | ((msg & 0x0100) >> 7); |
143 | } | 143 | } |
144 | 144 | ||
145 | |||
145 | /** | 146 | /** |
146 | * Convert a message to a StunMethod | 147 | * Convert a message to a StunMethod |
147 | * | 148 | * |
148 | * @param msg the received message | 149 | * @param msg the received message |
149 | * @return the converted StunMethod | 150 | * @return the converted StunMethod |
150 | */ | 151 | */ |
151 | static int | 152 | static enum StunMethods |
152 | decode_method(int msg) | 153 | decode_method (int msg) |
153 | { | 154 | { |
154 | return (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); | 155 | return (enum StunMethods) (msg & 0x000f) | ((msg & 0x00e0) >> 1) | ((msg & 0x3e00) >> 2); |
155 | } | 156 | } |
156 | 157 | ||
157 | 158 | ||
@@ -161,6 +162,7 @@ decode_method(int msg) | |||
161 | * @param msg | 162 | * @param msg |
162 | * @return string with the message class and method | 163 | * @return string with the message class and method |
163 | */ | 164 | */ |
165 | GNUNET_UNUSED | ||
164 | static const char * | 166 | static const char * |
165 | stun_msg2str (int msg) | 167 | stun_msg2str (int msg) |
166 | { | 168 | { |
@@ -172,14 +174,14 @@ stun_msg2str (int msg) | |||
172 | { STUN_INDICATION, "Indication" }, | 174 | { STUN_INDICATION, "Indication" }, |
173 | { STUN_RESPONSE, "Response" }, | 175 | { STUN_RESPONSE, "Response" }, |
174 | { STUN_ERROR_RESPONSE, "Error Response" }, | 176 | { STUN_ERROR_RESPONSE, "Error Response" }, |
175 | { 0, NULL } | 177 | { INVALID_CLASS, NULL } |
176 | }; | 178 | }; |
177 | static const struct { | 179 | static const struct { |
178 | enum StunMethods value; | 180 | enum StunMethods value; |
179 | const char *name; | 181 | const char *name; |
180 | } methods[] = { | 182 | } methods[] = { |
181 | { STUN_BINDING, "Binding" }, | 183 | { STUN_BINDING, "Binding" }, |
182 | { 0, NULL } | 184 | { INVALID_METHOD, NULL } |
183 | }; | 185 | }; |
184 | static char result[64]; | 186 | static char result[64]; |
185 | const char *msg_class = NULL; | 187 | const char *msg_class = NULL; |
@@ -215,6 +217,7 @@ stun_msg2str (int msg) | |||
215 | * @param msg with a attribute type | 217 | * @param msg with a attribute type |
216 | * @return string with the attribute name | 218 | * @return string with the attribute name |
217 | */ | 219 | */ |
220 | GNUNET_UNUSED | ||
218 | static const char * | 221 | static const char * |
219 | stun_attr2str (enum StunAttributes msg) | 222 | stun_attr2str (enum StunAttributes msg) |
220 | { | 223 | { |
diff --git a/src/util/util.conf b/src/util/util.conf index 6b9c52d00..ecc94ead0 100644 --- a/src/util/util.conf +++ b/src/util/util.conf | |||
@@ -48,8 +48,18 @@ GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-use | |||
48 | 48 | ||
49 | 49 | ||
50 | [PEER] | 50 | [PEER] |
51 | # Where do we store our private key? | ||
51 | PRIVATE_KEY = $GNUNET_DATA_HOME/private_key.ecc | 52 | PRIVATE_KEY = $GNUNET_DATA_HOME/private_key.ecc |
52 | 53 | ||
54 | # What kind of system are we on? Choices are | ||
55 | # INFRASTRUCTURE (always-on, grid, data center) | ||
56 | # DESKTOP (sometimes-on, grid, office) | ||
57 | # NOTEBOOK (sometimes-on, mobile, often limited network, | ||
58 | # if on-battery than large battery) | ||
59 | # MOBILE (sometimes-on, mobile, always limited network, | ||
60 | # always battery limited) | ||
61 | # UNKNOWN (not configured/specified/known) | ||
62 | SYSTEM_TYPE = UNKNOWN | ||
53 | 63 | ||
54 | [TESTING] | 64 | [TESTING] |
55 | SPEEDUP_INTERVAL = 0 ms | 65 | SPEEDUP_INTERVAL = 0 ms |