diff options
Diffstat (limited to 'src/nat/nat.c')
-rw-r--r-- | src/nat/nat.c | 2054 |
1 files changed, 0 insertions, 2054 deletions
diff --git a/src/nat/nat.c b/src/nat/nat.c deleted file mode 100644 index 08dd5dd1e..000000000 --- a/src/nat/nat.c +++ /dev/null | |||
@@ -1,2054 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file nat/nat.c | ||
23 | * @brief Library handling UPnP and NAT-PMP port forwarding and | ||
24 | * external IP address retrieval | ||
25 | * @author Milan Bouchet-Valat | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_resolver_service.h" | ||
31 | #include "gnunet_nat_lib.h" | ||
32 | #include "nat.h" | ||
33 | |||
34 | #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__) | ||
35 | |||
36 | /** | ||
37 | * How often do we scan for changes in our IP address from our local | ||
38 | * interfaces? | ||
39 | */ | ||
40 | #define IFC_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) | ||
41 | |||
42 | /** | ||
43 | * How often do we scan for changes in how our hostname resolves? | ||
44 | */ | ||
45 | #define HOSTNAME_DNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 20) | ||
46 | |||
47 | |||
48 | /** | ||
49 | * How often do we scan for changes in how our external (dyndns) hostname resolves? | ||
50 | */ | ||
51 | #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7) | ||
52 | |||
53 | /** | ||
54 | * How long until we give up trying to resolve our own hostname? | ||
55 | */ | ||
56 | #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1) | ||
57 | |||
58 | |||
59 | /** | ||
60 | * How often do we check a STUN server ? | ||
61 | */ | ||
62 | #define STUN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2) | ||
63 | |||
64 | |||
65 | /** | ||
66 | * Where did the given local address originate from? | ||
67 | * To be used for debugging as well as in the future | ||
68 | * to remove all addresses from a certain source when | ||
69 | * we reevaluate the source. | ||
70 | */ | ||
71 | enum LocalAddressSource | ||
72 | { | ||
73 | /** | ||
74 | * Address was obtained by DNS resolution of the external hostname | ||
75 | * given in the configuration (i.e. hole-punched DynDNS setup). | ||
76 | */ | ||
77 | LAL_EXTERNAL_IP, | ||
78 | |||
79 | /** | ||
80 | * Address was obtained by an external STUN server | ||
81 | */ | ||
82 | LAL_EXTERNAL_STUN_IP, | ||
83 | |||
84 | /** | ||
85 | * Address was obtained by DNS resolution of the external hostname | ||
86 | * given in the configuration (i.e. hole-punched DynDNS setup) | ||
87 | * during the previous iteration (see #3213). | ||
88 | */ | ||
89 | LAL_EXTERNAL_IP_OLD, | ||
90 | |||
91 | /** | ||
92 | * Address was obtained by looking up our own hostname in DNS. | ||
93 | */ | ||
94 | LAL_HOSTNAME_DNS, | ||
95 | |||
96 | /** | ||
97 | * Address was obtained by scanning our hosts's network interfaces | ||
98 | * and taking their address (no DNS involved). | ||
99 | */ | ||
100 | LAL_INTERFACE_ADDRESS, | ||
101 | |||
102 | /** | ||
103 | * Addresses we were explicitly bound to. | ||
104 | */ | ||
105 | LAL_BINDTO_ADDRESS, | ||
106 | |||
107 | /** | ||
108 | * Addresses from UPnP or PMP | ||
109 | */ | ||
110 | LAL_UPNP, | ||
111 | |||
112 | /** | ||
113 | * End of the list. | ||
114 | */ | ||
115 | LAL_END | ||
116 | }; | ||
117 | |||
118 | |||
119 | /** | ||
120 | * List of local addresses that we currently deem valid. Actual | ||
121 | * struct is followed by the 'struct sockaddr'. Note that the code | ||
122 | * intentionally makes no attempt to ensure that a particular address | ||
123 | * is only listed once (especially since it may come from different | ||
124 | * sources, and the source is an "internal" construct). | ||
125 | */ | ||
126 | struct LocalAddressList | ||
127 | { | ||
128 | /** | ||
129 | * This is a linked list. | ||
130 | */ | ||
131 | struct LocalAddressList *next; | ||
132 | |||
133 | /** | ||
134 | * Previous entry. | ||
135 | */ | ||
136 | struct LocalAddressList *prev; | ||
137 | |||
138 | /** | ||
139 | * Number of bytes of address that follow. | ||
140 | */ | ||
141 | socklen_t addrlen; | ||
142 | |||
143 | /** | ||
144 | * Origin of the local address. | ||
145 | */ | ||
146 | enum LocalAddressSource source; | ||
147 | }; | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Handle for miniupnp-based NAT traversal actions. | ||
152 | */ | ||
153 | struct MiniList | ||
154 | { | ||
155 | |||
156 | /** | ||
157 | * Doubly-linked list. | ||
158 | */ | ||
159 | struct MiniList *next; | ||
160 | |||
161 | /** | ||
162 | * Doubly-linked list. | ||
163 | */ | ||
164 | struct MiniList *prev; | ||
165 | |||
166 | /** | ||
167 | * Handle to mini-action. | ||
168 | */ | ||
169 | struct GNUNET_NAT_MiniHandle *mini; | ||
170 | |||
171 | /** | ||
172 | * Local port number that was mapped. | ||
173 | */ | ||
174 | uint16_t port; | ||
175 | |||
176 | }; | ||
177 | |||
178 | |||
179 | /** | ||
180 | * List of STUN servers | ||
181 | */ | ||
182 | struct StunServerList | ||
183 | { | ||
184 | |||
185 | /** | ||
186 | * Doubly-linked list. | ||
187 | */ | ||
188 | struct StunServerList *next; | ||
189 | |||
190 | /** | ||
191 | * Doubly-linked list. | ||
192 | */ | ||
193 | struct StunServerList *prev; | ||
194 | |||
195 | /** | ||
196 | * Address | ||
197 | */ | ||
198 | char * address; | ||
199 | |||
200 | /** | ||
201 | * Server Port | ||
202 | */ | ||
203 | uint16_t port; | ||
204 | |||
205 | }; | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Handle for active NAT registrations. | ||
210 | */ | ||
211 | struct GNUNET_NAT_Handle | ||
212 | { | ||
213 | |||
214 | /** | ||
215 | * Configuration to use. | ||
216 | */ | ||
217 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
218 | |||
219 | /** | ||
220 | * Function to call when we learn about a new address. | ||
221 | */ | ||
222 | GNUNET_NAT_AddressCallback address_callback; | ||
223 | |||
224 | /** | ||
225 | * Function to call when we notice another peer asking for | ||
226 | * connection reversal. | ||
227 | */ | ||
228 | GNUNET_NAT_ReversalCallback reversal_callback; | ||
229 | |||
230 | /** | ||
231 | * Closure for callbacks (@e address_callback and @e reversal_callback) | ||
232 | */ | ||
233 | void *callback_cls; | ||
234 | |||
235 | /** | ||
236 | * Handle for (DYN)DNS lookup of our external IP. | ||
237 | */ | ||
238 | struct GNUNET_RESOLVER_RequestHandle *ext_dns; | ||
239 | |||
240 | /** | ||
241 | * Handle for request of hostname resolution, non-NULL if pending. | ||
242 | */ | ||
243 | struct GNUNET_RESOLVER_RequestHandle *hostname_dns; | ||
244 | |||
245 | /** | ||
246 | * stdout pipe handle for the gnunet-helper-nat-server process | ||
247 | */ | ||
248 | struct GNUNET_DISK_PipeHandle *server_stdout; | ||
249 | |||
250 | /** | ||
251 | * stdout file handle (for reading) for the gnunet-helper-nat-server process | ||
252 | */ | ||
253 | const struct GNUNET_DISK_FileHandle *server_stdout_handle; | ||
254 | |||
255 | /** | ||
256 | * Linked list of currently valid addresses (head). | ||
257 | */ | ||
258 | struct LocalAddressList *lal_head; | ||
259 | |||
260 | /** | ||
261 | * Linked list of currently valid addresses (tail). | ||
262 | */ | ||
263 | struct LocalAddressList *lal_tail; | ||
264 | |||
265 | /** | ||
266 | * How long do we wait for restarting a crashed gnunet-helper-nat-server? | ||
267 | */ | ||
268 | struct GNUNET_TIME_Relative server_retry_delay; | ||
269 | |||
270 | /** | ||
271 | * ID of select gnunet-helper-nat-server stdout read task | ||
272 | */ | ||
273 | struct GNUNET_SCHEDULER_Task *server_read_task; | ||
274 | |||
275 | /** | ||
276 | * ID of interface IP-scan task | ||
277 | */ | ||
278 | struct GNUNET_SCHEDULER_Task *ifc_task; | ||
279 | |||
280 | /** | ||
281 | * ID of hostname DNS lookup task | ||
282 | */ | ||
283 | struct GNUNET_SCHEDULER_Task *hostname_task; | ||
284 | |||
285 | /** | ||
286 | * ID of DynDNS lookup task | ||
287 | */ | ||
288 | struct GNUNET_SCHEDULER_Task *dns_task; | ||
289 | |||
290 | /** | ||
291 | * Active STUN request, if any. | ||
292 | */ | ||
293 | struct GNUNET_NAT_STUN_Handle *stun_request; | ||
294 | |||
295 | /** | ||
296 | * How often do we scan for changes in our IP address from our local | ||
297 | * interfaces? | ||
298 | */ | ||
299 | struct GNUNET_TIME_Relative ifc_scan_frequency; | ||
300 | |||
301 | /** | ||
302 | * How often do we scan for changes in how our hostname resolves? | ||
303 | */ | ||
304 | struct GNUNET_TIME_Relative hostname_dns_frequency; | ||
305 | |||
306 | /** | ||
307 | * How often do we scan for changes in how our external (dyndns) hostname resolves? | ||
308 | */ | ||
309 | struct GNUNET_TIME_Relative dyndns_frequency; | ||
310 | |||
311 | /** | ||
312 | * The process id of the server process (if behind NAT) | ||
313 | */ | ||
314 | struct GNUNET_OS_Process *server_proc; | ||
315 | |||
316 | /** | ||
317 | * LAN address as passed by the caller (array). | ||
318 | */ | ||
319 | struct sockaddr **local_addrs; | ||
320 | |||
321 | /** | ||
322 | * Length of the @e local_addrs. | ||
323 | */ | ||
324 | socklen_t *local_addrlens; | ||
325 | |||
326 | /** | ||
327 | * List of handles for UPnP-traversal, one per local port (if | ||
328 | * not IPv6-only). | ||
329 | */ | ||
330 | struct MiniList *mini_head; | ||
331 | |||
332 | /** | ||
333 | * List of handles for UPnP-traversal, one per local port (if | ||
334 | * not IPv6-only). | ||
335 | */ | ||
336 | struct MiniList *mini_tail; | ||
337 | |||
338 | /** | ||
339 | * Number of entries in 'local_addrs' array. | ||
340 | */ | ||
341 | unsigned int num_local_addrs; | ||
342 | |||
343 | /** | ||
344 | * Our external address (according to config, UPnP may disagree...), | ||
345 | * in dotted decimal notation, IPv4-only. Or NULL if not known. | ||
346 | */ | ||
347 | char *external_address; | ||
348 | |||
349 | /** | ||
350 | * Presumably our internal address (according to config) | ||
351 | */ | ||
352 | char *internal_address; | ||
353 | |||
354 | /** | ||
355 | * Is this transport configured to be behind a NAT? | ||
356 | */ | ||
357 | int behind_nat; | ||
358 | |||
359 | /** | ||
360 | * Has the NAT been punched? (according to config) | ||
361 | */ | ||
362 | int nat_punched; | ||
363 | |||
364 | /** | ||
365 | * Is this transport configured to allow connections to NAT'd peers? | ||
366 | */ | ||
367 | int enable_nat_client; | ||
368 | |||
369 | /** | ||
370 | * Should we run the gnunet-helper-nat-server? | ||
371 | */ | ||
372 | int enable_nat_server; | ||
373 | |||
374 | /** | ||
375 | * Are we allowed to try UPnP/PMP for NAT traversal? | ||
376 | */ | ||
377 | int enable_upnp; | ||
378 | |||
379 | /** | ||
380 | * Should we use local addresses (loopback)? (according to config) | ||
381 | */ | ||
382 | int use_localaddresses; | ||
383 | |||
384 | /** | ||
385 | * Should we return local addresses to clients | ||
386 | */ | ||
387 | int return_localaddress; | ||
388 | |||
389 | /** | ||
390 | * Should we do a DNS lookup of our hostname to find out our own IP? | ||
391 | */ | ||
392 | int use_hostname; | ||
393 | |||
394 | /** | ||
395 | * Is using IPv6 disabled? | ||
396 | */ | ||
397 | int disable_ipv6; | ||
398 | |||
399 | /** | ||
400 | * Is this TCP or UDP? | ||
401 | */ | ||
402 | int is_tcp; | ||
403 | |||
404 | /** | ||
405 | * Port we advertise to the outside. | ||
406 | */ | ||
407 | uint16_t adv_port; | ||
408 | |||
409 | /** | ||
410 | * Should we use STUN ? | ||
411 | */ | ||
412 | int use_stun; | ||
413 | |||
414 | /** | ||
415 | * How often should we check STUN ? | ||
416 | */ | ||
417 | struct GNUNET_TIME_Relative stun_frequency; | ||
418 | |||
419 | /** | ||
420 | * STUN socket | ||
421 | */ | ||
422 | struct GNUNET_NETWORK_Handle* socket; | ||
423 | |||
424 | /* | ||
425 | * Am I waiting for a STUN response ? | ||
426 | */ | ||
427 | int waiting_stun; | ||
428 | |||
429 | /** | ||
430 | * STUN request task | ||
431 | */ | ||
432 | struct GNUNET_SCHEDULER_Task *stun_task; | ||
433 | |||
434 | /** | ||
435 | * Head of List of STUN servers | ||
436 | */ | ||
437 | struct StunServerList *stun_servers_head; | ||
438 | |||
439 | /** | ||
440 | * Tail of List of STUN servers | ||
441 | */ | ||
442 | struct StunServerList *stun_servers_tail; | ||
443 | |||
444 | /** | ||
445 | * Actual STUN Server | ||
446 | */ | ||
447 | struct StunServerList *actual_stun_server; | ||
448 | |||
449 | }; | ||
450 | |||
451 | |||
452 | /** | ||
453 | * Try to start the gnunet-helper-nat-server (if it is not | ||
454 | * already running). | ||
455 | * | ||
456 | * @param h handle to NAT | ||
457 | */ | ||
458 | static void | ||
459 | start_gnunet_nat_server (struct GNUNET_NAT_Handle *h); | ||
460 | |||
461 | |||
462 | /** | ||
463 | * Remove all addresses from the list of 'local' addresses | ||
464 | * that originated from the given source. | ||
465 | * | ||
466 | * @param h handle to NAT | ||
467 | * @param src source that identifies addresses to remove | ||
468 | */ | ||
469 | static void | ||
470 | remove_from_address_list_by_source (struct GNUNET_NAT_Handle *h, | ||
471 | enum LocalAddressSource src) | ||
472 | { | ||
473 | struct LocalAddressList *pos; | ||
474 | struct LocalAddressList *next; | ||
475 | |||
476 | next = h->lal_head; | ||
477 | while (NULL != (pos = next)) | ||
478 | { | ||
479 | next = pos->next; | ||
480 | if (pos->source != src) | ||
481 | continue; | ||
482 | GNUNET_CONTAINER_DLL_remove (h->lal_head, | ||
483 | h->lal_tail, | ||
484 | pos); | ||
485 | if (NULL != h->address_callback) | ||
486 | h->address_callback (h->callback_cls, | ||
487 | GNUNET_NO, | ||
488 | (const struct sockaddr *) &pos[1], | ||
489 | pos->addrlen); | ||
490 | GNUNET_free (pos); | ||
491 | } | ||
492 | } | ||
493 | |||
494 | |||
495 | /** | ||
496 | * Add the given address to the list of 'local' addresses, thereby | ||
497 | * making it a 'legal' address for this peer to have. | ||
498 | * | ||
499 | * @param h handle to NAT | ||
500 | * @param src where did the local address originate from? | ||
501 | * @param arg the address, some `struct sockaddr` | ||
502 | * @param arg_size number of bytes in @a arg | ||
503 | */ | ||
504 | static void | ||
505 | add_to_address_list_as_is (struct GNUNET_NAT_Handle *h, | ||
506 | enum LocalAddressSource src, | ||
507 | const struct sockaddr *arg, | ||
508 | socklen_t arg_size) | ||
509 | { | ||
510 | struct LocalAddressList *lal; | ||
511 | |||
512 | lal = GNUNET_malloc (sizeof (struct LocalAddressList) + arg_size); | ||
513 | GNUNET_memcpy (&lal[1], arg, arg_size); | ||
514 | lal->addrlen = arg_size; | ||
515 | lal->source = src; | ||
516 | GNUNET_CONTAINER_DLL_insert (h->lal_head, | ||
517 | h->lal_tail, | ||
518 | lal); | ||
519 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
520 | "Adding address `%s' from source %d\n", | ||
521 | GNUNET_a2s (arg, arg_size), | ||
522 | src); | ||
523 | if (NULL != h->address_callback) | ||
524 | h->address_callback (h->callback_cls, | ||
525 | GNUNET_YES, | ||
526 | arg, | ||
527 | arg_size); | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Add the given address to the list of 'local' addresses, thereby | ||
533 | * making it a 'legal' address for this peer to have. Set the | ||
534 | * port number in the process to the advertised port and possibly | ||
535 | * also to zero (if we have the gnunet-helper-nat-server). | ||
536 | * | ||
537 | * @param h handle to NAT | ||
538 | * @param src where did the local address originate from? | ||
539 | * @param arg the address, some `struct sockaddr` | ||
540 | * @param arg_size number of bytes in @a arg | ||
541 | */ | ||
542 | static void | ||
543 | add_to_address_list (struct GNUNET_NAT_Handle *h, | ||
544 | enum LocalAddressSource src, | ||
545 | const struct sockaddr *arg, | ||
546 | socklen_t arg_size) | ||
547 | { | ||
548 | struct sockaddr_in s4; | ||
549 | const struct sockaddr_in *in4; | ||
550 | struct sockaddr_in6 s6; | ||
551 | const struct sockaddr_in6 *in6; | ||
552 | |||
553 | if (arg_size == sizeof (struct sockaddr_in)) | ||
554 | { | ||
555 | in4 = (const struct sockaddr_in *) arg; | ||
556 | s4 = *in4; | ||
557 | s4.sin_port = htons (h->adv_port); | ||
558 | add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, | ||
559 | sizeof (struct sockaddr_in)); | ||
560 | if (GNUNET_YES == h->enable_nat_server) | ||
561 | { | ||
562 | /* also add with PORT = 0 to indicate NAT server is enabled */ | ||
563 | s4.sin_port = htons (0); | ||
564 | add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4, | ||
565 | sizeof (struct sockaddr_in)); | ||
566 | } | ||
567 | } | ||
568 | else if (arg_size == sizeof (struct sockaddr_in6)) | ||
569 | { | ||
570 | if (GNUNET_YES != h->disable_ipv6) | ||
571 | { | ||
572 | in6 = (const struct sockaddr_in6 *) arg; | ||
573 | s6 = *in6; | ||
574 | s6.sin6_port = htons (h->adv_port); | ||
575 | add_to_address_list_as_is (h, src, (const struct sockaddr *) &s6, | ||
576 | sizeof (struct sockaddr_in6)); | ||
577 | } | ||
578 | } | ||
579 | else | ||
580 | { | ||
581 | GNUNET_assert (0); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | |||
586 | /** | ||
587 | * Add the given IP address to the list of 'local' addresses, thereby | ||
588 | * making it a 'legal' address for this peer to have. | ||
589 | * | ||
590 | * @param h handle to NAT | ||
591 | * @param src where did the local address originate from? | ||
592 | * @param addr the address, some `struct in_addr` or `struct in6_addr` | ||
593 | * @param addrlen number of bytes in addr | ||
594 | */ | ||
595 | static void | ||
596 | add_ip_to_address_list (struct GNUNET_NAT_Handle *h, | ||
597 | enum LocalAddressSource src, | ||
598 | const void *addr, | ||
599 | socklen_t addrlen) | ||
600 | { | ||
601 | struct sockaddr_in s4; | ||
602 | const struct in_addr *in4; | ||
603 | struct sockaddr_in6 s6; | ||
604 | const struct in6_addr *in6; | ||
605 | |||
606 | if (addrlen == sizeof (struct in_addr)) | ||
607 | { | ||
608 | in4 = (const struct in_addr *) addr; | ||
609 | memset (&s4, 0, sizeof (s4)); | ||
610 | s4.sin_family = AF_INET; | ||
611 | s4.sin_port = 0; | ||
612 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
613 | s4.sin_len = (u_char) sizeof (struct sockaddr_in); | ||
614 | #endif | ||
615 | s4.sin_addr = *in4; | ||
616 | add_to_address_list (h, src, (const struct sockaddr *) &s4, | ||
617 | sizeof (struct sockaddr_in)); | ||
618 | if (GNUNET_YES == h->enable_nat_server) | ||
619 | { | ||
620 | /* also add with PORT = 0 to indicate NAT server is enabled */ | ||
621 | s4.sin_port = htons (0); | ||
622 | add_to_address_list (h, src, (const struct sockaddr *) &s4, | ||
623 | sizeof (struct sockaddr_in)); | ||
624 | |||
625 | } | ||
626 | } | ||
627 | else if (addrlen == sizeof (struct in6_addr)) | ||
628 | { | ||
629 | if (GNUNET_YES != h->disable_ipv6) | ||
630 | { | ||
631 | in6 = (const struct in6_addr *) addr; | ||
632 | memset (&s6, 0, sizeof (s6)); | ||
633 | s6.sin6_family = AF_INET6; | ||
634 | s6.sin6_port = htons (h->adv_port); | ||
635 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
636 | s6.sin6_len = (u_char) sizeof (struct sockaddr_in6); | ||
637 | #endif | ||
638 | s6.sin6_addr = *in6; | ||
639 | add_to_address_list (h, src, (const struct sockaddr *) &s6, | ||
640 | sizeof (struct sockaddr_in6)); | ||
641 | } | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | GNUNET_assert (0); | ||
646 | } | ||
647 | } | ||
648 | |||
649 | |||
650 | /** | ||
651 | * Task to do DNS lookup on our external hostname to | ||
652 | * get DynDNS-IP addresses. | ||
653 | * | ||
654 | * @param cls the NAT handle | ||
655 | */ | ||
656 | static void | ||
657 | resolve_dns (void *cls); | ||
658 | |||
659 | |||
660 | /** | ||
661 | * Our (external) hostname was resolved and the configuration says that | ||
662 | * the NAT was hole-punched. | ||
663 | * | ||
664 | * @param cls the `struct GNUNET_NAT_Handle` | ||
665 | * @param addr NULL on error, otherwise result of DNS lookup | ||
666 | * @param addrlen number of bytes in @a addr | ||
667 | */ | ||
668 | static void | ||
669 | process_external_ip (void *cls, | ||
670 | const struct sockaddr *addr, | ||
671 | socklen_t addrlen) | ||
672 | { | ||
673 | struct GNUNET_NAT_Handle *h = cls; | ||
674 | struct in_addr dummy; | ||
675 | |||
676 | if (NULL == addr) | ||
677 | { | ||
678 | h->ext_dns = NULL; | ||
679 | /* Current iteration is over, remove 'old' IPs now */ | ||
680 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
681 | "Purging old IPs for external address\n"); | ||
682 | remove_from_address_list_by_source (h, | ||
683 | LAL_EXTERNAL_IP_OLD); | ||
684 | if (1 == inet_pton (AF_INET, | ||
685 | h->external_address, | ||
686 | &dummy)) | ||
687 | { | ||
688 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
689 | "Got numeric IP for external address, not repeating lookup\n"); | ||
690 | return; /* repated lookup pointless: was numeric! */ | ||
691 | } | ||
692 | h->dns_task = | ||
693 | GNUNET_SCHEDULER_add_delayed (h->dyndns_frequency, | ||
694 | &resolve_dns, h); | ||
695 | return; | ||
696 | } | ||
697 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
698 | "Got IP `%s' for external address `%s'\n", | ||
699 | GNUNET_a2s (addr, | ||
700 | addrlen), | ||
701 | h->external_address); | ||
702 | add_to_address_list (h, | ||
703 | LAL_EXTERNAL_IP, | ||
704 | addr, | ||
705 | addrlen); | ||
706 | } | ||
707 | |||
708 | |||
709 | /** | ||
710 | * Task to do a lookup on our hostname for IP addresses. | ||
711 | * | ||
712 | * @param cls the NAT handle | ||
713 | */ | ||
714 | static void | ||
715 | resolve_hostname (void *cls); | ||
716 | |||
717 | |||
718 | /** | ||
719 | * Function called by the resolver for each address obtained from DNS | ||
720 | * for our own hostname. Add the addresses to the list of our IP | ||
721 | * addresses. | ||
722 | * | ||
723 | * @param cls closure | ||
724 | * @param addr one of the addresses of the host, NULL for the last address | ||
725 | * @param addrlen length of the @a addr | ||
726 | */ | ||
727 | static void | ||
728 | process_hostname_ip (void *cls, | ||
729 | const struct sockaddr *addr, | ||
730 | socklen_t addrlen) | ||
731 | { | ||
732 | struct GNUNET_NAT_Handle *h = cls; | ||
733 | |||
734 | if (NULL == addr) | ||
735 | { | ||
736 | h->hostname_dns = NULL; | ||
737 | h->hostname_task = | ||
738 | GNUNET_SCHEDULER_add_delayed (h->hostname_dns_frequency, | ||
739 | &resolve_hostname, | ||
740 | h); | ||
741 | return; | ||
742 | } | ||
743 | add_to_address_list (h, | ||
744 | LAL_HOSTNAME_DNS, | ||
745 | addr, | ||
746 | addrlen); | ||
747 | } | ||
748 | |||
749 | |||
750 | /** | ||
751 | * Length of the interface names returned from os_network.c. | ||
752 | * (in that file, hardcoded at 11). | ||
753 | */ | ||
754 | #define IF_NAME_LEN 11 | ||
755 | |||
756 | |||
757 | /** | ||
758 | * Add the IP of our network interface to the list of | ||
759 | * our IP addresses. | ||
760 | * | ||
761 | * @param cls the `struct GNUNET_NAT_Handle` | ||
762 | * @param name name of the interface | ||
763 | * @param isDefault do we think this may be our default interface | ||
764 | * @param addr address of the interface | ||
765 | * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned) | ||
766 | * @param netmask the network mask (can be NULL for unknown or unassigned)) | ||
767 | * @param addrlen number of bytes in @a addr and @a broadcast_addr | ||
768 | * @return #GNUNET_OK to continue iterating | ||
769 | */ | ||
770 | static int | ||
771 | process_interfaces (void *cls, | ||
772 | const char *name, | ||
773 | int isDefault, | ||
774 | const struct sockaddr *addr, | ||
775 | const struct sockaddr *broadcast_addr, | ||
776 | const struct sockaddr *netmask, | ||
777 | socklen_t addrlen) | ||
778 | { | ||
779 | const static struct in6_addr any6 = IN6ADDR_ANY_INIT; | ||
780 | struct GNUNET_NAT_Handle *h = cls; | ||
781 | const struct sockaddr_in *s4; | ||
782 | const struct sockaddr_in6 *s6; | ||
783 | const void *ip; | ||
784 | char buf[INET6_ADDRSTRLEN]; | ||
785 | unsigned int i; | ||
786 | int have_any; | ||
787 | char *tun_if; | ||
788 | |||
789 | /* skip virtual interfaces created by GNUnet-vpn */ | ||
790 | if (GNUNET_OK == | ||
791 | GNUNET_CONFIGURATION_get_value_string (h->cfg, | ||
792 | "vpn", | ||
793 | "IFNAME", | ||
794 | &tun_if)) | ||
795 | { | ||
796 | if (0 == strncasecmp (name, | ||
797 | tun_if, | ||
798 | IF_NAME_LEN)) | ||
799 | { | ||
800 | GNUNET_free (tun_if); | ||
801 | return GNUNET_OK; | ||
802 | } | ||
803 | GNUNET_free (tun_if); | ||
804 | } | ||
805 | /* skip virtual interfaces created by GNUnet-dns */ | ||
806 | if (GNUNET_OK == | ||
807 | GNUNET_CONFIGURATION_get_value_string (h->cfg, | ||
808 | "dns", | ||
809 | "IFNAME", | ||
810 | &tun_if)) | ||
811 | { | ||
812 | if (0 == strncasecmp (name, | ||
813 | tun_if, | ||
814 | IF_NAME_LEN)) | ||
815 | { | ||
816 | GNUNET_free (tun_if); | ||
817 | return GNUNET_OK; | ||
818 | } | ||
819 | GNUNET_free (tun_if); | ||
820 | } | ||
821 | /* skip virtual interfaces created by GNUnet-exit */ | ||
822 | if (GNUNET_OK == | ||
823 | GNUNET_CONFIGURATION_get_value_string (h->cfg, | ||
824 | "exit", | ||
825 | "TUN_IFNAME", | ||
826 | &tun_if)) | ||
827 | { | ||
828 | if (0 == strncasecmp (name, | ||
829 | tun_if, | ||
830 | IF_NAME_LEN)) | ||
831 | { | ||
832 | GNUNET_free (tun_if); | ||
833 | return GNUNET_OK; | ||
834 | } | ||
835 | GNUNET_free (tun_if); | ||
836 | } | ||
837 | |||
838 | switch (addr->sa_family) | ||
839 | { | ||
840 | case AF_INET: | ||
841 | /* check if we're bound to the "ANY" IP address */ | ||
842 | have_any = GNUNET_NO; | ||
843 | for (i=0;i<h->num_local_addrs;i++) | ||
844 | { | ||
845 | if (h->local_addrs[i]->sa_family != AF_INET) | ||
846 | continue; | ||
847 | #ifndef INADDR_ANY | ||
848 | #define INADDR_ANY 0 | ||
849 | #endif | ||
850 | if (INADDR_ANY == ((struct sockaddr_in*) h->local_addrs[i])->sin_addr.s_addr) | ||
851 | { | ||
852 | have_any = GNUNET_YES; | ||
853 | break; | ||
854 | } | ||
855 | } | ||
856 | if (GNUNET_NO == have_any) | ||
857 | return GNUNET_OK; /* not bound to IP 0.0.0.0 but to specific IP addresses, | ||
858 | do not use those from interfaces */ | ||
859 | s4 = (struct sockaddr_in *) addr; | ||
860 | ip = &s4->sin_addr; | ||
861 | |||
862 | /* Check if address is in 127.0.0.0/8 */ | ||
863 | uint32_t address = ntohl ((uint32_t) (s4->sin_addr.s_addr)); | ||
864 | uint32_t value = (address & 0xFF000000) ^ 0x7F000000; | ||
865 | |||
866 | if ((h->return_localaddress == GNUNET_NO) && (value == 0)) | ||
867 | { | ||
868 | return GNUNET_OK; | ||
869 | } | ||
870 | if ((GNUNET_YES == h->use_localaddresses) || (value != 0)) | ||
871 | { | ||
872 | add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s4->sin_addr, | ||
873 | sizeof (struct in_addr)); | ||
874 | } | ||
875 | break; | ||
876 | case AF_INET6: | ||
877 | /* check if we're bound to the "ANY" IP address */ | ||
878 | have_any = GNUNET_NO; | ||
879 | for (i=0;i<h->num_local_addrs;i++) | ||
880 | { | ||
881 | if (h->local_addrs[i]->sa_family != AF_INET6) | ||
882 | continue; | ||
883 | if (0 == memcmp (&any6, | ||
884 | &((struct sockaddr_in6*) h->local_addrs[i])->sin6_addr, | ||
885 | sizeof (struct in6_addr))) | ||
886 | { | ||
887 | have_any = GNUNET_YES; | ||
888 | break; | ||
889 | } | ||
890 | } | ||
891 | if (GNUNET_NO == have_any) | ||
892 | return GNUNET_OK; /* not bound to "ANY" IP (::0) but to specific IP addresses, | ||
893 | do not use those from interfaces */ | ||
894 | |||
895 | s6 = (struct sockaddr_in6 *) addr; | ||
896 | if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr)) | ||
897 | { | ||
898 | /* skip link local addresses */ | ||
899 | return GNUNET_OK; | ||
900 | } | ||
901 | if ((h->return_localaddress == GNUNET_NO) && | ||
902 | (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr))) | ||
903 | { | ||
904 | return GNUNET_OK; | ||
905 | } | ||
906 | ip = &s6->sin6_addr; | ||
907 | if (GNUNET_YES == h->use_localaddresses) | ||
908 | { | ||
909 | add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s6->sin6_addr, | ||
910 | sizeof (struct in6_addr)); | ||
911 | } | ||
912 | break; | ||
913 | default: | ||
914 | GNUNET_break (0); | ||
915 | return GNUNET_OK; | ||
916 | } | ||
917 | if ( (h->internal_address == NULL) && | ||
918 | (h->server_proc == NULL) && | ||
919 | (h->server_read_task == NULL) && | ||
920 | (GNUNET_YES == isDefault) && | ||
921 | ( (addr->sa_family == AF_INET) || | ||
922 | (addr->sa_family == AF_INET6) ) ) | ||
923 | { | ||
924 | /* no internal address configured, but we found a "default" | ||
925 | * interface, try using that as our 'internal' address */ | ||
926 | h->internal_address = | ||
927 | GNUNET_strdup (inet_ntop (addr->sa_family, ip, buf, sizeof (buf))); | ||
928 | start_gnunet_nat_server (h); | ||
929 | } | ||
930 | return GNUNET_OK; | ||
931 | } | ||
932 | |||
933 | |||
934 | /** | ||
935 | * Task that restarts the gnunet-helper-nat-server process after a crash | ||
936 | * after a certain delay. | ||
937 | * | ||
938 | * @param cls the `struct GNUNET_NAT_Handle` | ||
939 | */ | ||
940 | static void | ||
941 | restart_nat_server (void *cls) | ||
942 | { | ||
943 | struct GNUNET_NAT_Handle *h = cls; | ||
944 | |||
945 | h->server_read_task = NULL; | ||
946 | start_gnunet_nat_server (h); | ||
947 | } | ||
948 | |||
949 | |||
950 | /** | ||
951 | * We have been notified that gnunet-helper-nat-server has written | ||
952 | * something to stdout. Handle the output, then reschedule this | ||
953 | * function to be called again once more is available. | ||
954 | * | ||
955 | * @param cls the NAT handle | ||
956 | */ | ||
957 | static void | ||
958 | nat_server_read (void *cls) | ||
959 | { | ||
960 | struct GNUNET_NAT_Handle *h = cls; | ||
961 | char mybuf[40]; | ||
962 | ssize_t bytes; | ||
963 | size_t i; | ||
964 | int port; | ||
965 | const char *port_start; | ||
966 | struct sockaddr_in sin_addr; | ||
967 | |||
968 | h->server_read_task = NULL; | ||
969 | memset (mybuf, 0, sizeof (mybuf)); | ||
970 | bytes = | ||
971 | GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof (mybuf)); | ||
972 | if (bytes < 1) | ||
973 | { | ||
974 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
975 | "Finished reading from server stdout with code: %d\n", | ||
976 | bytes); | ||
977 | if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG)) | ||
978 | GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill"); | ||
979 | GNUNET_OS_process_wait (h->server_proc); | ||
980 | GNUNET_OS_process_destroy (h->server_proc); | ||
981 | h->server_proc = NULL; | ||
982 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
983 | h->server_stdout = NULL; | ||
984 | h->server_stdout_handle = NULL; | ||
985 | /* now try to restart it */ | ||
986 | h->server_retry_delay = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay); | ||
987 | h->server_read_task = | ||
988 | GNUNET_SCHEDULER_add_delayed (h->server_retry_delay, | ||
989 | &restart_nat_server, h); | ||
990 | return; | ||
991 | } | ||
992 | |||
993 | port_start = NULL; | ||
994 | for (i = 0; i < sizeof (mybuf); i++) | ||
995 | { | ||
996 | if (mybuf[i] == '\n') | ||
997 | { | ||
998 | mybuf[i] = '\0'; | ||
999 | break; | ||
1000 | } | ||
1001 | if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf))) | ||
1002 | { | ||
1003 | mybuf[i] = '\0'; | ||
1004 | port_start = &mybuf[i + 1]; | ||
1005 | } | ||
1006 | } | ||
1007 | |||
1008 | /* construct socket address of sender */ | ||
1009 | memset (&sin_addr, 0, sizeof (sin_addr)); | ||
1010 | sin_addr.sin_family = AF_INET; | ||
1011 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
1012 | sin_addr.sin_len = sizeof (sin_addr); | ||
1013 | #endif | ||
1014 | if ((NULL == port_start) || (1 != SSCANF (port_start, "%d", &port)) || | ||
1015 | (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr))) | ||
1016 | { | ||
1017 | /* should we restart gnunet-helper-nat-server? */ | ||
1018 | LOG (GNUNET_ERROR_TYPE_WARNING, "nat", | ||
1019 | _("gnunet-helper-nat-server generated malformed address `%s'\n"), | ||
1020 | mybuf); | ||
1021 | h->server_read_task = | ||
1022 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1023 | h->server_stdout_handle, | ||
1024 | &nat_server_read, h); | ||
1025 | return; | ||
1026 | } | ||
1027 | sin_addr.sin_port = htons ((uint16_t) port); | ||
1028 | LOG (GNUNET_ERROR_TYPE_DEBUG, "gnunet-helper-nat-server read: %s:%d\n", mybuf, | ||
1029 | port); | ||
1030 | h->reversal_callback (h->callback_cls, (const struct sockaddr *) &sin_addr, | ||
1031 | sizeof (sin_addr)); | ||
1032 | h->server_read_task = | ||
1033 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1034 | h->server_stdout_handle, | ||
1035 | &nat_server_read, | ||
1036 | h); | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | /** | ||
1041 | * Try to start the gnunet-helper-nat-server (if it is not | ||
1042 | * already running). | ||
1043 | * | ||
1044 | * @param h handle to NAT | ||
1045 | */ | ||
1046 | static void | ||
1047 | start_gnunet_nat_server (struct GNUNET_NAT_Handle *h) | ||
1048 | { | ||
1049 | char *binary; | ||
1050 | |||
1051 | if ((h->behind_nat == GNUNET_YES) && (h->enable_nat_server == GNUNET_YES) && | ||
1052 | (h->internal_address != NULL) && | ||
1053 | (NULL != | ||
1054 | (h->server_stdout = | ||
1055 | GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES)))) | ||
1056 | { | ||
1057 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1058 | "Starting `%s' at `%s'\n", | ||
1059 | "gnunet-helper-nat-server", h->internal_address); | ||
1060 | /* Start the server process */ | ||
1061 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server"); | ||
1062 | h->server_proc = | ||
1063 | GNUNET_OS_start_process (GNUNET_NO, 0, NULL, h->server_stdout, NULL, | ||
1064 | binary, | ||
1065 | "gnunet-helper-nat-server", | ||
1066 | h->internal_address, NULL); | ||
1067 | GNUNET_free (binary); | ||
1068 | if (h->server_proc == NULL) | ||
1069 | { | ||
1070 | LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("Failed to start %s\n"), | ||
1071 | "gnunet-helper-nat-server"); | ||
1072 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
1073 | h->server_stdout = NULL; | ||
1074 | } | ||
1075 | else | ||
1076 | { | ||
1077 | /* Close the write end of the read pipe */ | ||
1078 | GNUNET_DISK_pipe_close_end (h->server_stdout, GNUNET_DISK_PIPE_END_WRITE); | ||
1079 | h->server_stdout_handle = | ||
1080 | GNUNET_DISK_pipe_handle (h->server_stdout, GNUNET_DISK_PIPE_END_READ); | ||
1081 | h->server_read_task = | ||
1082 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1083 | h->server_stdout_handle, | ||
1084 | &nat_server_read, h); | ||
1085 | } | ||
1086 | } | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | /** | ||
1091 | * Task to scan the local network interfaces for IP addresses. | ||
1092 | * | ||
1093 | * @param cls the NAT handle | ||
1094 | */ | ||
1095 | static void | ||
1096 | list_interfaces (void *cls) | ||
1097 | { | ||
1098 | struct GNUNET_NAT_Handle *h = cls; | ||
1099 | |||
1100 | h->ifc_task = NULL; | ||
1101 | remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS); | ||
1102 | GNUNET_OS_network_interfaces_list (&process_interfaces, h); | ||
1103 | h->ifc_task = | ||
1104 | GNUNET_SCHEDULER_add_delayed (h->ifc_scan_frequency, | ||
1105 | &list_interfaces, h); | ||
1106 | } | ||
1107 | |||
1108 | |||
1109 | /** | ||
1110 | * Callback with the result from the STUN request. | ||
1111 | * | ||
1112 | * @param cls the NAT handle | ||
1113 | * @param result the status | ||
1114 | */ | ||
1115 | static void | ||
1116 | stun_request_callback (void *cls, | ||
1117 | enum GNUNET_NAT_StatusCode result) | ||
1118 | { | ||
1119 | struct GNUNET_NAT_Handle *h = cls; | ||
1120 | |||
1121 | h->stun_request = NULL; | ||
1122 | switch (result) | ||
1123 | { | ||
1124 | case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR: | ||
1125 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1126 | "Failed to transmit STUN request\n"); | ||
1127 | break; | ||
1128 | case GNUNET_NAT_ERROR_NOT_ONLINE: | ||
1129 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1130 | "Failed to resolve STUN server (are we online?)\n"); | ||
1131 | break; | ||
1132 | case GNUNET_NAT_ERROR_SUCCESS: | ||
1133 | /* all good, STUN request active */ | ||
1134 | h->waiting_stun = GNUNET_YES; | ||
1135 | break; | ||
1136 | default: | ||
1137 | /* unexpected error code for STUN */ | ||
1138 | GNUNET_break (0); | ||
1139 | } | ||
1140 | } | ||
1141 | |||
1142 | |||
1143 | /** | ||
1144 | * CHECK if is a valid STUN packet sending to GNUNET_NAT_stun_handle_packet(). | ||
1145 | * It also check if it can handle the packet based on the NAT handler. | ||
1146 | * You don't need to call anything else to check if the packet is valid, | ||
1147 | * | ||
1148 | * @param cls the NAT handle | ||
1149 | * @param data packet | ||
1150 | * @param len packet length | ||
1151 | * @return #GNUNET_NO if it can't decode, #GNUNET_YES if is a packet | ||
1152 | */ | ||
1153 | int | ||
1154 | GNUNET_NAT_is_valid_stun_packet (void *cls, | ||
1155 | const void *data, | ||
1156 | size_t len) | ||
1157 | { | ||
1158 | struct GNUNET_NAT_Handle *h = cls; | ||
1159 | struct sockaddr_in answer; | ||
1160 | |||
1161 | /* We are not expecting a STUN message */ | ||
1162 | if (GNUNET_YES != h->waiting_stun) | ||
1163 | return GNUNET_NO; | ||
1164 | |||
1165 | /* We dont have STUN installed */ | ||
1166 | if (! h->use_stun) | ||
1167 | return GNUNET_NO; | ||
1168 | |||
1169 | /* Empty the answer structure */ | ||
1170 | memset (&answer, | ||
1171 | 0, | ||
1172 | sizeof(struct sockaddr_in)); | ||
1173 | |||
1174 | /* Lets handle the packet*/ | ||
1175 | if (GNUNET_NO == | ||
1176 | GNUNET_NAT_stun_handle_packet (data, | ||
1177 | len, | ||
1178 | &answer)) | ||
1179 | return GNUNET_NO; | ||
1180 | |||
1181 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1182 | "STUN server returned %s:%d\n", | ||
1183 | inet_ntoa (answer.sin_addr), | ||
1184 | ntohs (answer.sin_port)); | ||
1185 | /* Remove old IPs from previous STUN calls */ | ||
1186 | remove_from_address_list_by_source (h, | ||
1187 | LAL_EXTERNAL_STUN_IP); | ||
1188 | /* Add new IP from STUN packet */ | ||
1189 | add_to_address_list (h, | ||
1190 | LAL_EXTERNAL_STUN_IP, | ||
1191 | (const struct sockaddr *) &answer, | ||
1192 | sizeof (struct sockaddr_in)); | ||
1193 | h->waiting_stun = GNUNET_NO; | ||
1194 | return GNUNET_YES; | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | /** | ||
1199 | * Task to do a STUN request | ||
1200 | * | ||
1201 | * @param cls the NAT handle | ||
1202 | */ | ||
1203 | static void | ||
1204 | process_stun (void *cls) | ||
1205 | { | ||
1206 | struct GNUNET_NAT_Handle *h = cls; | ||
1207 | struct StunServerList *elem = h->actual_stun_server; | ||
1208 | |||
1209 | h->stun_task = NULL; | ||
1210 | /* Make the request */ | ||
1211 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1212 | "I will request the stun server %s:%i\n", | ||
1213 | elem->address, | ||
1214 | elem->port); | ||
1215 | if (NULL != h->stun_request) | ||
1216 | { | ||
1217 | GNUNET_NAT_stun_make_request_cancel (h->stun_request); | ||
1218 | h->stun_request = NULL; | ||
1219 | } | ||
1220 | h->waiting_stun = GNUNET_NO; | ||
1221 | h->stun_request | ||
1222 | = GNUNET_NAT_stun_make_request (elem->address, | ||
1223 | elem->port, | ||
1224 | h->socket, | ||
1225 | &stun_request_callback, | ||
1226 | h); | ||
1227 | if (NULL == h->stun_request) | ||
1228 | { | ||
1229 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1230 | "STUN request to %s:%i failed\n", | ||
1231 | elem->address, | ||
1232 | elem->port); | ||
1233 | } | ||
1234 | h->stun_task = | ||
1235 | GNUNET_SCHEDULER_add_delayed (h->stun_frequency, | ||
1236 | &process_stun, | ||
1237 | h); | ||
1238 | |||
1239 | /* Set actual Server*/ | ||
1240 | if (NULL != elem->next) | ||
1241 | { | ||
1242 | h->actual_stun_server = elem->next; | ||
1243 | } | ||
1244 | else | ||
1245 | { | ||
1246 | h->actual_stun_server = h->stun_servers_head; | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | |||
1251 | /** | ||
1252 | * Task to do a lookup on our hostname for IP addresses. | ||
1253 | * | ||
1254 | * @param cls the NAT handle | ||
1255 | */ | ||
1256 | static void | ||
1257 | resolve_hostname (void *cls) | ||
1258 | { | ||
1259 | struct GNUNET_NAT_Handle *h = cls; | ||
1260 | |||
1261 | h->hostname_task = NULL; | ||
1262 | remove_from_address_list_by_source (h, LAL_HOSTNAME_DNS); | ||
1263 | GNUNET_assert (NULL == h->hostname_dns); | ||
1264 | h->hostname_dns = | ||
1265 | GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, | ||
1266 | HOSTNAME_RESOLVE_TIMEOUT, | ||
1267 | &process_hostname_ip, | ||
1268 | h); | ||
1269 | } | ||
1270 | |||
1271 | |||
1272 | /** | ||
1273 | * Task to do DNS lookup on our external hostname to | ||
1274 | * get DynDNS-IP addresses. | ||
1275 | * | ||
1276 | * @param cls the NAT handle | ||
1277 | */ | ||
1278 | static void | ||
1279 | resolve_dns (void *cls) | ||
1280 | { | ||
1281 | struct GNUNET_NAT_Handle *h = cls; | ||
1282 | struct LocalAddressList *pos; | ||
1283 | |||
1284 | h->dns_task = NULL; | ||
1285 | for (pos = h->lal_head; NULL != pos; pos = pos->next) | ||
1286 | if (pos->source == LAL_EXTERNAL_IP) | ||
1287 | pos->source = LAL_EXTERNAL_IP_OLD; | ||
1288 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1289 | "Resolving external address `%s'\n", | ||
1290 | h->external_address); | ||
1291 | GNUNET_assert (NULL == h->ext_dns); | ||
1292 | h->ext_dns = | ||
1293 | GNUNET_RESOLVER_ip_get (h->external_address, | ||
1294 | AF_INET, | ||
1295 | GNUNET_TIME_UNIT_MINUTES, | ||
1296 | &process_external_ip, | ||
1297 | h); | ||
1298 | } | ||
1299 | |||
1300 | |||
1301 | /** | ||
1302 | * Add or remove UPnP-mapped addresses. | ||
1303 | * | ||
1304 | * @param cls the `struct GNUNET_NAT_Handle` | ||
1305 | * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean | ||
1306 | * the previous (now invalid) one | ||
1307 | * @param addr either the previous or the new public IP address | ||
1308 | * @param addrlen actual lenght of @a addr | ||
1309 | * @param ret GNUNET_NAT_ERROR_SUCCESS on success, otherwise an error code | ||
1310 | */ | ||
1311 | static void | ||
1312 | upnp_add (void *cls, | ||
1313 | int add_remove, | ||
1314 | const struct sockaddr *addr, | ||
1315 | socklen_t addrlen, | ||
1316 | enum GNUNET_NAT_StatusCode ret) | ||
1317 | { | ||
1318 | struct GNUNET_NAT_Handle *h = cls; | ||
1319 | struct LocalAddressList *pos; | ||
1320 | struct LocalAddressList *next; | ||
1321 | |||
1322 | |||
1323 | if (GNUNET_NAT_ERROR_SUCCESS != ret) | ||
1324 | { | ||
1325 | /* Error while running upnp client */ | ||
1326 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1327 | _("Error while running upnp client:\n")); | ||
1328 | //FIXME: convert error code to string | ||
1329 | return; | ||
1330 | } | ||
1331 | |||
1332 | if (GNUNET_YES == add_remove) | ||
1333 | { | ||
1334 | add_to_address_list (h, | ||
1335 | LAL_UPNP, | ||
1336 | addr, | ||
1337 | addrlen); | ||
1338 | return; | ||
1339 | } | ||
1340 | else if (GNUNET_NO == add_remove) | ||
1341 | { | ||
1342 | /* remove address */ | ||
1343 | next = h->lal_head; | ||
1344 | while (NULL != (pos = next)) | ||
1345 | { | ||
1346 | next = pos->next; | ||
1347 | if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) || | ||
1348 | (0 != memcmp (&pos[1], addr, addrlen))) | ||
1349 | continue; | ||
1350 | GNUNET_CONTAINER_DLL_remove (h->lal_head, | ||
1351 | h->lal_tail, | ||
1352 | pos); | ||
1353 | if (NULL != h->address_callback) | ||
1354 | h->address_callback (h->callback_cls, | ||
1355 | GNUNET_NO, | ||
1356 | (const struct sockaddr *) &pos[1], | ||
1357 | pos->addrlen); | ||
1358 | GNUNET_free (pos); | ||
1359 | return; /* only remove once */ | ||
1360 | } | ||
1361 | /* asked to remove address that does not exist */ | ||
1362 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1363 | "Asked to remove unkown address `%s'\n", | ||
1364 | GNUNET_a2s(addr, addrlen)); | ||
1365 | GNUNET_break (0); | ||
1366 | } | ||
1367 | else | ||
1368 | { | ||
1369 | |||
1370 | GNUNET_break (0); | ||
1371 | } | ||
1372 | } | ||
1373 | |||
1374 | |||
1375 | /** | ||
1376 | * Try to add a port mapping using UPnP. | ||
1377 | * | ||
1378 | * @param h overall NAT handle | ||
1379 | * @param port port to map with UPnP | ||
1380 | */ | ||
1381 | static void | ||
1382 | add_minis (struct GNUNET_NAT_Handle *h, | ||
1383 | uint16_t port) | ||
1384 | { | ||
1385 | struct MiniList *ml; | ||
1386 | |||
1387 | ml = h->mini_head; | ||
1388 | while (NULL != ml) | ||
1389 | { | ||
1390 | if (port == ml->port) | ||
1391 | return; /* already got this port */ | ||
1392 | ml = ml->next; | ||
1393 | } | ||
1394 | |||
1395 | ml = GNUNET_new (struct MiniList); | ||
1396 | ml->port = port; | ||
1397 | ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h); | ||
1398 | |||
1399 | if (NULL == ml->mini) | ||
1400 | { | ||
1401 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1402 | _("Failed to run upnp client for port %u\n"), ml->port); | ||
1403 | GNUNET_free (ml); | ||
1404 | return; | ||
1405 | } | ||
1406 | |||
1407 | GNUNET_CONTAINER_DLL_insert (h->mini_head, | ||
1408 | h->mini_tail, | ||
1409 | ml); | ||
1410 | } | ||
1411 | |||
1412 | |||
1413 | /** | ||
1414 | * Task to add addresses from original bind to set of valid addrs. | ||
1415 | * | ||
1416 | * @param h the NAT handle | ||
1417 | */ | ||
1418 | static void | ||
1419 | add_from_bind (struct GNUNET_NAT_Handle *h) | ||
1420 | { | ||
1421 | static struct in6_addr any = IN6ADDR_ANY_INIT; | ||
1422 | |||
1423 | unsigned int i; | ||
1424 | struct sockaddr *sa; | ||
1425 | const struct sockaddr_in *v4; | ||
1426 | |||
1427 | for (i = 0; i < h->num_local_addrs; i++) | ||
1428 | { | ||
1429 | sa = h->local_addrs[i]; | ||
1430 | switch (sa->sa_family) | ||
1431 | { | ||
1432 | case AF_INET: | ||
1433 | if (sizeof (struct sockaddr_in) != h->local_addrlens[i]) | ||
1434 | { | ||
1435 | GNUNET_break (0); | ||
1436 | break; | ||
1437 | } | ||
1438 | v4 = (const struct sockaddr_in *) sa; | ||
1439 | if (0 != v4->sin_addr.s_addr) | ||
1440 | add_to_address_list (h, | ||
1441 | LAL_BINDTO_ADDRESS, sa, | ||
1442 | sizeof (struct sockaddr_in)); | ||
1443 | if (h->enable_upnp) | ||
1444 | { | ||
1445 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1446 | "Running upnp client for address `%s'\n", | ||
1447 | GNUNET_a2s (sa,sizeof (struct sockaddr_in))); | ||
1448 | add_minis (h, ntohs (v4->sin_port)); | ||
1449 | } | ||
1450 | break; | ||
1451 | case AF_INET6: | ||
1452 | if (sizeof (struct sockaddr_in6) != h->local_addrlens[i]) | ||
1453 | { | ||
1454 | GNUNET_break (0); | ||
1455 | break; | ||
1456 | } | ||
1457 | if (0 != | ||
1458 | memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr, | ||
1459 | &any, | ||
1460 | sizeof (struct in6_addr))) | ||
1461 | add_to_address_list (h, | ||
1462 | LAL_BINDTO_ADDRESS, | ||
1463 | sa, | ||
1464 | sizeof (struct sockaddr_in6)); | ||
1465 | break; | ||
1466 | default: | ||
1467 | break; | ||
1468 | } | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | |||
1473 | /** | ||
1474 | * Attempt to enable port redirection and detect public IP address contacting | ||
1475 | * UPnP or NAT-PMP routers on the local network. Use addr to specify to which | ||
1476 | * of the local host's addresses should the external port be mapped. The port | ||
1477 | * is taken from the corresponding sockaddr_in[6] field. | ||
1478 | * | ||
1479 | * @param cfg configuration to use | ||
1480 | * @param is_tcp #GNUNET_YES for TCP, #GNUNET_NO for UDP | ||
1481 | * @param adv_port advertised port (port we are either bound to or that our OS | ||
1482 | * locally performs redirection from to our bound port). | ||
1483 | * @param num_addrs number of addresses in @a addrs | ||
1484 | * @param addrs the local addresses packets should be redirected to | ||
1485 | * @param addrlens actual lengths of the addresses | ||
1486 | * @param address_callback function to call everytime the public IP address changes | ||
1487 | * @param reversal_callback function to call if someone wants connection reversal from us | ||
1488 | * @param callback_cls closure for callbacks | ||
1489 | * @param sock used socket | ||
1490 | * @return NULL on error, otherwise handle that can be used to unregister | ||
1491 | */ | ||
1492 | struct GNUNET_NAT_Handle * | ||
1493 | GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1494 | int is_tcp, | ||
1495 | uint16_t adv_port, | ||
1496 | unsigned int num_addrs, | ||
1497 | const struct sockaddr **addrs, | ||
1498 | const socklen_t *addrlens, | ||
1499 | GNUNET_NAT_AddressCallback address_callback, | ||
1500 | GNUNET_NAT_ReversalCallback reversal_callback, | ||
1501 | void *callback_cls, | ||
1502 | struct GNUNET_NETWORK_Handle *sock) | ||
1503 | { | ||
1504 | struct GNUNET_NAT_Handle *h; | ||
1505 | struct in_addr in_addr; | ||
1506 | unsigned int i; | ||
1507 | char *binary; | ||
1508 | |||
1509 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1510 | "Registered with NAT service at port %u with %u IP bound local addresses\n", | ||
1511 | (unsigned int) adv_port, num_addrs); | ||
1512 | h = GNUNET_new (struct GNUNET_NAT_Handle); | ||
1513 | h->server_retry_delay = GNUNET_TIME_UNIT_SECONDS; | ||
1514 | h->cfg = cfg; | ||
1515 | h->is_tcp = is_tcp; | ||
1516 | h->address_callback = address_callback; | ||
1517 | h->reversal_callback = reversal_callback; | ||
1518 | h->callback_cls = callback_cls; | ||
1519 | h->num_local_addrs = num_addrs; | ||
1520 | h->adv_port = adv_port; | ||
1521 | if (0 != num_addrs) | ||
1522 | { | ||
1523 | h->local_addrs = GNUNET_malloc (num_addrs * sizeof (struct sockaddr *)); | ||
1524 | h->local_addrlens = GNUNET_malloc (num_addrs * sizeof (socklen_t)); | ||
1525 | for (i = 0; i < num_addrs; i++) | ||
1526 | { | ||
1527 | GNUNET_assert (addrlens[i] > 0); | ||
1528 | GNUNET_assert (addrs[i] != NULL); | ||
1529 | h->local_addrlens[i] = addrlens[i]; | ||
1530 | h->local_addrs[i] = GNUNET_malloc (addrlens[i]); | ||
1531 | GNUNET_memcpy (h->local_addrs[i], addrs[i], addrlens[i]); | ||
1532 | } | ||
1533 | } | ||
1534 | if (GNUNET_OK == | ||
1535 | GNUNET_CONFIGURATION_have_value (cfg, "nat", "INTERNAL_ADDRESS")) | ||
1536 | { | ||
1537 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", | ||
1538 | "INTERNAL_ADDRESS", | ||
1539 | &h->internal_address); | ||
1540 | } | ||
1541 | if ((h->internal_address != NULL) && | ||
1542 | (inet_pton (AF_INET, h->internal_address, &in_addr) != 1)) | ||
1543 | { | ||
1544 | GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING, | ||
1545 | "nat", "INTERNAL_ADDRESS", | ||
1546 | _("malformed")); | ||
1547 | GNUNET_free (h->internal_address); | ||
1548 | h->internal_address = NULL; | ||
1549 | } | ||
1550 | |||
1551 | if (GNUNET_OK == | ||
1552 | GNUNET_CONFIGURATION_have_value (cfg, "nat", "EXTERNAL_ADDRESS")) | ||
1553 | { | ||
1554 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat", | ||
1555 | "EXTERNAL_ADDRESS", | ||
1556 | &h->external_address); | ||
1557 | } | ||
1558 | h->behind_nat = | ||
1559 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "BEHIND_NAT"); | ||
1560 | h->nat_punched = | ||
1561 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "PUNCHED_NAT"); | ||
1562 | h->enable_nat_client = | ||
1563 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_CLIENT"); | ||
1564 | h->enable_nat_server = | ||
1565 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_SERVER"); | ||
1566 | h->enable_upnp = | ||
1567 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_UPNP"); | ||
1568 | h->use_localaddresses = | ||
1569 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_LOCALADDR"); | ||
1570 | h->return_localaddress = | ||
1571 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", | ||
1572 | "RETURN_LOCAL_ADDRESSES"); | ||
1573 | |||
1574 | h->use_hostname = | ||
1575 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_HOSTNAME"); | ||
1576 | h->disable_ipv6 = | ||
1577 | GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "DISABLEV6"); | ||
1578 | if (GNUNET_OK != | ||
1579 | GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "DYNDNS_FREQUENCY", | ||
1580 | &h->dyndns_frequency)) | ||
1581 | h->dyndns_frequency = DYNDNS_FREQUENCY; | ||
1582 | if (GNUNET_OK != | ||
1583 | GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "IFC_SCAN_FREQUENCY", | ||
1584 | &h->ifc_scan_frequency)) | ||
1585 | h->ifc_scan_frequency = IFC_SCAN_FREQUENCY; | ||
1586 | if (GNUNET_OK != | ||
1587 | GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "HOSTNAME_DNS_FREQUENCY", | ||
1588 | &h->hostname_dns_frequency)) | ||
1589 | h->hostname_dns_frequency = HOSTNAME_DNS_FREQUENCY; | ||
1590 | |||
1591 | if (NULL == reversal_callback) | ||
1592 | h->enable_nat_server = GNUNET_NO; | ||
1593 | |||
1594 | /* Check for UPnP client, disable immediately if not available */ | ||
1595 | if ( (GNUNET_YES == h->enable_upnp) && | ||
1596 | (GNUNET_SYSERR == | ||
1597 | GNUNET_OS_check_helper_binary ("upnpc", GNUNET_NO, NULL)) ) | ||
1598 | { | ||
1599 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1600 | _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP \n")); | ||
1601 | h->enable_upnp = GNUNET_NO; | ||
1602 | } | ||
1603 | |||
1604 | /* STUN */ | ||
1605 | h->use_stun = | ||
1606 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
1607 | "nat", | ||
1608 | "USE_STUN"); | ||
1609 | |||
1610 | if (GNUNET_OK != | ||
1611 | GNUNET_CONFIGURATION_get_value_time (cfg, | ||
1612 | "nat", | ||
1613 | "STUN_FREQUENCY", | ||
1614 | &h->stun_frequency)) | ||
1615 | h->stun_frequency = STUN_FREQUENCY; | ||
1616 | |||
1617 | |||
1618 | /* Check if NAT was hole-punched */ | ||
1619 | if ((NULL != h->address_callback) && | ||
1620 | (NULL != h->external_address) && | ||
1621 | (GNUNET_YES == h->nat_punched)) | ||
1622 | { | ||
1623 | h->dns_task = GNUNET_SCHEDULER_add_now (&resolve_dns, h); | ||
1624 | h->enable_nat_server = GNUNET_NO; | ||
1625 | h->enable_upnp = GNUNET_NO; | ||
1626 | h->use_stun = GNUNET_NO; | ||
1627 | } | ||
1628 | else | ||
1629 | { | ||
1630 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1631 | "No external IP address given to add to our list of addresses\n"); | ||
1632 | } | ||
1633 | |||
1634 | /* ENABLE STUN ONLY ON UDP */ | ||
1635 | if( (! is_tcp) && | ||
1636 | (NULL != sock) && | ||
1637 | h->use_stun) | ||
1638 | { | ||
1639 | char *stun_servers; | ||
1640 | size_t urls; | ||
1641 | ssize_t pos; | ||
1642 | size_t pos_port; | ||
1643 | |||
1644 | h->socket = sock; | ||
1645 | stun_servers = NULL; | ||
1646 | /* Lets process the servers*/ | ||
1647 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, | ||
1648 | "nat", | ||
1649 | "STUN_SERVERS", | ||
1650 | &stun_servers); | ||
1651 | urls = 0; | ||
1652 | if ( (NULL != stun_servers) && | ||
1653 | (strlen (stun_servers) > 0) ) | ||
1654 | { | ||
1655 | pos_port = 0; | ||
1656 | for (pos = strlen (stun_servers) - 1; | ||
1657 | pos >= 0; | ||
1658 | pos--) | ||
1659 | { | ||
1660 | if (stun_servers[pos] == ':') | ||
1661 | { | ||
1662 | pos_port = pos + 1; | ||
1663 | stun_servers[pos] = '\0'; | ||
1664 | continue; | ||
1665 | } | ||
1666 | if ((stun_servers[pos] == ' ') || (0 == pos)) | ||
1667 | { | ||
1668 | struct StunServerList *ml; | ||
1669 | |||
1670 | /* Check if we do have a port */ | ||
1671 | if ((0 == pos_port) || (pos_port <= pos)) | ||
1672 | { | ||
1673 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1674 | "STUN server format mistake\n"); | ||
1675 | break; | ||
1676 | } | ||
1677 | urls++; | ||
1678 | ml = GNUNET_new (struct StunServerList); | ||
1679 | ml->port = atoi (&stun_servers[pos_port]); | ||
1680 | |||
1681 | /* Remove trailing space */ | ||
1682 | if (stun_servers[pos] == ' ') | ||
1683 | ml->address = GNUNET_strdup (&stun_servers[pos + 1]); | ||
1684 | else | ||
1685 | ml->address = GNUNET_strdup (&stun_servers[pos]); | ||
1686 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1687 | "Found STUN server %s:%i\n", | ||
1688 | ml->address, | ||
1689 | ml->port); | ||
1690 | GNUNET_CONTAINER_DLL_insert (h->stun_servers_head, | ||
1691 | h->stun_servers_tail, | ||
1692 | ml); | ||
1693 | stun_servers[pos] = '\0'; | ||
1694 | } | ||
1695 | } | ||
1696 | } | ||
1697 | if (0 == urls) | ||
1698 | { | ||
1699 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, | ||
1700 | "nat", | ||
1701 | "STUN_SERVERS"); | ||
1702 | } | ||
1703 | else | ||
1704 | { | ||
1705 | /* Set the actual STUN server*/ | ||
1706 | h->actual_stun_server = h->stun_servers_head; | ||
1707 | } | ||
1708 | h->stun_task = GNUNET_SCHEDULER_add_now (&process_stun, | ||
1709 | h); | ||
1710 | GNUNET_free_non_null (stun_servers); | ||
1711 | } | ||
1712 | |||
1713 | |||
1714 | /* Test for SUID binaries */ | ||
1715 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server"); | ||
1716 | if ( (GNUNET_YES == h->behind_nat) && | ||
1717 | (GNUNET_YES == h->enable_nat_server) && | ||
1718 | (GNUNET_YES != | ||
1719 | GNUNET_OS_check_helper_binary (binary, | ||
1720 | GNUNET_YES, | ||
1721 | "-d 127.0.0.1" ))) | ||
1722 | { | ||
1723 | // use localhost as source for that one udp-port, ok for testing | ||
1724 | h->enable_nat_server = GNUNET_NO; | ||
1725 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1726 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
1727 | "gnunet-helper-nat-server"); | ||
1728 | } | ||
1729 | GNUNET_free (binary); | ||
1730 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client"); | ||
1731 | if ((GNUNET_YES == h->enable_nat_client) && | ||
1732 | (GNUNET_YES != | ||
1733 | GNUNET_OS_check_helper_binary (binary, | ||
1734 | GNUNET_YES, | ||
1735 | "-d 127.0.0.1 127.0.0.2 42"))) /* none of these parameters are actually used in privilege testing mode */ | ||
1736 | { | ||
1737 | h->enable_nat_client = GNUNET_NO; | ||
1738 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1739 | _("Configuration requires `%s', but binary is not installed properly (SUID bit not set). Option disabled.\n"), | ||
1740 | "gnunet-helper-nat-client"); | ||
1741 | } | ||
1742 | GNUNET_free (binary); | ||
1743 | start_gnunet_nat_server (h); | ||
1744 | |||
1745 | /* FIXME: add support for UPnP, etc */ | ||
1746 | |||
1747 | if (NULL != h->address_callback) | ||
1748 | { | ||
1749 | h->ifc_task = GNUNET_SCHEDULER_add_now (&list_interfaces, | ||
1750 | h); | ||
1751 | if (GNUNET_YES == h->use_hostname) | ||
1752 | h->hostname_task = GNUNET_SCHEDULER_add_now (&resolve_hostname, | ||
1753 | h); | ||
1754 | } | ||
1755 | add_from_bind (h); | ||
1756 | |||
1757 | return h; | ||
1758 | } | ||
1759 | |||
1760 | |||
1761 | /** | ||
1762 | * Stop port redirection and public IP address detection for the given handle. | ||
1763 | * This frees the handle, after having sent the needed commands to close open ports. | ||
1764 | * | ||
1765 | * @param h the handle to stop | ||
1766 | */ | ||
1767 | void | ||
1768 | GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h) | ||
1769 | { | ||
1770 | unsigned int i; | ||
1771 | struct LocalAddressList *lal; | ||
1772 | struct MiniList *ml; | ||
1773 | struct StunServerList *ssl; | ||
1774 | |||
1775 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1776 | "NAT unregister called\n"); | ||
1777 | while (NULL != (ssl = h->stun_servers_head)) | ||
1778 | { | ||
1779 | GNUNET_CONTAINER_DLL_remove (h->stun_servers_head, | ||
1780 | h->stun_servers_tail, | ||
1781 | ssl); | ||
1782 | GNUNET_free (ssl->address); | ||
1783 | GNUNET_free (ssl); | ||
1784 | } | ||
1785 | while (NULL != (lal = h->lal_head)) | ||
1786 | { | ||
1787 | GNUNET_CONTAINER_DLL_remove (h->lal_head, | ||
1788 | h->lal_tail, | ||
1789 | lal); | ||
1790 | if (NULL != h->address_callback) | ||
1791 | h->address_callback (h->callback_cls, | ||
1792 | GNUNET_NO, | ||
1793 | (const struct sockaddr *) &lal[1], | ||
1794 | lal->addrlen); | ||
1795 | GNUNET_free (lal); | ||
1796 | } | ||
1797 | while (NULL != (ml = h->mini_head)) | ||
1798 | { | ||
1799 | GNUNET_CONTAINER_DLL_remove (h->mini_head, | ||
1800 | h->mini_tail, | ||
1801 | ml); | ||
1802 | if (NULL != ml->mini) | ||
1803 | GNUNET_NAT_mini_map_stop (ml->mini); | ||
1804 | GNUNET_free (ml); | ||
1805 | } | ||
1806 | if (NULL != h->ext_dns) | ||
1807 | { | ||
1808 | GNUNET_RESOLVER_request_cancel (h->ext_dns); | ||
1809 | h->ext_dns = NULL; | ||
1810 | } | ||
1811 | if (NULL != h->hostname_dns) | ||
1812 | { | ||
1813 | GNUNET_RESOLVER_request_cancel (h->hostname_dns); | ||
1814 | h->hostname_dns = NULL; | ||
1815 | } | ||
1816 | if (NULL != h->server_read_task) | ||
1817 | { | ||
1818 | GNUNET_SCHEDULER_cancel (h->server_read_task); | ||
1819 | h->server_read_task = NULL; | ||
1820 | } | ||
1821 | if (NULL != h->ifc_task) | ||
1822 | { | ||
1823 | GNUNET_SCHEDULER_cancel (h->ifc_task); | ||
1824 | h->ifc_task = NULL; | ||
1825 | } | ||
1826 | if (NULL != h->hostname_task) | ||
1827 | { | ||
1828 | GNUNET_SCHEDULER_cancel (h->hostname_task); | ||
1829 | h->hostname_task = NULL; | ||
1830 | } | ||
1831 | if (NULL != h->dns_task) | ||
1832 | { | ||
1833 | GNUNET_SCHEDULER_cancel (h->dns_task); | ||
1834 | h->dns_task = NULL; | ||
1835 | } | ||
1836 | if (NULL != h->stun_task) | ||
1837 | { | ||
1838 | GNUNET_SCHEDULER_cancel (h->stun_task); | ||
1839 | h->stun_task = NULL; | ||
1840 | } | ||
1841 | if (NULL != h->stun_request) | ||
1842 | { | ||
1843 | GNUNET_NAT_stun_make_request_cancel (h->stun_request); | ||
1844 | h->stun_request = NULL; | ||
1845 | } | ||
1846 | if (NULL != h->server_proc) | ||
1847 | { | ||
1848 | if (0 != GNUNET_OS_process_kill (h->server_proc, | ||
1849 | GNUNET_TERM_SIG)) | ||
1850 | GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
1851 | "nat", | ||
1852 | "kill"); | ||
1853 | GNUNET_OS_process_wait (h->server_proc); | ||
1854 | GNUNET_OS_process_destroy (h->server_proc); | ||
1855 | h->server_proc = NULL; | ||
1856 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
1857 | h->server_stdout = NULL; | ||
1858 | h->server_stdout_handle = NULL; | ||
1859 | } | ||
1860 | if (NULL != h->server_stdout) | ||
1861 | { | ||
1862 | GNUNET_DISK_pipe_close (h->server_stdout); | ||
1863 | h->server_stdout = NULL; | ||
1864 | h->server_stdout_handle = NULL; | ||
1865 | } | ||
1866 | for (i = 0; i < h->num_local_addrs; i++) | ||
1867 | GNUNET_free (h->local_addrs[i]); | ||
1868 | GNUNET_free_non_null (h->local_addrs); | ||
1869 | GNUNET_free_non_null (h->local_addrlens); | ||
1870 | GNUNET_free_non_null (h->external_address); | ||
1871 | GNUNET_free_non_null (h->internal_address); | ||
1872 | GNUNET_free (h); | ||
1873 | } | ||
1874 | |||
1875 | |||
1876 | /** | ||
1877 | * We learned about a peer (possibly behind NAT) so run the | ||
1878 | * gnunet-helper-nat-client to send dummy ICMP responses to cause | ||
1879 | * that peer to connect to us (connection reversal). | ||
1880 | * | ||
1881 | * @param h handle (used for configuration) | ||
1882 | * @param sa the address of the peer (IPv4-only) | ||
1883 | * @return #GNUNET_SYSERR on error, #GNUNET_NO if nat client is disabled, | ||
1884 | * #GNUNET_OK otherwise | ||
1885 | */ | ||
1886 | int | ||
1887 | GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h, | ||
1888 | const struct sockaddr_in *sa) | ||
1889 | |||
1890 | |||
1891 | { | ||
1892 | char inet4[INET_ADDRSTRLEN]; | ||
1893 | char port_as_string[6]; | ||
1894 | struct GNUNET_OS_Process *proc; | ||
1895 | char *binary; | ||
1896 | |||
1897 | if (GNUNET_YES != h->enable_nat_client) | ||
1898 | return GNUNET_NO; /* not permitted / possible */ | ||
1899 | |||
1900 | if (h->internal_address == NULL) | ||
1901 | { | ||
1902 | LOG (GNUNET_ERROR_TYPE_WARNING, "nat", | ||
1903 | _("Internal IP address not known, cannot use ICMP NAT traversal method\n")); | ||
1904 | return GNUNET_SYSERR; | ||
1905 | } | ||
1906 | GNUNET_assert (sa->sin_family == AF_INET); | ||
1907 | if (NULL == inet_ntop (AF_INET, &sa->sin_addr, inet4, INET_ADDRSTRLEN)) | ||
1908 | { | ||
1909 | GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
1910 | "nat", | ||
1911 | "inet_ntop"); | ||
1912 | return GNUNET_SYSERR; | ||
1913 | } | ||
1914 | GNUNET_snprintf (port_as_string, | ||
1915 | sizeof (port_as_string), | ||
1916 | "%d", | ||
1917 | h->adv_port); | ||
1918 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1919 | _("Running gnunet-helper-nat-client %s %s %u\n"), | ||
1920 | h->internal_address, | ||
1921 | inet4, | ||
1922 | (unsigned int) h->adv_port); | ||
1923 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client"); | ||
1924 | proc = | ||
1925 | GNUNET_OS_start_process (GNUNET_NO, 0, NULL, NULL, NULL, | ||
1926 | binary, | ||
1927 | "gnunet-helper-nat-client", | ||
1928 | h->internal_address, | ||
1929 | inet4, port_as_string, NULL); | ||
1930 | GNUNET_free (binary); | ||
1931 | if (NULL == proc) | ||
1932 | return GNUNET_SYSERR; | ||
1933 | /* we know that the gnunet-helper-nat-client will terminate virtually | ||
1934 | * instantly */ | ||
1935 | GNUNET_OS_process_wait (proc); | ||
1936 | GNUNET_OS_process_destroy (proc); | ||
1937 | return GNUNET_OK; | ||
1938 | } | ||
1939 | |||
1940 | |||
1941 | /** | ||
1942 | * Test if the given address is (currently) a plausible IP address for this peer. | ||
1943 | * | ||
1944 | * @param h the handle returned by register | ||
1945 | * @param addr IP address to test (IPv4 or IPv6) | ||
1946 | * @param addrlen number of bytes in @a addr | ||
1947 | * @return #GNUNET_YES if the address is plausible, | ||
1948 | * #GNUNET_NO if the address is not plausible, | ||
1949 | * #GNUNET_SYSERR if the address is malformed | ||
1950 | */ | ||
1951 | int | ||
1952 | GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h, | ||
1953 | const void *addr, | ||
1954 | socklen_t addrlen) | ||
1955 | { | ||
1956 | struct LocalAddressList *pos; | ||
1957 | const struct sockaddr_in *in4; | ||
1958 | const struct sockaddr_in6 *in6; | ||
1959 | char pbuf[INET6_ADDRSTRLEN+1]; | ||
1960 | |||
1961 | if ((addrlen != sizeof (struct in_addr)) && | ||
1962 | (addrlen != sizeof (struct in6_addr))) | ||
1963 | { | ||
1964 | GNUNET_break (0); | ||
1965 | return GNUNET_SYSERR; | ||
1966 | } | ||
1967 | for (pos = h->lal_head; NULL != pos; pos = pos->next) | ||
1968 | { | ||
1969 | if (pos->addrlen == sizeof (struct sockaddr_in)) | ||
1970 | { | ||
1971 | in4 = (struct sockaddr_in *) &pos[1]; | ||
1972 | if ((addrlen == sizeof (struct in_addr)) && | ||
1973 | (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr)))) | ||
1974 | return GNUNET_YES; | ||
1975 | } | ||
1976 | else if (pos->addrlen == sizeof (struct sockaddr_in6)) | ||
1977 | { | ||
1978 | in6 = (struct sockaddr_in6 *) &pos[1]; | ||
1979 | if ((addrlen == sizeof (struct in6_addr)) && | ||
1980 | (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr)))) | ||
1981 | return GNUNET_YES; | ||
1982 | } | ||
1983 | else | ||
1984 | { | ||
1985 | GNUNET_assert (0); | ||
1986 | } | ||
1987 | } | ||
1988 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1989 | "Asked to validate one of my addresses (%s) and validation failed!\n", | ||
1990 | inet_ntop ((addrlen == sizeof(struct in_addr)) | ||
1991 | ? AF_INET | ||
1992 | : AF_INET6, | ||
1993 | addr, | ||
1994 | pbuf, sizeof (pbuf))); | ||
1995 | return GNUNET_NO; | ||
1996 | } | ||
1997 | |||
1998 | /** | ||
1999 | * Converts enum GNUNET_NAT_StatusCode to a string | ||
2000 | * | ||
2001 | * @param err error code to resolve to a string | ||
2002 | * @return pointer to a static string containing the error code | ||
2003 | */ | ||
2004 | const char * | ||
2005 | GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err) | ||
2006 | { | ||
2007 | switch (err) | ||
2008 | { | ||
2009 | case GNUNET_NAT_ERROR_SUCCESS: | ||
2010 | return _ ("Operation Successful"); | ||
2011 | case GNUNET_NAT_ERROR_IPC_FAILURE: | ||
2012 | return _ ("Internal Failure (IPC, ...)"); | ||
2013 | case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR: | ||
2014 | return _ ("Failure in network subsystem, check permissions."); | ||
2015 | case GNUNET_NAT_ERROR_TIMEOUT: | ||
2016 | return _ ("Encountered timeout while performing operation"); | ||
2017 | case GNUNET_NAT_ERROR_NOT_ONLINE: | ||
2018 | return _ ("detected that we are offline"); | ||
2019 | case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND: | ||
2020 | return _ ("`upnpc` command not found"); | ||
2021 | case GNUNET_NAT_ERROR_UPNPC_FAILED: | ||
2022 | return _ ("Failed to run `upnpc` command"); | ||
2023 | case GNUNET_NAT_ERROR_UPNPC_TIMEOUT: | ||
2024 | return _ ("`upnpc' command took too long, process killed"); | ||
2025 | case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED: | ||
2026 | return _ ("`upnpc' command failed to establish port mapping"); | ||
2027 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND: | ||
2028 | return _ ("`external-ip' command not found"); | ||
2029 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED: | ||
2030 | return _ ("Failed to run `external-ip` command"); | ||
2031 | case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID: | ||
2032 | return _ ("`external-ip' command output invalid"); | ||
2033 | case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID: | ||
2034 | return _ ("no valid address was returned by `external-ip'"); | ||
2035 | case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO: | ||
2036 | return _ ("Could not determine interface with internal/local network address"); | ||
2037 | case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND: | ||
2038 | return _ ("No functioning gnunet-helper-nat-server installation found"); | ||
2039 | case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED: | ||
2040 | return _ ("NAT test could not be initialized"); | ||
2041 | case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT: | ||
2042 | return _ ("NAT test timeout reached"); | ||
2043 | case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED: | ||
2044 | return _ ("could not register NAT"); | ||
2045 | case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND: | ||
2046 | return _ ("No working gnunet-helper-nat-client installation found"); | ||
2047 | /* case: | ||
2048 | return _ ("");*/ | ||
2049 | default: | ||
2050 | return "unknown status code"; | ||
2051 | } | ||
2052 | } | ||
2053 | |||
2054 | /* end of nat.c */ | ||