aboutsummaryrefslogtreecommitdiff
path: root/src/nat/gnunet-service-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nat/gnunet-service-nat.c')
-rw-r--r--src/nat/gnunet-service-nat.c2083
1 files changed, 0 insertions, 2083 deletions
diff --git a/src/nat/gnunet-service-nat.c b/src/nat/gnunet-service-nat.c
deleted file mode 100644
index 4dcc0312f..000000000
--- a/src/nat/gnunet-service-nat.c
+++ /dev/null
@@ -1,2083 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016, 2017 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file nat/gnunet-service-nat.c
23 * @brief network address translation traversal service
24 * @author Christian Grothoff
25 *
26 * The purpose of this service is to enable transports to
27 * traverse NAT routers, by providing traversal options and
28 * knowledge about the local network topology.
29 *
30 * TODO:
31 * - migrate test cases to new NAT service
32 * - add new traceroute-based logic for external IP detection
33 *
34 * - implement & test STUN processing to classify NAT;
35 * basically, open port & try different methods.
36 */
37#include "platform.h"
38#include <math.h>
39#include "gnunet_util_lib.h"
40#include "gnunet_protocols.h"
41#include "gnunet_signatures.h"
42#include "gnunet_statistics_service.h"
43#include "gnunet_resolver_service.h"
44#include "gnunet_nat_service.h"
45#include "gnunet-service-nat.h"
46#include "gnunet-service-nat_externalip.h"
47#include "gnunet-service-nat_stun.h"
48#include "gnunet-service-nat_mini.h"
49#include "gnunet-service-nat_helper.h"
50#include "nat.h"
51#include <gcrypt.h>
52
53
54/**
55 * How often should we ask the OS about a list of active
56 * network interfaces?
57 */
58#define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
59
60/**
61 * How long do we wait until we forcefully terminate autoconfiguration?
62 */
63#define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \
64 GNUNET_TIME_UNIT_SECONDS, 5)
65
66/**
67 * How often do we scan for changes in how our external (dyndns) hostname resolves?
68 */
69#define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \
70 GNUNET_TIME_UNIT_MINUTES, 7)
71
72
73/**
74 * Information we track per client address.
75 */
76struct ClientAddress
77{
78 /**
79 * Network address used by the client.
80 */
81 struct sockaddr_storage ss;
82
83 /**
84 * Handle to active UPnP request where we asked upnpc to open
85 * a port at the NAT. NULL if we do not have such a request
86 * pending.
87 */
88 struct GNUNET_NAT_MiniHandle *mh;
89};
90
91
92/**
93 * List of local addresses this system has.
94 */
95struct LocalAddressList
96{
97 /**
98 * This is a linked list.
99 */
100 struct LocalAddressList *next;
101
102 /**
103 * Previous entry.
104 */
105 struct LocalAddressList *prev;
106
107 /**
108 * Context for a gnunet-helper-nat-server used to listen
109 * for ICMP messages to this client for connection reversal.
110 */
111 struct HelperContext *hc;
112
113 /**
114 * The address itself (i.e. `struct sockaddr_in` or `struct
115 * sockaddr_in6`, in the respective byte order).
116 */
117 struct sockaddr_storage addr;
118
119 /**
120 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
121 */
122 int af;
123
124 /**
125 * #GNUNET_YES if we saw this one in the previous iteration,
126 * but not in the current iteration and thus might need to
127 * remove it at the end.
128 */
129 int old;
130
131 /**
132 * What type of address is this?
133 */
134 enum GNUNET_NAT_AddressClass ac;
135};
136
137
138/**
139 * Internal data structure we track for each of our clients.
140 */
141struct ClientHandle
142{
143 /**
144 * Kept in a DLL.
145 */
146 struct ClientHandle *next;
147
148 /**
149 * Kept in a DLL.
150 */
151 struct ClientHandle *prev;
152
153 /**
154 * Underlying handle for this client with the service.
155 */
156 struct GNUNET_SERVICE_Client *client;
157
158 /**
159 * Message queue for communicating with the client.
160 */
161 struct GNUNET_MQ_Handle *mq;
162
163 /**
164 * Array of addresses used by the service.
165 */
166 struct ClientAddress *caddrs;
167
168 /**
169 * External DNS name and port given by user due to manual
170 * hole punching. Special DNS name 'AUTO' is used to indicate
171 * desire for automatic determination of the external IP
172 * (instead of DNS or manual configuration, i.e. to be used
173 * if the IP keeps changing and we have no DynDNS, but we do
174 * have a hole punched).
175 */
176 char *hole_external;
177
178 /**
179 * Name of the configuration section this client cares about.
180 */
181 char *section_name;
182
183 /**
184 * Task for periodically re-running the @e ext_dns DNS lookup.
185 */
186 struct GNUNET_SCHEDULER_Task *ext_dns_task;
187
188 /**
189 * Handle for (DYN)DNS lookup of our external IP as given in
190 * @e hole_external.
191 */
192 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
193
194 /**
195 * Handle for monitoring external IP changes.
196 */
197 struct GN_ExternalIPMonitor *external_monitor;
198
199 /**
200 * DLL of external IP addresses as given in @e hole_external.
201 */
202 struct LocalAddressList *ext_addr_head;
203
204 /**
205 * DLL of external IP addresses as given in @e hole_external.
206 */
207 struct LocalAddressList *ext_addr_tail;
208
209 /**
210 * Port number we found in @e hole_external.
211 */
212 uint16_t ext_dns_port;
213
214 /**
215 * What does this client care about?
216 */
217 enum GNUNET_NAT_RegisterFlags flags;
218
219 /**
220 * Is any of the @e caddrs in a reserved subnet for NAT?
221 */
222 int natted_address;
223
224 /**
225 * Number of addresses that this service is bound to.
226 * Length of the @e caddrs array.
227 */
228 uint16_t num_caddrs;
229
230 /**
231 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
232 */
233 uint8_t proto;
234};
235
236
237/**
238 * External IP address as given to us via some STUN server.
239 */
240struct StunExternalIP
241{
242 /**
243 * Kept in a DLL.
244 */
245 struct StunExternalIP *next;
246
247 /**
248 * Kept in a DLL.
249 */
250 struct StunExternalIP *prev;
251
252 /**
253 * Task we run to remove this entry when it is stale.
254 */
255 struct GNUNET_SCHEDULER_Task *timeout_task;
256
257 /**
258 * Our external IP address as reported by the
259 * STUN server.
260 */
261 struct sockaddr_in external_addr;
262
263 /**
264 * Address of the reporting STUN server. Used to
265 * detect when a STUN server changes its opinion
266 * to more quickly remove stale results.
267 */
268 struct sockaddr_storage stun_server_addr;
269
270 /**
271 * Number of bytes used in @e stun_server_addr.
272 */
273 size_t stun_server_addr_len;
274};
275
276
277/**
278 * Timeout to use when STUN data is considered stale.
279 */
280static struct GNUNET_TIME_Relative stun_stale_timeout;
281
282/**
283 * How often do we scan for changes in how our external (dyndns) hostname resolves?
284 */
285static struct GNUNET_TIME_Relative dyndns_frequency;
286
287/**
288 * Handle to our current configuration.
289 */
290static const struct GNUNET_CONFIGURATION_Handle *cfg;
291
292/**
293 * Handle to the statistics service.
294 */
295static struct GNUNET_STATISTICS_Handle *stats;
296
297/**
298 * Task scheduled to periodically scan our network interfaces.
299 */
300static struct GNUNET_SCHEDULER_Task *scan_task;
301
302/**
303 * Head of client DLL.
304 */
305static struct ClientHandle *ch_head;
306
307/**
308 * Tail of client DLL.
309 */
310static struct ClientHandle *ch_tail;
311
312/**
313 * Head of DLL of local addresses.
314 */
315static struct LocalAddressList *lal_head;
316
317/**
318 * Tail of DLL of local addresses.
319 */
320static struct LocalAddressList *lal_tail;
321
322/**
323 * Kept in a DLL.
324 */
325static struct StunExternalIP *se_head;
326
327/**
328 * Kept in a DLL.
329 */
330static struct StunExternalIP *se_tail;
331
332/**
333 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
334 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
335 */
336int enable_upnp;
337
338/**
339 * Is IP Scanning enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
340 * without, only explicitly specified IPs will be handled (HOLE_EXTERNAL)
341 */
342int enable_ipscan;
343
344/**
345 * Remove and free an entry from the #lal_head DLL.
346 *
347 * @param lal entry to free
348 */
349static void
350free_lal (struct LocalAddressList *lal)
351{
352 GNUNET_CONTAINER_DLL_remove (lal_head,
353 lal_tail,
354 lal);
355 if (NULL != lal->hc)
356 {
357 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
358 "Lost NATed local address %s, stopping NAT server\n",
359 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
360 sizeof(struct sockaddr_in)));
361
362 GN_stop_gnunet_nat_server_ (lal->hc);
363 lal->hc = NULL;
364 }
365 GNUNET_free (lal);
366}
367
368
369/**
370 * Free the DLL starting at #lal_head.
371 */
372static void
373destroy_lal ()
374{
375 struct LocalAddressList *lal;
376
377 while (NULL != (lal = lal_head))
378 free_lal (lal);
379}
380
381
382/**
383 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
384 * client.
385 *
386 * @param cls client who sent the message
387 * @param message the message received
388 * @return #GNUNET_OK if message is well-formed
389 */
390static int
391check_register (void *cls,
392 const struct GNUNET_NAT_RegisterMessage *message)
393{
394 uint16_t num_addrs = ntohs (message->num_addrs);
395 const char *off = (const char *) &message[1];
396 size_t left = ntohs (message->header.size) - sizeof(*message);
397
398 for (unsigned int i = 0; i < num_addrs; i++)
399 {
400 size_t alen;
401 const struct sockaddr *sa = (const struct sockaddr *) off;
402
403 if (sizeof(sa_family_t) > left)
404 {
405 GNUNET_break (0);
406 return GNUNET_SYSERR;
407 }
408 switch (sa->sa_family)
409 {
410 case AF_INET:
411 alen = sizeof(struct sockaddr_in);
412 break;
413
414 case AF_INET6:
415 alen = sizeof(struct sockaddr_in6);
416 break;
417
418#if AF_UNIX
419 case AF_UNIX:
420 alen = sizeof(struct sockaddr_un);
421 break;
422#endif
423 default:
424 GNUNET_break (0);
425 return GNUNET_SYSERR;
426 }
427 if (alen > left)
428 {
429 GNUNET_break (0);
430 return GNUNET_SYSERR;
431 }
432 off += alen;
433 left -= alen;
434 }
435 if (left != ntohs (message->str_len))
436 {
437 GNUNET_break (0);
438 return GNUNET_SYSERR;
439 }
440 return GNUNET_OK;
441}
442
443
444/**
445 * Check if @a ip is in @a network with @a bits netmask.
446 *
447 * @param network to test
448 * @param ip IP address to test
449 * @param bits bitmask for the network
450 * @return #GNUNET_YES if @a ip is in @a network
451 */
452static int
453match_ipv4 (const char *network,
454 const struct in_addr *ip,
455 uint8_t bits)
456{
457 struct in_addr net;
458
459 if (0 == ip->s_addr)
460 return GNUNET_YES;
461 if (0 == bits)
462 return GNUNET_YES;
463 GNUNET_assert (1 == inet_pton (AF_INET,
464 network,
465 &net));
466 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
467}
468
469
470/**
471 * Check if @a ip is in @a network with @a bits netmask.
472 *
473 * @param network to test
474 * @param ip IP address to test
475 * @param bits bitmask for the network
476 * @return #GNUNET_YES if @a ip is in @a network
477 */
478static int
479match_ipv6 (const char *network,
480 const struct in6_addr *ip,
481 uint8_t bits)
482{
483 struct in6_addr net;
484 struct in6_addr mask;
485 unsigned int off;
486
487 if (0 == bits)
488 return GNUNET_YES;
489 GNUNET_assert (1 == inet_pton (AF_INET6,
490 network,
491 &net));
492 memset (&mask, 0, sizeof(mask));
493 if (0 == GNUNET_memcmp (&mask,
494 ip))
495 return GNUNET_YES;
496 off = 0;
497 while (bits > 8)
498 {
499 mask.s6_addr[off++] = 0xFF;
500 bits -= 8;
501 }
502 while (bits > 0)
503 {
504 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
505 bits--;
506 }
507 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
508 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
509 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
510 return GNUNET_NO;
511 return GNUNET_YES;
512}
513
514
515/**
516 * Test if the given IPv4 address is in a known range
517 * for private networks.
518 *
519 * @param ip address to test
520 * @return #GNUNET_YES if @a ip is in a NAT range
521 */
522static int
523is_nat_v4 (const struct in_addr *ip)
524{
525 return
526 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
527 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
528 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
529 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
530 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
531}
532
533
534/**
535 * Test if the given IPv6 address is in a known range
536 * for private networks.
537 *
538 * @param ip address to test
539 * @return #GNUNET_YES if @a ip is in a NAT range
540 */
541static int
542is_nat_v6 (const struct in6_addr *ip)
543{
544 return
545 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
546 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
547 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
548}
549
550
551/**
552 * Closure for #ifc_proc.
553 */
554struct IfcProcContext
555{
556 /**
557 * Head of DLL of local addresses.
558 */
559 struct LocalAddressList *lal_head;
560
561 /**
562 * Tail of DLL of local addresses.
563 */
564 struct LocalAddressList *lal_tail;
565};
566
567
568/**
569 * Callback function invoked for each interface found. Adds them
570 * to our new address list.
571 *
572 * @param cls a `struct IfcProcContext *`
573 * @param name name of the interface (can be NULL for unknown)
574 * @param isDefault is this presumably the default interface
575 * @param addr address of this interface (can be NULL for unknown or unassigned)
576 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
577 * @param netmask the network mask (can be NULL for unknown or unassigned)
578 * @param addrlen length of the address
579 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
580 */
581static int
582ifc_proc (void *cls,
583 const char *name,
584 int isDefault,
585 const struct sockaddr *addr,
586 const struct sockaddr *broadcast_addr,
587 const struct sockaddr *netmask,
588 socklen_t addrlen)
589{
590 struct IfcProcContext *ifc_ctx = cls;
591 struct LocalAddressList *lal;
592 size_t alen;
593 const struct in_addr *ip4;
594 const struct in6_addr *ip6;
595 enum GNUNET_NAT_AddressClass ac;
596
597 switch (addr->sa_family)
598 {
599 case AF_INET:
600 alen = sizeof(struct sockaddr_in);
601 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
602 if (match_ipv4 ("127.0.0.0", ip4, 8))
603 ac = GNUNET_NAT_AC_LOOPBACK;
604 else if (is_nat_v4 (ip4))
605 ac = GNUNET_NAT_AC_LAN;
606 else
607 ac = GNUNET_NAT_AC_GLOBAL;
608 break;
609
610 case AF_INET6:
611 alen = sizeof(struct sockaddr_in6);
612 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
613 if (match_ipv6 ("::1", ip6, 128))
614 ac = GNUNET_NAT_AC_LOOPBACK;
615 else if (is_nat_v6 (ip6))
616 ac = GNUNET_NAT_AC_LAN;
617 else
618 ac = GNUNET_NAT_AC_GLOBAL;
619 if ((ip6->s6_addr[11] == 0xFF) &&
620 (ip6->s6_addr[12] == 0xFE))
621 {
622 /* contains a MAC, be extra careful! */
623 ac |= GNUNET_NAT_AC_PRIVATE;
624 }
625 break;
626
627#if AF_UNIX
628 case AF_UNIX:
629 GNUNET_break (0);
630 return GNUNET_OK;
631#endif
632 default:
633 GNUNET_break (0);
634 return GNUNET_OK;
635 }
636 lal = GNUNET_malloc (sizeof(*lal));
637 lal->af = addr->sa_family;
638 lal->ac = ac;
639 GNUNET_memcpy (&lal->addr,
640 addr,
641 alen);
642 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
643 ifc_ctx->lal_tail,
644 lal);
645 return GNUNET_OK;
646}
647
648
649/**
650 * Notify client about a change in the list of addresses this peer
651 * has.
652 *
653 * @param ac address class of the entry in the list that changed
654 * @param ch client to contact
655 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
656 * @param addr the address that changed
657 * @param addr_len number of bytes in @a addr
658 */
659static void
660notify_client (enum GNUNET_NAT_AddressClass ac,
661 struct ClientHandle *ch,
662 int add,
663 const void *addr,
664 size_t addr_len)
665{
666 struct GNUNET_MQ_Envelope *env;
667 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
668
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 "Notifying client about %s of IP %s\n",
671 add ? "addition" : "removal",
672 GNUNET_a2s (addr,
673 addr_len));
674 env = GNUNET_MQ_msg_extra (msg,
675 addr_len,
676 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
677 msg->add_remove = htonl (add);
678 msg->addr_class = htonl (ac);
679 GNUNET_memcpy (&msg[1],
680 addr,
681 addr_len);
682 GNUNET_MQ_send (ch->mq,
683 env);
684}
685
686
687/**
688 * Check if we should bother to notify this client about this
689 * address change, and if so, do it.
690 *
691 * @param delta the entry in the list that changed
692 * @param ch client to check
693 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
694 */
695static void
696check_notify_client (struct LocalAddressList *delta,
697 struct ClientHandle *ch,
698 int add)
699{
700 size_t alen;
701 struct sockaddr_in v4;
702 struct sockaddr_in6 v6;
703
704 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
705 {
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "Not notifying client as it does not care about addresses\n");
708 return;
709 }
710 switch (delta->af)
711 {
712 case AF_INET:
713 alen = sizeof(struct sockaddr_in);
714 GNUNET_memcpy (&v4,
715 &delta->addr,
716 alen);
717
718 /* Check for client notifications */
719 for (unsigned int i = 0; i < ch->num_caddrs; i++)
720 {
721 const struct sockaddr_in *c4;
722
723 if (AF_INET != ch->caddrs[i].ss.ss_family)
724 continue; /* IPv4 not relevant */
725 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
726 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
727 (0 != c4->sin_addr.s_addr) &&
728 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
729 continue; /* bound to loopback, but this is not loopback */
730 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
731 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
732 continue; /* bound to non-loopback, but this is loopback */
733 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
734 (0 != c4->sin_addr.s_addr) &&
735 (! is_nat_v4 (&v4.sin_addr)))
736 continue; /* based on external-IP, but this IP is not
737 from private address range. */
738 if ((0 != GNUNET_memcmp (&v4.sin_addr,
739 &c4->sin_addr)) &&
740 (0 != c4->sin_addr.s_addr) &&
741 (! is_nat_v4 (&c4->sin_addr)))
742 continue; /* this IP is not from private address range,
743 and IP does not match. */
744
745 /* OK, IP seems relevant, notify client */
746 if (0 == htons (v4.sin_port))
747 v4.sin_port = c4->sin_port;
748 notify_client (delta->ac,
749 ch,
750 add,
751 &v4,
752 alen);
753 }
754 break;
755
756 case AF_INET6:
757 alen = sizeof(struct sockaddr_in6);
758 GNUNET_memcpy (&v6,
759 &delta->addr,
760 alen);
761 for (unsigned int i = 0; i < ch->num_caddrs; i++)
762 {
763 const struct sockaddr_in6 *c6;
764
765 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
766 continue; /* IPv4 not relevant */
767 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
768 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
769 (0 != GNUNET_memcmp (&c6->sin6_addr,
770 &in6addr_any)) &&
771 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
772 continue; /* bound to loopback, but this is not loopback */
773 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
774 match_ipv6 ("::1", &v6.sin6_addr, 128))
775 continue; /* bound to non-loopback, but this is loopback */
776 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
777 (0 != GNUNET_memcmp (&c6->sin6_addr,
778 &in6addr_any)) &&
779 (! is_nat_v6 (&v6.sin6_addr)))
780 continue; /* based on external-IP, but this IP is not
781 from private address range. */
782 if ((0 != GNUNET_memcmp (&v6.sin6_addr,
783 &c6->sin6_addr)) &&
784 (0 != GNUNET_memcmp (&c6->sin6_addr,
785 &in6addr_any)) &&
786 (! is_nat_v6 (&c6->sin6_addr)))
787 continue; /* this IP is not from private address range,
788 and IP does not match. */
789 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
790 (0 != GNUNET_memcmp (&c6->sin6_addr,
791 &in6addr_any)) &&
792 (0 != GNUNET_memcmp (&v6.sin6_addr,
793 &c6->sin6_addr)) &&
794 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)))
795 continue; /* client bound to link-local, and the other address
796 does not match and is not an external IP */
797
798 /* OK, IP seems relevant, notify client */
799 if (0 == htons (v6.sin6_port))
800 v6.sin6_port = c6->sin6_port;
801 notify_client (delta->ac,
802 ch,
803 add,
804 &v6,
805 alen);
806 }
807 break;
808
809 default:
810 GNUNET_break (0);
811 return;
812 }
813}
814
815
816/**
817 * Notify all clients about a change in the list
818 * of addresses this peer has.
819 *
820 * @param delta the entry in the list that changed
821 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
822 */
823static void
824notify_clients (struct LocalAddressList *delta,
825 int add)
826{
827 for (struct ClientHandle *ch = ch_head;
828 NULL != ch;
829 ch = ch->next)
830 check_notify_client (delta,
831 ch,
832 add);
833}
834
835
836/**
837 * Tell relevant client about a change in our external
838 * IPv4 address.
839 *
840 * @param cls client to check if it cares and possibly notify
841 * @param v4 the external address that changed
842 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
843 */
844static void
845notify_client_external_ipv4_change (void *cls,
846 const struct in_addr *v4,
847 int add)
848{
849 struct ClientHandle *ch = cls;
850 struct sockaddr_in sa;
851 int have_v4;
852
853 /* (0) check if this impacts 'hole_external' */
854 if ((NULL != ch->hole_external) &&
855 (0 == strcasecmp (ch->hole_external,
856 "AUTO")))
857 {
858 struct LocalAddressList lal;
859 struct sockaddr_in *s4;
860
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
862 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
863 (unsigned int) ch->ext_dns_port,
864 ch->section_name);
865 memset (&lal, 0, sizeof(lal));
866 s4 = (struct sockaddr_in *) &lal.addr;
867 s4->sin_family = AF_INET;
868 s4->sin_port = htons (ch->ext_dns_port);
869 s4->sin_addr = *v4;
870 lal.af = AF_INET;
871 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
872 check_notify_client (&lal,
873 ch,
874 add);
875 }
876
877 /* (1) check if client cares. */
878 if (! ch->natted_address)
879 return;
880 have_v4 = GNUNET_NO;
881 for (unsigned int i = 0; i < ch->num_caddrs; i++)
882 {
883 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
884
885 if (AF_INET != ss->ss_family)
886 continue;
887 have_v4 = GNUNET_YES;
888 break;
889 }
890 if (GNUNET_NO == have_v4)
891 return; /* IPv6-only */
892
893 /* (2) build address info */
894 memset (&sa,
895 0,
896 sizeof(sa));
897 sa.sin_family = AF_INET;
898 sa.sin_addr = *v4;
899 sa.sin_port = htons (0);
900
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902 "Detected eternal IP %s, notifying client of external IP (without port)\n",
903 GNUNET_a2s ((const struct sockaddr *) &sa,
904 sizeof(sa)));
905 /* (3) notify client of change */
906 notify_client (is_nat_v4 (v4)
907 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
908 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
909 ch,
910 add,
911 &sa,
912 sizeof(sa));
913}
914
915
916/**
917 * We got a connection reversal request from another peer.
918 * Notify applicable clients.
919 *
920 * @param cls closure with the `struct LocalAddressList`
921 * @param ra IP address of the peer who wants us to connect to it
922 */
923static void
924reversal_callback (void *cls,
925 const struct sockaddr_in *ra)
926{
927 struct LocalAddressList *lal = cls;
928 const struct sockaddr_in *l4;
929
930 GNUNET_assert (AF_INET == lal->af);
931 l4 = (const struct sockaddr_in *) &lal->addr;
932 for (struct ClientHandle *ch = ch_head;
933 NULL != ch;
934 ch = ch->next)
935 {
936 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
937 struct GNUNET_MQ_Envelope *env;
938 int match;
939
940 /* Check if client is in applicable range for ICMP NAT traversal
941 for this local address */
942 if (! ch->natted_address)
943 continue;
944 match = GNUNET_NO;
945 for (unsigned int i = 0; i < ch->num_caddrs; i++)
946 {
947 struct ClientAddress *ca = &ch->caddrs[i];
948 const struct sockaddr_in *c4;
949
950 if (AF_INET != ca->ss.ss_family)
951 continue;
952 c4 = (const struct sockaddr_in *) &ca->ss;
953 if ((0 != c4->sin_addr.s_addr) &&
954 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
955 continue;
956 match = GNUNET_YES;
957 break;
958 }
959 if (! match)
960 continue;
961
962 /* Notify applicable client about connection reversal request */
963 env = GNUNET_MQ_msg_extra (crrm,
964 sizeof(struct sockaddr_in),
965 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
966 GNUNET_memcpy (&crrm[1],
967 ra,
968 sizeof(struct sockaddr_in));
969 GNUNET_MQ_send (ch->mq,
970 env);
971 }
972}
973
974
975/**
976 * Task we run periodically to scan for network interfaces.
977 *
978 * @param cls NULL
979 */
980static void
981run_scan (void *cls)
982{
983 struct IfcProcContext ifc_ctx;
984 int found;
985 int have_nat;
986 struct LocalAddressList *lnext;
987
988 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
989 &run_scan,
990 NULL);
991 memset (&ifc_ctx,
992 0,
993 sizeof(ifc_ctx));
994 GNUNET_OS_network_interfaces_list (&ifc_proc,
995 &ifc_ctx);
996 /* remove addresses that disappeared */
997 for (struct LocalAddressList *lal = lal_head;
998 NULL != lal;
999 lal = lnext)
1000 {
1001 lnext = lal->next;
1002 found = GNUNET_NO;
1003 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1004 NULL != pos;
1005 pos = pos->next)
1006 {
1007 if ((pos->af == lal->af) &&
1008 (0 == memcmp (&lal->addr,
1009 &pos->addr,
1010 (AF_INET == lal->af)
1011 ? sizeof(struct sockaddr_in)
1012 : sizeof(struct sockaddr_in6))))
1013 {
1014 found = GNUNET_YES;
1015 }
1016 }
1017 if (GNUNET_NO == found)
1018 {
1019 notify_clients (lal,
1020 GNUNET_NO);
1021 free_lal (lal);
1022 }
1023 }
1024
1025 /* add addresses that appeared */
1026 have_nat = GNUNET_NO;
1027 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1028 NULL != pos;
1029 pos = ifc_ctx.lal_head)
1030 {
1031 found = GNUNET_NO;
1032 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1033 have_nat = GNUNET_YES;
1034 for (struct LocalAddressList *lal = lal_head;
1035 NULL != lal;
1036 lal = lal->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 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1047 ifc_ctx.lal_tail,
1048 pos);
1049 if (GNUNET_YES == found)
1050 {
1051 GNUNET_free (pos);
1052 }
1053 else
1054 {
1055 notify_clients (pos,
1056 GNUNET_YES);
1057 GNUNET_CONTAINER_DLL_insert (lal_head,
1058 lal_tail,
1059 pos);
1060 if ((AF_INET == pos->af) &&
1061 (NULL == pos->hc) &&
1062 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1063 {
1064 const struct sockaddr_in *s4
1065 = (const struct sockaddr_in *) &pos->addr;
1066
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Found NATed local address %s, starting NAT server\n",
1069 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1070 sizeof(*s4)));
1071 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1072 &reversal_callback,
1073 pos,
1074 cfg);
1075 }
1076 }
1077 }
1078 GN_nat_status_changed (have_nat);
1079}
1080
1081
1082/**
1083 * Function called whenever our set of external addresses
1084 * as created by `upnpc` changes.
1085 *
1086 * @param cls closure with our `struct ClientHandle *`
1087 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1088 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1089 * @param addr either the previous or the new public IP address
1090 * @param addrlen actual length of the @a addr
1091 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1092 */
1093static void
1094upnp_addr_change_cb (void *cls,
1095 int add_remove,
1096 const struct sockaddr *addr,
1097 socklen_t addrlen,
1098 enum GNUNET_NAT_StatusCode result)
1099{
1100 struct ClientHandle *ch = cls;
1101 enum GNUNET_NAT_AddressClass ac;
1102
1103 switch (result)
1104 {
1105 case GNUNET_NAT_ERROR_SUCCESS:
1106 GNUNET_assert (NULL != addr);
1107 break;
1108
1109 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1110 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1111 case GNUNET_NAT_ERROR_IPC_FAILURE:
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113 "Running upnpc failed: %d\n",
1114 result);
1115 return;
1116
1117 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1118 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1119 "external-ip binary not found\n");
1120 return;
1121
1122 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1124 "upnpc binary not found\n");
1125 return;
1126
1127 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1128 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1129 "external-ip binary could not be run\n");
1130 return;
1131
1132 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1134 "upnpc failed to create port mapping\n");
1135 return;
1136
1137 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Invalid output from upnpc\n");
1140 return;
1141
1142 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1144 "Invalid address returned by upnpc\n");
1145 return;
1146
1147 default:
1148 GNUNET_break (0); /* should not be possible */
1149 return;
1150 }
1151 switch (addr->sa_family)
1152 {
1153 case AF_INET:
1154 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1155 ? GNUNET_NAT_AC_LAN
1156 : GNUNET_NAT_AC_EXTERN;
1157 break;
1158
1159 case AF_INET6:
1160 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1161 ? GNUNET_NAT_AC_LAN
1162 : GNUNET_NAT_AC_EXTERN;
1163 break;
1164
1165 default:
1166 GNUNET_break (0);
1167 return;
1168 }
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170 "upnp external address %s: %s\n",
1171 add_remove ? "added" : "removed",
1172 GNUNET_a2s (addr,
1173 addrlen));
1174 notify_client (ac,
1175 ch,
1176 add_remove,
1177 addr,
1178 addrlen);
1179}
1180
1181
1182/**
1183 * Resolve the `hole_external` name to figure out our
1184 * external address from a manually punched hole. The
1185 * port number has already been parsed, this task is
1186 * responsible for periodically doing a DNS lookup.
1187 *
1188 * @param ch client handle to act upon
1189 */
1190static void
1191dyndns_lookup (void *cls);
1192
1193
1194/**
1195 * Our (external) hostname was resolved. Update lists of
1196 * current external IPs (note that DNS may return multiple
1197 * addresses!) and notify client accordingly.
1198 *
1199 * @param cls the `struct ClientHandle`
1200 * @param addr NULL on error, otherwise result of DNS lookup
1201 * @param addrlen number of bytes in @a addr
1202 */
1203static void
1204process_external_ip (void *cls,
1205 const struct sockaddr *addr,
1206 socklen_t addrlen)
1207{
1208 struct ClientHandle *ch = cls;
1209 struct LocalAddressList *lal;
1210 struct sockaddr_storage ss;
1211 struct sockaddr_in *v4;
1212 struct sockaddr_in6 *v6;
1213
1214 if (NULL == addr)
1215 {
1216 struct LocalAddressList *laln;
1217
1218 ch->ext_dns = NULL;
1219 ch->ext_dns_task
1220 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1221 &dyndns_lookup,
1222 ch);
1223 /* Current iteration is over, remove 'old' IPs now */
1224 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1225 {
1226 laln = lal->next;
1227 if (GNUNET_YES == lal->old)
1228 {
1229 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1230 ch->ext_addr_tail,
1231 lal);
1232 check_notify_client (lal,
1233 ch,
1234 GNUNET_NO);
1235 GNUNET_free (lal);
1236 }
1237 }
1238 return;
1239 }
1240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1241 "Got IP `%s' for external address `%s'\n",
1242 GNUNET_a2s (addr,
1243 addrlen),
1244 ch->hole_external);
1245
1246 /* build sockaddr storage with port number */
1247 memset (&ss,
1248 0,
1249 sizeof(ss));
1250 GNUNET_memcpy (&ss,
1251 addr,
1252 addrlen);
1253 switch (addr->sa_family)
1254 {
1255 case AF_INET:
1256 v4 = (struct sockaddr_in *) &ss;
1257 v4->sin_port = htons (ch->ext_dns_port);
1258 break;
1259
1260 case AF_INET6:
1261 v6 = (struct sockaddr_in6 *) &ss;
1262 v6->sin6_port = htons (ch->ext_dns_port);
1263 break;
1264
1265 default:
1266 GNUNET_break (0);
1267 return;
1268 }
1269 /* See if 'ss' matches any of our known addresses */
1270 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1271 {
1272 if (GNUNET_NO == lal->old)
1273 continue; /* already processed, skip */
1274 if ((addr->sa_family == lal->addr.ss_family) &&
1275 (0 == memcmp (&ss,
1276 &lal->addr,
1277 addrlen)))
1278 {
1279 /* Address unchanged, remember so we do not remove */
1280 lal->old = GNUNET_NO;
1281 return; /* done here */
1282 }
1283 }
1284 /* notify client, and remember IP for later removal! */
1285 lal = GNUNET_new (struct LocalAddressList);
1286 lal->addr = ss;
1287 lal->af = ss.ss_family;
1288 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1289 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1290 ch->ext_addr_tail,
1291 lal);
1292 check_notify_client (lal,
1293 ch,
1294 GNUNET_YES);
1295}
1296
1297
1298/**
1299 * Resolve the `hole_external` name to figure out our
1300 * external address from a manually punched hole. The
1301 * port number has already been parsed, this task is
1302 * responsible for periodically doing a DNS lookup.
1303 *
1304 * @param ch client handle to act upon
1305 */
1306static void
1307dyndns_lookup (void *cls)
1308{
1309 struct ClientHandle *ch = cls;
1310 struct LocalAddressList *lal;
1311
1312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1314 ch->section_name,
1315 ch->hole_external,
1316 (unsigned int) ch->ext_dns_port);
1317 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1318 lal->old = GNUNET_YES;
1319 ch->ext_dns_task = NULL;
1320 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1321 AF_UNSPEC,
1322 GNUNET_TIME_UNIT_MINUTES,
1323 &process_external_ip,
1324 ch);
1325}
1326
1327
1328/**
1329 * Resolve the `hole_external` name to figure out our
1330 * external address from a manually punched hole. The
1331 * given name may be "AUTO" in which case we should use
1332 * the IP address(es) we have from upnpc or other methods.
1333 * The name can also be an IP address, in which case we
1334 * do not need to do DNS resolution. Finally, we also
1335 * need to parse the port number.
1336 *
1337 * @param ch client handle to act upon
1338 */
1339static void
1340lookup_hole_external (struct ClientHandle *ch)
1341{
1342 char *port;
1343 unsigned int pnum;
1344 struct sockaddr_in *s4;
1345 struct LocalAddressList *lal;
1346
1347 port = strrchr (ch->hole_external, ':');
1348 if (NULL == port)
1349 {
1350 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1351 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1352 ch->hole_external);
1353 return;
1354 }
1355 if ((1 != sscanf (port + 1,
1356 "%u",
1357 &pnum)) ||
1358 (pnum > 65535))
1359 {
1360 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1361 _ (
1362 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1363 port + 1);
1364 return;
1365 }
1366 ch->ext_dns_port = (uint16_t) pnum;
1367 *port = '\0';
1368
1369 lal = GNUNET_new (struct LocalAddressList);
1370 if ('[' == *ch->hole_external)
1371 {
1372 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1373
1374 s6->sin6_family = AF_INET6;
1375 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1376 {
1377 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1378 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1379 ch->hole_external);
1380 GNUNET_free (lal);
1381 return;
1382 }
1383 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1384 if (1 != inet_pton (AF_INET6,
1385 ch->hole_external + 1,
1386 &s6->sin6_addr))
1387 {
1388 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1389 _ (
1390 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1391 ch->hole_external + 1);
1392 GNUNET_free (lal);
1393 return;
1394 }
1395 s6->sin6_port = htons (ch->ext_dns_port);
1396 lal->af = AF_INET6;
1397 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1398 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1399 ch->ext_addr_tail,
1400 lal);
1401 check_notify_client (lal,
1402 ch,
1403 GNUNET_YES);
1404 return;
1405 }
1406
1407 s4 = (struct sockaddr_in *) &lal->addr;
1408 s4->sin_family = AF_INET;
1409 if (1 == inet_pton (AF_INET,
1410 ch->hole_external,
1411 &s4->sin_addr))
1412 {
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1415 ch->section_name,
1416 ch->hole_external,
1417 (unsigned int) ch->ext_dns_port);
1418 s4->sin_port = htons (ch->ext_dns_port);
1419 lal->af = AF_INET;
1420 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1421 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1422 ch->ext_addr_tail,
1423 lal);
1424 check_notify_client (lal,
1425 ch,
1426 GNUNET_YES);
1427 return;
1428 }
1429 if (0 == strcasecmp (ch->hole_external,
1430 "AUTO"))
1431 {
1432 /* handled in #notify_client_external_ipv4_change() */
1433 GNUNET_free (lal);
1434 return;
1435 }
1436 /* got a DNS name, trigger lookup! */
1437 GNUNET_free (lal);
1438 ch->ext_dns_task
1439 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1440 ch);
1441}
1442
1443
1444/**
1445 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1446 * We remember the client for updates upon future NAT events.
1447 *
1448 * @param cls client who sent the message
1449 * @param message the message received
1450 */
1451static void
1452handle_register (void *cls,
1453 const struct GNUNET_NAT_RegisterMessage *message)
1454{
1455 struct ClientHandle *ch = cls;
1456 const char *off;
1457 size_t left;
1458
1459 if ((0 != ch->proto) ||
1460 (NULL != ch->caddrs))
1461 {
1462 /* double registration not allowed */
1463 GNUNET_break (0);
1464 GNUNET_SERVICE_client_drop (ch->client);
1465 return;
1466 }
1467 ch->flags = message->flags;
1468 ch->proto = message->proto;
1469 ch->num_caddrs = ntohs (message->num_addrs);
1470 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1471 struct ClientAddress);
1472 left = ntohs (message->header.size) - sizeof(*message);
1473 off = (const char *) &message[1];
1474 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1475 {
1476 const struct sockaddr *sa = (const struct sockaddr *) off;
1477 size_t alen;
1478 uint16_t port;
1479 int is_nat;
1480
1481 if (sizeof(sa_family_t) > left)
1482 {
1483 GNUNET_break (0);
1484 GNUNET_SERVICE_client_drop (ch->client);
1485 return;
1486 }
1487 is_nat = GNUNET_NO;
1488 switch (sa->sa_family)
1489 {
1490 case AF_INET:
1491 {
1492 struct sockaddr_in s4;
1493
1494 GNUNET_memcpy (&s4,
1495 off,
1496 sizeof(struct sockaddr_in));
1497 alen = sizeof(struct sockaddr_in);
1498 if (is_nat_v4 (&s4.sin_addr))
1499 is_nat = GNUNET_YES;
1500 port = ntohs (s4.sin_port);
1501 }
1502 break;
1503
1504 case AF_INET6:
1505 {
1506 struct sockaddr_in6 s6;
1507
1508 GNUNET_memcpy (&s6,
1509 off,
1510 sizeof(struct sockaddr_in6));
1511 alen = sizeof(struct sockaddr_in6);
1512 if (is_nat_v6 (&s6.sin6_addr))
1513 is_nat = GNUNET_YES;
1514 port = ntohs (s6.sin6_port);
1515 }
1516 break;
1517
1518#if AF_UNIX
1519 case AF_UNIX:
1520 alen = sizeof(struct sockaddr_un);
1521 port = 0;
1522 break;
1523#endif
1524 default:
1525 GNUNET_break (0);
1526 GNUNET_SERVICE_client_drop (ch->client);
1527 return;
1528 }
1529 /* store address */
1530 GNUNET_assert (alen <= left);
1531 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1532 GNUNET_memcpy (&ch->caddrs[i].ss,
1533 off,
1534 alen);
1535
1536 /* If applicable, try UPNPC NAT punching */
1537 if ((is_nat) &&
1538 (enable_upnp) &&
1539 ((IPPROTO_TCP == ch->proto) ||
1540 (IPPROTO_UDP == ch->proto)))
1541 {
1542 ch->natted_address = GNUNET_YES;
1543 ch->caddrs[i].mh
1544 = GNUNET_NAT_mini_map_start (port,
1545 IPPROTO_TCP == ch->proto,
1546 &upnp_addr_change_cb,
1547 ch);
1548 }
1549
1550 off += alen;
1551 }
1552
1553 ch->section_name
1554 = GNUNET_strndup (off,
1555 ntohs (message->str_len));
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Received REGISTER message from client for subsystem `%s'\n",
1558 ch->section_name);
1559 if (GNUNET_OK ==
1560 GNUNET_CONFIGURATION_get_value_string (cfg,
1561 ch->section_name,
1562 "HOLE_EXTERNAL",
1563 &ch->hole_external))
1564 lookup_hole_external (ch);
1565
1566 /* Actually send IP address list to client */
1567 for (struct LocalAddressList *lal = lal_head;
1568 NULL != lal;
1569 lal = lal->next)
1570 {
1571 check_notify_client (lal,
1572 ch,
1573 GNUNET_YES);
1574 }
1575 /* Also consider IPv4 determined by `external-ip` */
1576 ch->external_monitor
1577 = GN_external_ipv4_monitor_start (&notify_client_external_ipv4_change,
1578 ch);
1579 GNUNET_SERVICE_client_continue (ch->client);
1580}
1581
1582
1583/**
1584 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1585 * client.
1586 *
1587 * @param cls client who sent the message
1588 * @param message the message received
1589 * @return #GNUNET_OK if message is well-formed
1590 */
1591static int
1592check_stun (void *cls,
1593 const struct GNUNET_NAT_HandleStunMessage *message)
1594{
1595 size_t sa_len = ntohs (message->sender_addr_size);
1596 size_t expect = sa_len + ntohs (message->payload_size);
1597
1598 if (ntohs (message->header.size) - sizeof(*message) != expect)
1599 {
1600 GNUNET_break (0);
1601 return GNUNET_SYSERR;
1602 }
1603 if (sa_len < sizeof(sa_family_t))
1604 {
1605 GNUNET_break (0);
1606 return GNUNET_SYSERR;
1607 }
1608 return GNUNET_OK;
1609}
1610
1611
1612/**
1613 * Notify all clients about our external IP address
1614 * as reported by the STUN server.
1615 *
1616 * @param ip the external IP
1617 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1618 */
1619static void
1620notify_clients_stun_change (const struct sockaddr_in *ip,
1621 int add)
1622{
1623 for (struct ClientHandle *ch = ch_head;
1624 NULL != ch;
1625 ch = ch->next)
1626 {
1627 struct sockaddr_in v4;
1628 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1629 struct GNUNET_MQ_Envelope *env;
1630
1631 if (! ch->natted_address)
1632 continue;
1633 v4 = *ip;
1634 v4.sin_port = htons (0);
1635 env = GNUNET_MQ_msg_extra (msg,
1636 sizeof(v4),
1637 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1638 msg->add_remove = htonl ((int32_t) add);
1639 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1640 | GNUNET_NAT_AC_GLOBAL);
1641 GNUNET_memcpy (&msg[1],
1642 &v4,
1643 sizeof(v4));
1644 GNUNET_MQ_send (ch->mq,
1645 env);
1646 }
1647}
1648
1649
1650/**
1651 * Function to be called when we decide that an
1652 * external IP address as told to us by a STUN
1653 * server has gone stale.
1654 *
1655 * @param cls the `struct StunExternalIP` to drop
1656 */
1657static void
1658stun_ip_timeout (void *cls)
1659{
1660 struct StunExternalIP *se = cls;
1661
1662 se->timeout_task = NULL;
1663 notify_clients_stun_change (&se->external_addr,
1664 GNUNET_NO);
1665 GNUNET_CONTAINER_DLL_remove (se_head,
1666 se_tail,
1667 se);
1668 GNUNET_free (se);
1669}
1670
1671
1672/**
1673 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1674 * client.
1675 *
1676 * @param cls client who sent the message
1677 * @param message the message received
1678 */
1679static void
1680handle_stun (void *cls,
1681 const struct GNUNET_NAT_HandleStunMessage *message)
1682{
1683 struct ClientHandle *ch = cls;
1684 const char *buf = (const char *) &message[1];
1685 const struct sockaddr *sa;
1686 const void *payload;
1687 size_t sa_len;
1688 size_t payload_size;
1689 struct sockaddr_in external_addr;
1690
1691 sa_len = ntohs (message->sender_addr_size);
1692 payload_size = ntohs (message->payload_size);
1693 sa = (const struct sockaddr *) &buf[0];
1694 payload = (const struct sockaddr *) &buf[sa_len];
1695 switch (sa->sa_family)
1696 {
1697 case AF_INET:
1698 if (sa_len != sizeof(struct sockaddr_in))
1699 {
1700 GNUNET_break (0);
1701 GNUNET_SERVICE_client_drop (ch->client);
1702 return;
1703 }
1704 break;
1705
1706 case AF_INET6:
1707 if (sa_len != sizeof(struct sockaddr_in6))
1708 {
1709 GNUNET_break (0);
1710 GNUNET_SERVICE_client_drop (ch->client);
1711 return;
1712 }
1713 break;
1714 }
1715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1716 "Received HANDLE_STUN message from client\n");
1717 if (GNUNET_OK ==
1718 GNUNET_NAT_stun_handle_packet_ (payload,
1719 payload_size,
1720 &external_addr))
1721 {
1722 /* We now know that a server at "sa" claims that
1723 we are visible at IP "external_addr".
1724
1725 We should (for some fixed period of time) tell
1726 all of our clients that listen to a NAT'ed address
1727 that they might want to consider the given 'external_ip'
1728 as their public IP address (this includes TCP and UDP
1729 clients, even if only UDP sends STUN requests).
1730
1731 If we do not get a renewal, the "external_addr" should be
1732 removed again. The timeout frequency should be configurable
1733 (with a sane default), so that the UDP plugin can tell how
1734 often to re-request STUN.
1735 */struct StunExternalIP *se;
1736
1737 /* Check if we had a prior response from this STUN server */
1738 for (se = se_head; NULL != se; se = se->next)
1739 {
1740 if ((se->stun_server_addr_len != sa_len) ||
1741 (0 != memcmp (sa,
1742 &se->stun_server_addr,
1743 sa_len)))
1744 continue; /* different STUN server */
1745 if (0 != GNUNET_memcmp (&external_addr,
1746 &se->external_addr))
1747 {
1748 /* external IP changed, update! */
1749 notify_clients_stun_change (&se->external_addr,
1750 GNUNET_NO);
1751 se->external_addr = external_addr;
1752 notify_clients_stun_change (&se->external_addr,
1753 GNUNET_YES);
1754 }
1755 /* update timeout */
1756 GNUNET_SCHEDULER_cancel (se->timeout_task);
1757 se->timeout_task
1758 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1759 &stun_ip_timeout,
1760 se);
1761 return;
1762 }
1763 /* STUN server is completely new, create fresh entry */
1764 se = GNUNET_new (struct StunExternalIP);
1765 se->external_addr = external_addr;
1766 GNUNET_memcpy (&se->stun_server_addr,
1767 sa,
1768 sa_len);
1769 se->stun_server_addr_len = sa_len;
1770 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1771 &stun_ip_timeout,
1772 se);
1773 GNUNET_CONTAINER_DLL_insert (se_head,
1774 se_tail,
1775 se);
1776 notify_clients_stun_change (&se->external_addr,
1777 GNUNET_NO);
1778 }
1779 GNUNET_SERVICE_client_continue (ch->client);
1780}
1781
1782
1783/**
1784 * Check validity of
1785 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1786 * client.
1787 *
1788 * @param cls client who sent the message
1789 * @param message the message received
1790 * @return #GNUNET_OK if message is well-formed
1791 */
1792static int
1793check_request_connection_reversal (void *cls,
1794 const struct
1795 GNUNET_NAT_RequestConnectionReversalMessage *
1796 message)
1797{
1798 size_t expect;
1799
1800 expect = ntohs (message->local_addr_size)
1801 + ntohs (message->remote_addr_size);
1802 if (ntohs (message->header.size) - sizeof(*message) != expect)
1803 {
1804 GNUNET_break (0);
1805 return GNUNET_SYSERR;
1806 }
1807 return GNUNET_OK;
1808}
1809
1810
1811/**
1812 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1813 * message from client.
1814 *
1815 * @param cls client who sent the message
1816 * @param message the message received
1817 */
1818static void
1819handle_request_connection_reversal (void *cls,
1820 const struct
1821 GNUNET_NAT_RequestConnectionReversalMessage
1822 *message)
1823{
1824 struct ClientHandle *ch = cls;
1825 const char *buf = (const char *) &message[1];
1826 size_t local_sa_len = ntohs (message->local_addr_size);
1827 size_t remote_sa_len = ntohs (message->remote_addr_size);
1828 struct sockaddr_in l4;
1829 struct sockaddr_in r4;
1830 int ret;
1831
1832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833 "Received REQUEST CONNECTION REVERSAL message from client\n");
1834 if (local_sa_len != sizeof(struct sockaddr_in))
1835 {
1836 GNUNET_break_op (0);
1837 GNUNET_SERVICE_client_drop (ch->client);
1838 return;
1839 }
1840 if (remote_sa_len != sizeof(struct sockaddr_in))
1841 {
1842 GNUNET_break_op (0);
1843 GNUNET_SERVICE_client_drop (ch->client);
1844 return;
1845 }
1846 GNUNET_memcpy (&l4,
1847 buf,
1848 sizeof(struct sockaddr_in));
1849 GNUNET_break_op (AF_INET == l4.sin_family);
1850 buf += sizeof(struct sockaddr_in);
1851 GNUNET_memcpy (&r4,
1852 buf,
1853 sizeof(struct sockaddr_in));
1854 GNUNET_break_op (AF_INET == r4.sin_family);
1855 ret = GN_request_connection_reversal (&l4.sin_addr,
1856 ntohs (l4.sin_port),
1857 &r4.sin_addr,
1858 cfg);
1859 if (GNUNET_OK != ret)
1860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1861 _ ("Connection reversal request failed\n"));
1862 GNUNET_SERVICE_client_continue (ch->client);
1863}
1864
1865
1866/**
1867 * Task run during shutdown.
1868 *
1869 * @param cls unused
1870 */
1871static void
1872shutdown_task (void *cls)
1873{
1874 struct StunExternalIP *se;
1875
1876 while (NULL != (se = se_head))
1877 {
1878 GNUNET_CONTAINER_DLL_remove (se_head,
1879 se_tail,
1880 se);
1881 GNUNET_SCHEDULER_cancel (se->timeout_task);
1882 GNUNET_free (se);
1883 }
1884 GN_nat_status_changed (GNUNET_NO);
1885 if (NULL != scan_task)
1886 {
1887 GNUNET_SCHEDULER_cancel (scan_task);
1888 scan_task = NULL;
1889 }
1890 if (NULL != stats)
1891 {
1892 GNUNET_STATISTICS_destroy (stats,
1893 GNUNET_NO);
1894 stats = NULL;
1895 }
1896 destroy_lal ();
1897}
1898
1899
1900/**
1901 * Setup NAT service.
1902 *
1903 * @param cls closure
1904 * @param c configuration to use
1905 * @param service the initialized service
1906 */
1907static void
1908run (void *cls,
1909 const struct GNUNET_CONFIGURATION_Handle *c,
1910 struct GNUNET_SERVICE_Handle *service)
1911{
1912 cfg = c;
1913 if (GNUNET_OK !=
1914 GNUNET_CONFIGURATION_get_value_time (cfg,
1915 "NAT",
1916 "STUN_STALE",
1917 &stun_stale_timeout))
1918 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1919
1920 /* Check for UPnP */
1921 enable_upnp
1922 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1923 "NAT",
1924 "ENABLE_UPNP");
1925 if (GNUNET_YES == enable_upnp)
1926 {
1927 /* check if it works */
1928 if (GNUNET_SYSERR ==
1929 GNUNET_OS_check_helper_binary ("upnpc",
1930 GNUNET_NO,
1931 NULL))
1932 {
1933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1934 _ (
1935 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1936 enable_upnp = GNUNET_SYSERR;
1937 }
1938 }
1939 if (GNUNET_OK !=
1940 GNUNET_CONFIGURATION_get_value_time (cfg,
1941 "nat",
1942 "DYNDNS_FREQUENCY",
1943 &dyndns_frequency))
1944 dyndns_frequency = DYNDNS_FREQUENCY;
1945
1946 enable_ipscan
1947 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1948 "NAT",
1949 "ENABLE_IPSCAN");
1950
1951 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1952 NULL);
1953 stats = GNUNET_STATISTICS_create ("nat",
1954 cfg);
1955 if (GNUNET_YES == enable_ipscan)
1956 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1957 NULL);
1958}
1959
1960
1961/**
1962 * Callback called when a client connects to the service.
1963 *
1964 * @param cls closure for the service
1965 * @param c the new client that connected to the service
1966 * @param mq the message queue used to send messages to the client
1967 * @return a `struct ClientHandle`
1968 */
1969static void *
1970client_connect_cb (void *cls,
1971 struct GNUNET_SERVICE_Client *c,
1972 struct GNUNET_MQ_Handle *mq)
1973{
1974 struct ClientHandle *ch;
1975
1976 ch = GNUNET_new (struct ClientHandle);
1977 ch->mq = mq;
1978 ch->client = c;
1979 GNUNET_CONTAINER_DLL_insert (ch_head,
1980 ch_tail,
1981 ch);
1982 return ch;
1983}
1984
1985
1986/**
1987 * Callback called when a client disconnected from the service
1988 *
1989 * @param cls closure for the service
1990 * @param c the client that disconnected
1991 * @param internal_cls a `struct ClientHandle *`
1992 */
1993static void
1994client_disconnect_cb (void *cls,
1995 struct GNUNET_SERVICE_Client *c,
1996 void *internal_cls)
1997{
1998 struct ClientHandle *ch = internal_cls;
1999 struct LocalAddressList *lal;
2000
2001 GNUNET_CONTAINER_DLL_remove (ch_head,
2002 ch_tail,
2003 ch);
2004 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2005 {
2006 if (NULL != ch->caddrs[i].mh)
2007 {
2008 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2009 ch->caddrs[i].mh = NULL;
2010 }
2011 }
2012 GNUNET_free (ch->caddrs);
2013 while (NULL != (lal = ch->ext_addr_head))
2014 {
2015 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2016 ch->ext_addr_tail,
2017 lal);
2018 GNUNET_free (lal);
2019 }
2020 if (NULL != ch->ext_dns_task)
2021 {
2022 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2023 ch->ext_dns_task = NULL;
2024 }
2025 if (NULL != ch->external_monitor)
2026 {
2027 GN_external_ipv4_monitor_stop (ch->external_monitor);
2028 ch->external_monitor = NULL;
2029 }
2030 if (NULL != ch->ext_dns)
2031 {
2032 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2033 ch->ext_dns = NULL;
2034 }
2035 GNUNET_free (ch->hole_external);
2036 GNUNET_free (ch->section_name);
2037 GNUNET_free (ch);
2038}
2039
2040
2041/**
2042 * Define "main" method using service macro.
2043 */
2044GNUNET_SERVICE_MAIN
2045 ("nat",
2046 GNUNET_SERVICE_OPTION_NONE,
2047 &run,
2048 &client_connect_cb,
2049 &client_disconnect_cb,
2050 NULL,
2051 GNUNET_MQ_hd_var_size (register,
2052 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2053 struct GNUNET_NAT_RegisterMessage,
2054 NULL),
2055 GNUNET_MQ_hd_var_size (stun,
2056 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2057 struct GNUNET_NAT_HandleStunMessage,
2058 NULL),
2059 GNUNET_MQ_hd_var_size (request_connection_reversal,
2060 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2061 struct GNUNET_NAT_RequestConnectionReversalMessage,
2062 NULL),
2063 GNUNET_MQ_handler_end ());
2064
2065
2066#if defined(__linux__) && defined(__GLIBC__)
2067#include <malloc.h>
2068
2069/**
2070 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2071 */
2072void __attribute__ ((constructor))
2073GNUNET_ARM_memory_init ()
2074{
2075 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2076 mallopt (M_TOP_PAD, 1 * 1024);
2077 malloc_trim (0);
2078}
2079
2080
2081#endif
2082
2083/* end of gnunet-service-nat.c */