2 This file is part of GNUnet.
3 Copyright (C) 2016, 2017 GNUnet e.V.
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.
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.
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.
22 * @file nat/gnunet-service-nat.c
23 * @brief network address translation traversal service
24 * @author Christian Grothoff
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.
31 * - test and document (!) ICMP based NAT traversal
32 * - implement manual hole punching support (AUTO missing)
33 * - test manual hole punching support
34 * - implement "more" autoconfig:
35 * + consider moving autoconfig-logic into separate service!
36 * + re-work gnunet-nat-server & integrate!
37 * + test manually punched NAT (how?)
38 * - implement & test STUN processing to classify NAT;
39 * basically, open port & try different methods.
43 #include "gnunet_util_lib.h"
44 #include "gnunet_protocols.h"
45 #include "gnunet_signatures.h"
46 #include "gnunet_statistics_service.h"
47 #include "gnunet_resolver_service.h"
48 #include "gnunet_nat_service.h"
49 #include "gnunet-service-nat.h"
50 #include "gnunet-service-nat_externalip.h"
51 #include "gnunet-service-nat_stun.h"
52 #include "gnunet-service-nat_mini.h"
53 #include "gnunet-service-nat_helper.h"
59 * How often should we ask the OS about a list of active
62 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
65 * How long do we wait until we forcefully terminate autoconfiguration?
67 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
70 * How often do we scan for changes in how our external (dyndns) hostname resolves?
72 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
76 * Information we track per client address.
81 * Network address used by the client.
83 struct sockaddr_storage ss;
86 * Handle to active UPnP request where we asked upnpc to open
87 * a port at the NAT. NULL if we do not have such a request
90 struct GNUNET_NAT_MiniHandle *mh;
96 * List of local addresses this system has.
98 struct LocalAddressList
101 * This is a linked list.
103 struct LocalAddressList *next;
108 struct LocalAddressList *prev;
111 * Context for a gnunet-helper-nat-server used to listen
112 * for ICMP messages to this client for connection reversal.
114 struct HelperContext *hc;
117 * The address itself (i.e. `struct sockaddr_in` or `struct
118 * sockaddr_in6`, in the respective byte order).
120 struct sockaddr_storage addr;
123 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
128 * #GNUNET_YES if we saw this one in the previous iteration,
129 * but not in the current iteration and thus might need to
130 * remove it at the end.
135 * What type of address is this?
137 enum GNUNET_NAT_AddressClass ac;
143 * Internal data structure we track for each of our clients.
151 struct ClientHandle *next;
156 struct ClientHandle *prev;
159 * Underlying handle for this client with the service.
161 struct GNUNET_SERVICE_Client *client;
164 * Message queue for communicating with the client.
166 struct GNUNET_MQ_Handle *mq;
169 * Array of addresses used by the service.
171 struct ClientAddress *caddrs;
174 * External DNS name and port given by user due to manual
175 * hole punching. Special DNS name 'AUTO' is used to indicate
176 * desire for automatic determination of the external IP
177 * (instead of DNS or manual configuration, i.e. to be used
178 * if the IP keeps changing and we have no DynDNS, but we do
179 * have a hole punched).
184 * Task for periodically re-running the @e ext_dns DNS lookup.
186 struct GNUNET_SCHEDULER_Task *ext_dns_task;
189 * Handle for (DYN)DNS lookup of our external IP as given in
192 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
195 * Handle for monitoring external IP changes.
197 struct GN_ExternalIPMonitor *external_monitor;
200 * DLL of external IP addresses as given in @e hole_external.
202 struct LocalAddressList *ext_addr_head;
205 * DLL of external IP addresses as given in @e hole_external.
207 struct LocalAddressList *ext_addr_tail;
210 * Port number we found in @e hole_external.
212 uint16_t ext_dns_port;
215 * What does this client care about?
217 enum GNUNET_NAT_RegisterFlags flags;
220 * Is any of the @e caddrs in a reserved subnet for NAT?
225 * Number of addresses that this service is bound to.
226 * Length of the @e caddrs array.
231 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
239 * External IP address as given to us via some STUN server.
241 struct StunExternalIP
246 struct StunExternalIP *next;
251 struct StunExternalIP *prev;
254 * Task we run to remove this entry when it is stale.
256 struct GNUNET_SCHEDULER_Task *timeout_task;
259 * Our external IP address as reported by the
262 struct sockaddr_in external_addr;
265 * Address of the reporting STUN server. Used to
266 * detect when a STUN server changes its opinion
267 * to more quickly remove stale results.
269 struct sockaddr_storage stun_server_addr;
272 * Number of bytes used in @e stun_server_addr.
274 size_t stun_server_addr_len;
279 * Context for autoconfiguration operations.
281 struct AutoconfigContext
286 struct AutoconfigContext *prev;
291 struct AutoconfigContext *next;
294 * Which client asked the question.
296 struct ClientHandle *ch;
299 * Configuration we are creating.
301 struct GNUNET_CONFIGURATION_Handle *c;
304 * Original configuration (for diffing).
306 struct GNUNET_CONFIGURATION_Handle *orig;
309 * Timeout task to force termination.
311 struct GNUNET_SCHEDULER_Task *timeout_task;
314 * What type of system are we on?
319 * Handle to activity to probe for our external IP.
321 struct GNUNET_NAT_ExternalHandle *probe_external;
324 * #GNUNET_YES if upnpc should be used,
325 * #GNUNET_NO if upnpc should not be used,
326 * #GNUNET_SYSERR if we should simply not change the option.
331 * Status code to return to the client.
333 enum GNUNET_NAT_StatusCode status_code;
336 * NAT type to return to the client.
338 enum GNUNET_NAT_Type type;
343 * DLL of our autoconfiguration operations.
345 static struct AutoconfigContext *ac_head;
348 * DLL of our autoconfiguration operations.
350 static struct AutoconfigContext *ac_tail;
353 * Timeout to use when STUN data is considered stale.
355 static struct GNUNET_TIME_Relative stun_stale_timeout;
358 * How often do we scan for changes in how our external (dyndns) hostname resolves?
360 static struct GNUNET_TIME_Relative dyndns_frequency;
363 * Handle to our current configuration.
365 static const struct GNUNET_CONFIGURATION_Handle *cfg;
368 * Handle to the statistics service.
370 static struct GNUNET_STATISTICS_Handle *stats;
373 * Task scheduled to periodically scan our network interfaces.
375 static struct GNUNET_SCHEDULER_Task *scan_task;
378 * Head of client DLL.
380 static struct ClientHandle *ch_head;
383 * Tail of client DLL.
385 static struct ClientHandle *ch_tail;
388 * Head of DLL of local addresses.
390 static struct LocalAddressList *lal_head;
393 * Tail of DLL of local addresses.
395 static struct LocalAddressList *lal_tail;
400 static struct StunExternalIP *se_head;
405 static struct StunExternalIP *se_tail;
408 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
409 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
415 * Remove and free an entry from the #lal_head DLL.
417 * @param lal entry to free
420 free_lal (struct LocalAddressList *lal)
422 GNUNET_CONTAINER_DLL_remove (lal_head,
427 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
428 "Lost NATed local address %s, stopping NAT server\n",
429 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
430 sizeof (struct sockaddr_in)));
432 GN_stop_gnunet_nat_server_ (lal->hc);
440 * Free the DLL starting at #lal_head.
445 struct LocalAddressList *lal;
447 while (NULL != (lal = lal_head))
453 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
456 * @param cls client who sent the message
457 * @param message the message received
458 * @return #GNUNET_OK if message is well-formed
461 check_register (void *cls,
462 const struct GNUNET_NAT_RegisterMessage *message)
464 uint16_t num_addrs = ntohs (message->num_addrs);
465 const char *off = (const char *) &message[1];
466 size_t left = ntohs (message->header.size) - sizeof (*message);
468 for (unsigned int i=0;i<num_addrs;i++)
471 const struct sockaddr *sa = (const struct sockaddr *) off;
473 if (sizeof (sa_family_t) > left)
476 return GNUNET_SYSERR;
478 switch (sa->sa_family)
481 alen = sizeof (struct sockaddr_in);
484 alen = sizeof (struct sockaddr_in6);
488 alen = sizeof (struct sockaddr_un);
493 return GNUNET_SYSERR;
498 return GNUNET_SYSERR;
503 if (left != ntohs (message->hole_external_len))
506 return GNUNET_SYSERR;
513 * Check if @a ip is in @a network with @a bits netmask.
515 * @param network to test
516 * @param ip IP address to test
517 * @param bits bitmask for the network
518 * @return #GNUNET_YES if @a ip is in @a network
521 match_ipv4 (const char *network,
522 const struct in_addr *ip,
531 GNUNET_assert (1 == inet_pton (AF_INET,
534 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
539 * Check if @a ip is in @a network with @a bits netmask.
541 * @param network to test
542 * @param ip IP address to test
543 * @param bits bitmask for the network
544 * @return #GNUNET_YES if @a ip is in @a network
547 match_ipv6 (const char *network,
548 const struct in6_addr *ip,
552 struct in6_addr mask;
557 GNUNET_assert (1 == inet_pton (AF_INET6,
560 memset (&mask, 0, sizeof (mask));
561 if (0 == memcmp (&mask,
568 mask.s6_addr[off++] = 0xFF;
573 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
576 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
577 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
578 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
585 * Test if the given IPv4 address is in a known range
586 * for private networks.
588 * @param ip address to test
589 * @return #GNUNET_YES if @a ip is in a NAT range
592 is_nat_v4 (const struct in_addr *ip)
595 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
596 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
597 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
598 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
599 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
604 * Test if the given IPv6 address is in a known range
605 * for private networks.
607 * @param ip address to test
608 * @return #GNUNET_YES if @a ip is in a NAT range
611 is_nat_v6 (const struct in6_addr *ip)
614 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
615 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
616 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
621 * Closure for #ifc_proc.
623 struct IfcProcContext
627 * Head of DLL of local addresses.
629 struct LocalAddressList *lal_head;
632 * Tail of DLL of local addresses.
634 struct LocalAddressList *lal_tail;
640 * Callback function invoked for each interface found. Adds them
641 * to our new address list.
643 * @param cls a `struct IfcProcContext *`
644 * @param name name of the interface (can be NULL for unknown)
645 * @param isDefault is this presumably the default interface
646 * @param addr address of this interface (can be NULL for unknown or unassigned)
647 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
648 * @param netmask the network mask (can be NULL for unknown or unassigned)
649 * @param addrlen length of the address
650 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
656 const struct sockaddr *addr,
657 const struct sockaddr *broadcast_addr,
658 const struct sockaddr *netmask,
661 struct IfcProcContext *ifc_ctx = cls;
662 struct LocalAddressList *lal;
664 const struct in_addr *ip4;
665 const struct in6_addr *ip6;
666 enum GNUNET_NAT_AddressClass ac;
668 switch (addr->sa_family)
671 alen = sizeof (struct sockaddr_in);
672 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
673 if (match_ipv4 ("127.0.0.0", ip4, 8))
674 ac = GNUNET_NAT_AC_LOOPBACK;
675 else if (is_nat_v4 (ip4))
676 ac = GNUNET_NAT_AC_LAN;
678 ac = GNUNET_NAT_AC_GLOBAL;
681 alen = sizeof (struct sockaddr_in6);
682 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
683 if (match_ipv6 ("::1", ip6, 128))
684 ac = GNUNET_NAT_AC_LOOPBACK;
685 else if (is_nat_v6 (ip6))
686 ac = GNUNET_NAT_AC_LAN;
688 ac = GNUNET_NAT_AC_GLOBAL;
689 if ( (ip6->s6_addr[11] == 0xFF) &&
690 (ip6->s6_addr[12] == 0xFE) )
692 /* contains a MAC, be extra careful! */
693 ac |= GNUNET_NAT_AC_PRIVATE;
705 lal = GNUNET_malloc (sizeof (*lal));
706 lal->af = addr->sa_family;
708 GNUNET_memcpy (&lal->addr,
711 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
719 * Notify client about a change in the list of addresses this peer
722 * @param ac address class of the entry in the list that changed
723 * @param ch client to contact
724 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
725 * @param addr the address that changed
726 * @param addr_len number of bytes in @a addr
729 notify_client (enum GNUNET_NAT_AddressClass ac,
730 struct ClientHandle *ch,
735 struct GNUNET_MQ_Envelope *env;
736 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
738 env = GNUNET_MQ_msg_extra (msg,
740 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
741 msg->add_remove = htonl (add);
742 msg->addr_class = htonl (ac);
743 GNUNET_memcpy (&msg[1],
746 GNUNET_MQ_send (ch->mq,
752 * Check if we should bother to notify this client about this
753 * address change, and if so, do it.
755 * @param delta the entry in the list that changed
756 * @param ch client to check
757 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
760 check_notify_client (struct LocalAddressList *delta,
761 struct ClientHandle *ch,
765 struct sockaddr_in v4;
766 struct sockaddr_in6 v6;
768 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
773 alen = sizeof (struct sockaddr_in);
778 /* Check for client notifications */
779 for (unsigned int i=0;i<ch->num_caddrs;i++)
781 const struct sockaddr_in *c4;
783 if (AF_INET != ch->caddrs[i].ss.ss_family)
784 continue; /* IPv4 not relevant */
785 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
786 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
787 (0 != c4->sin_addr.s_addr) &&
788 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
789 continue; /* bound to loopback, but this is not loopback */
790 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
791 (0 != c4->sin_addr.s_addr) &&
792 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
793 continue; /* bound to non-loopback, but this is loopback */
794 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
795 (0 != c4->sin_addr.s_addr) &&
796 (! is_nat_v4 (&v4.sin_addr)) )
797 continue; /* based on external-IP, but this IP is not
798 from private address range. */
799 if ( (0 != memcmp (&v4.sin_addr,
801 sizeof (struct in_addr))) &&
802 (0 != c4->sin_addr.s_addr) &&
803 ( (! is_nat_v4 (&c4->sin_addr)) ||
804 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
805 continue; /* this IP is not from private address range,
806 and IP does not match. */
808 /* OK, IP seems relevant, notify client */
809 v4.sin_port = c4->sin_port;
810 notify_client (delta->ac,
818 alen = sizeof (struct sockaddr_in6);
822 for (unsigned int i=0;i<ch->num_caddrs;i++)
824 const struct sockaddr_in6 *c6;
826 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
827 continue; /* IPv4 not relevant */
828 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
829 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
830 (0 != memcmp (&c6->sin6_addr,
832 sizeof (struct in6_addr))) &&
833 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
834 continue; /* bound to loopback, but this is not loopback */
835 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
836 (0 != memcmp (&c6->sin6_addr,
838 sizeof (struct in6_addr))) &&
839 match_ipv6 ("::1", &v6.sin6_addr, 128) )
840 continue; /* bound to non-loopback, but this is loopback */
841 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
842 (0 != memcmp (&c6->sin6_addr,
844 sizeof (struct in6_addr))) &&
845 (! is_nat_v6 (&v6.sin6_addr)) )
846 continue; /* based on external-IP, but this IP is not
847 from private address range. */
848 if ( (0 != memcmp (&v6.sin6_addr,
850 sizeof (struct in6_addr))) &&
851 (0 != memcmp (&c6->sin6_addr,
853 sizeof (struct in6_addr))) &&
854 (! is_nat_v6 (&c6->sin6_addr)) )
855 continue; /* this IP is not from private address range,
856 and IP does not match. */
857 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
858 (0 != memcmp (&c6->sin6_addr,
860 sizeof (struct in6_addr))) &&
861 (0 != memcmp (&v6.sin6_addr,
863 sizeof (struct in6_addr))) &&
864 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
865 continue; /* client bound to link-local, and the other address
866 does not match and is not an external IP */
868 /* OK, IP seems relevant, notify client */
869 v6.sin6_port = c6->sin6_port;
870 notify_client (delta->ac,
885 * Notify all clients about a change in the list
886 * of addresses this peer has.
888 * @param delta the entry in the list that changed
889 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
892 notify_clients (struct LocalAddressList *delta,
895 for (struct ClientHandle *ch = ch_head;
898 check_notify_client (delta,
905 * Tell relevant client about a change in our external
908 * @param cls client to check if it cares and possibly notify
909 * @param v4 the external address that changed
910 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
913 notify_client_external_ipv4_change (void *cls,
914 const struct in_addr *v4,
917 struct ClientHandle *ch = cls;
918 struct sockaddr_in sa;
921 /* (1) check if client cares. */
922 if (! ch->natted_address)
924 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
927 for (unsigned int i=0;i<ch->num_caddrs;i++)
929 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
931 if (AF_INET != ss->ss_family)
933 have_v4 = GNUNET_YES;
936 if (GNUNET_NO == have_v4)
937 return; /* IPv6-only */
939 /* build address info */
943 sa.sin_family = AF_INET;
945 sa.sin_port = htons (0);
947 /* (3) notify client of change */
948 notify_client (is_nat_v4 (v4)
949 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
950 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
959 * We got a connection reversal request from another peer.
960 * Notify applicable clients.
962 * @param cls closure with the `struct LocalAddressList`
963 * @param ra IP address of the peer who wants us to connect to it
966 reversal_callback (void *cls,
967 const struct sockaddr_in *ra)
969 struct LocalAddressList *lal = cls;
970 const struct sockaddr_in *l4;
972 GNUNET_assert (AF_INET == lal->af);
973 l4 = (const struct sockaddr_in *) &lal->addr;
974 for (struct ClientHandle *ch = ch_head;
978 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
979 struct GNUNET_MQ_Envelope *env;
982 /* Check if client is in applicable range for ICMP NAT traversal
983 for this local address */
984 if (! ch->natted_address)
987 for (unsigned int i=0;i<ch->num_caddrs;i++)
989 struct ClientAddress *ca = &ch->caddrs[i];
990 const struct sockaddr_in *c4;
992 if (AF_INET != ca->ss.ss_family)
994 c4 = (const struct sockaddr_in *) &ca->ss;
995 if ( (0 != c4->sin_addr.s_addr) &&
996 (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
1004 /* Notify applicable client about connection reversal request */
1005 env = GNUNET_MQ_msg_extra (crrm,
1006 sizeof (struct sockaddr_in),
1007 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
1008 GNUNET_memcpy (&crrm[1],
1010 sizeof (struct sockaddr_in));
1011 GNUNET_MQ_send (ch->mq,
1018 * Task we run periodically to scan for network interfaces.
1023 run_scan (void *cls)
1025 struct IfcProcContext ifc_ctx;
1028 struct LocalAddressList *lnext;
1030 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1036 GNUNET_OS_network_interfaces_list (&ifc_proc,
1038 /* remove addresses that disappeared */
1039 for (struct LocalAddressList *lal = lal_head;
1045 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1049 if ( (pos->af == lal->af) &&
1050 (0 == memcmp (&lal->addr,
1052 (AF_INET == lal->af)
1053 ? sizeof (struct sockaddr_in)
1054 : sizeof (struct sockaddr_in6))) )
1059 if (GNUNET_NO == found)
1061 notify_clients (lal,
1067 /* add addresses that appeared */
1068 have_nat = GNUNET_NO;
1069 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1071 pos = ifc_ctx.lal_head)
1074 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1075 have_nat = GNUNET_YES;
1076 for (struct LocalAddressList *lal = lal_head;
1080 if ( (pos->af == lal->af) &&
1081 (0 == memcmp (&lal->addr,
1083 (AF_INET == lal->af)
1084 ? sizeof (struct sockaddr_in)
1085 : sizeof (struct sockaddr_in6))) )
1088 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1091 if (GNUNET_YES == found)
1097 notify_clients (pos,
1099 GNUNET_CONTAINER_DLL_insert (lal_head,
1102 if ( (AF_INET == pos->af) &&
1103 (NULL == pos->hc) &&
1104 (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1106 const struct sockaddr_in *s4
1107 = (const struct sockaddr_in *) &pos->addr;
1109 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1110 "Found NATed local address %s, starting NAT server\n",
1111 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
1112 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1118 GN_nat_status_changed (have_nat);
1123 * Function called whenever our set of external addresses
1124 * as created by `upnpc` changes.
1126 * @param cls closure with our `struct ClientHandle *`
1127 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1128 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1129 * @param addr either the previous or the new public IP address
1130 * @param addrlen actual length of the @a addr
1131 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1134 upnp_addr_change_cb (void *cls,
1136 const struct sockaddr *addr,
1138 enum GNUNET_NAT_StatusCode result)
1140 struct ClientHandle *ch = cls;
1141 enum GNUNET_NAT_AddressClass ac;
1145 case GNUNET_NAT_ERROR_SUCCESS:
1146 GNUNET_assert (NULL != addr);
1148 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1149 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1150 case GNUNET_NAT_ERROR_IPC_FAILURE:
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 "Running upnpc failed: %d\n",
1155 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1156 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1157 "external-ip binary not found\n");
1159 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1160 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1161 "external-ip binary could not be run\n");
1163 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1165 "upnpc failed to create port mapping\n");
1167 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1169 "Invalid output from upnpc\n");
1171 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1172 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1173 "Invalid address returned by upnpc\n");
1176 GNUNET_break (0); /* should not be possible */
1179 switch (addr->sa_family)
1182 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1184 : GNUNET_NAT_AC_EXTERN;
1187 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1189 : GNUNET_NAT_AC_EXTERN;
1195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1196 "upnp external address %s: %s\n",
1197 add_remove ? "added" : "removed",
1209 * Resolve the `hole_external` name to figure out our
1210 * external address from a manually punched hole. The
1211 * port number has already been parsed, this task is
1212 * responsible for periodically doing a DNS lookup.
1214 * @param ch client handle to act upon
1217 dyndns_lookup (void *cls);
1221 * Our (external) hostname was resolved. Update lists of
1222 * current external IPs (note that DNS may return multiple
1223 * addresses!) and notify client accordingly.
1225 * @param cls the `struct ClientHandle`
1226 * @param addr NULL on error, otherwise result of DNS lookup
1227 * @param addrlen number of bytes in @a addr
1230 process_external_ip (void *cls,
1231 const struct sockaddr *addr,
1234 struct ClientHandle *ch = cls;
1235 struct LocalAddressList *lal;
1236 struct sockaddr_storage ss;
1237 struct sockaddr_in *v4;
1238 struct sockaddr_in6 *v6;
1242 struct LocalAddressList *laln;
1246 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1249 /* Current iteration is over, remove 'old' IPs now */
1250 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1253 if (GNUNET_YES == lal->old)
1255 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1258 check_notify_client (lal,
1266 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1267 "Got IP `%s' for external address `%s'\n",
1272 /* build sockaddr storage with port number */
1273 memset (&ss, 0, sizeof (ss));
1274 memcpy (&ss, addr, addrlen);
1275 switch (addr->sa_family)
1278 v4 = (struct sockaddr_in *) &ss;
1279 v4->sin_port = htons (ch->ext_dns_port);
1282 v6 = (struct sockaddr_in6 *) &ss;
1283 v6->sin6_port = htons (ch->ext_dns_port);
1289 /* See if 'ss' matches any of our known addresses */
1290 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1292 if (GNUNET_NO == lal->old)
1293 continue; /* already processed, skip */
1294 if ( (addr->sa_family == lal->addr.ss_family) &&
1299 /* Address unchanged, remember so we do not remove */
1300 lal->old = GNUNET_NO;
1301 return; /* done here */
1304 /* notify client, and remember IP for later removal! */
1305 lal = GNUNET_new (struct LocalAddressList);
1307 lal->af = ss.ss_family;
1308 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1309 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1312 check_notify_client (lal,
1319 * Resolve the `hole_external` name to figure out our
1320 * external address from a manually punched hole. The
1321 * port number has already been parsed, this task is
1322 * responsible for periodically doing a DNS lookup.
1324 * @param ch client handle to act upon
1327 dyndns_lookup (void *cls)
1329 struct ClientHandle *ch = cls;
1330 struct LocalAddressList *lal;
1332 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1333 lal->old = GNUNET_YES;
1334 ch->ext_dns_task = NULL;
1335 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1337 GNUNET_TIME_UNIT_MINUTES,
1338 &process_external_ip,
1344 * Resolve the `hole_external` name to figure out our
1345 * external address from a manually punched hole. The
1346 * given name may be "AUTO" in which case we should use
1347 * the IP address(es) we have from upnpc or other methods.
1348 * The name can also be an IP address, in which case we
1349 * do not need to do DNS resolution. Finally, we also
1350 * need to parse the port number.
1352 * @param ch client handle to act upon
1355 lookup_hole_external (struct ClientHandle *ch)
1359 struct sockaddr_in *s4;
1360 struct LocalAddressList *lal;
1362 port = strrchr (ch->hole_external, ':');
1365 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1366 _("Malformed punched hole specification `%s' (lacks port)\n"),
1370 if ( (1 != sscanf (port + 1,
1375 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1376 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1380 ch->ext_dns_port = (uint16_t) pnum;
1383 lal = GNUNET_new (struct LocalAddressList);
1384 if ('[' == *ch->hole_external)
1386 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1388 s6->sin6_family = AF_INET6;
1389 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1391 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1392 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1397 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1398 if (1 != inet_pton (AF_INET6,
1399 ch->hole_external + 1,
1402 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1403 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1404 ch->hole_external + 1);
1408 s6->sin6_port = htons (ch->ext_dns_port);
1410 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1411 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1414 check_notify_client (lal,
1420 s4 = (struct sockaddr_in *) &lal->addr;
1421 s4->sin_family = AF_INET;
1422 if (1 == inet_pton (AF_INET,
1426 s4->sin_port = htons (ch->ext_dns_port);
1428 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1429 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1432 check_notify_client (lal,
1437 if (0 == strcasecmp (ch->hole_external,
1440 // FIXME: use `external-ip` address(es)!
1441 GNUNET_break (0); // not implemented!
1445 /* got a DNS name, trigger lookup! */
1448 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1454 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1455 * We remember the client for updates upon future NAT events.
1457 * @param cls client who sent the message
1458 * @param message the message received
1461 handle_register (void *cls,
1462 const struct GNUNET_NAT_RegisterMessage *message)
1464 struct ClientHandle *ch = cls;
1468 if ( (0 != ch->proto) ||
1469 (NULL != ch->caddrs) )
1471 /* double registration not allowed */
1473 GNUNET_SERVICE_client_drop (ch->client);
1476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1477 "Received REGISTER message from client\n");
1478 ch->flags = message->flags;
1479 ch->proto = message->proto;
1480 ch->num_caddrs = ntohs (message->num_addrs);
1481 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1482 struct ClientAddress);
1483 left = ntohs (message->header.size) - sizeof (*message);
1484 off = (const char *) &message[1];
1485 for (unsigned int i=0;i<ch->num_caddrs;i++)
1488 const struct sockaddr *sa = (const struct sockaddr *) off;
1492 if (sizeof (sa_family_t) > left)
1495 GNUNET_SERVICE_client_drop (ch->client);
1499 switch (sa->sa_family)
1503 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1505 alen = sizeof (struct sockaddr_in);
1506 if (is_nat_v4 (&s4->sin_addr))
1507 is_nat = GNUNET_YES;
1508 port = ntohs (s4->sin_port);
1513 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1515 alen = sizeof (struct sockaddr_in6);
1516 if (is_nat_v6 (&s6->sin6_addr))
1517 is_nat = GNUNET_YES;
1518 port = ntohs (s6->sin6_port);
1523 alen = sizeof (struct sockaddr_un);
1529 GNUNET_SERVICE_client_drop (ch->client);
1533 GNUNET_assert (alen <= left);
1534 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1535 GNUNET_memcpy (&ch->caddrs[i].ss,
1539 /* If applicable, try UPNPC NAT punching */
1542 ( (IPPROTO_TCP == ch->proto) ||
1543 (IPPROTO_UDP == ch->proto) ) )
1545 ch->natted_address = GNUNET_YES;
1547 = GNUNET_NAT_mini_map_start (port,
1548 IPPROTO_TCP == ch->proto,
1549 &upnp_addr_change_cb,
1557 = GNUNET_strndup (off,
1558 ntohs (message->hole_external_len));
1559 if (0 != ntohs (message->hole_external_len))
1560 lookup_hole_external (ch);
1562 /* Actually send IP address list to client */
1563 for (struct LocalAddressList *lal = lal_head;
1567 check_notify_client (lal,
1571 /* Also consider IPv4 determined by `external-ip` */
1572 ch->external_monitor
1573 = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change,
1575 GNUNET_SERVICE_client_continue (ch->client);
1580 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1583 * @param cls client who sent the message
1584 * @param message the message received
1585 * @return #GNUNET_OK if message is well-formed
1588 check_stun (void *cls,
1589 const struct GNUNET_NAT_HandleStunMessage *message)
1591 size_t sa_len = ntohs (message->sender_addr_size);
1592 size_t expect = sa_len + ntohs (message->payload_size);
1594 if (ntohs (message->header.size) - sizeof (*message) != expect)
1597 return GNUNET_SYSERR;
1599 if (sa_len < sizeof (sa_family_t))
1602 return GNUNET_SYSERR;
1609 * Notify all clients about our external IP address
1610 * as reported by the STUN server.
1612 * @param ip the external IP
1613 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1616 notify_clients_stun_change (const struct sockaddr_in *ip,
1619 for (struct ClientHandle *ch = ch_head;
1623 struct sockaddr_in v4;
1624 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1625 struct GNUNET_MQ_Envelope *env;
1627 if (! ch->natted_address)
1630 v4.sin_port = htons (0);
1631 env = GNUNET_MQ_msg_extra (msg,
1633 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1634 msg->add_remove = htonl ((int32_t) add);
1635 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1636 GNUNET_NAT_AC_GLOBAL);
1637 GNUNET_memcpy (&msg[1],
1640 GNUNET_MQ_send (ch->mq,
1647 * Function to be called when we decide that an
1648 * external IP address as told to us by a STUN
1649 * server has gone stale.
1651 * @param cls the `struct StunExternalIP` to drop
1654 stun_ip_timeout (void *cls)
1656 struct StunExternalIP *se = cls;
1658 se->timeout_task = NULL;
1659 notify_clients_stun_change (&se->external_addr,
1661 GNUNET_CONTAINER_DLL_remove (se_head,
1669 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1672 * @param cls client who sent the message
1673 * @param message the message received
1676 handle_stun (void *cls,
1677 const struct GNUNET_NAT_HandleStunMessage *message)
1679 struct ClientHandle *ch = cls;
1680 const char *buf = (const char *) &message[1];
1681 const struct sockaddr *sa;
1682 const void *payload;
1684 size_t payload_size;
1685 struct sockaddr_in external_addr;
1687 sa_len = ntohs (message->sender_addr_size);
1688 payload_size = ntohs (message->payload_size);
1689 sa = (const struct sockaddr *) &buf[0];
1690 payload = (const struct sockaddr *) &buf[sa_len];
1691 switch (sa->sa_family)
1694 if (sa_len != sizeof (struct sockaddr_in))
1697 GNUNET_SERVICE_client_drop (ch->client);
1702 if (sa_len != sizeof (struct sockaddr_in6))
1705 GNUNET_SERVICE_client_drop (ch->client);
1710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711 "Received HANDLE_STUN message from client\n");
1713 GNUNET_NAT_stun_handle_packet_ (payload,
1717 /* We now know that a server at "sa" claims that
1718 we are visible at IP "external_addr".
1720 We should (for some fixed period of time) tell
1721 all of our clients that listen to a NAT'ed address
1722 that they might want to consider the given 'external_ip'
1723 as their public IP address (this includes TCP and UDP
1724 clients, even if only UDP sends STUN requests).
1726 If we do not get a renewal, the "external_addr" should be
1727 removed again. The timeout frequency should be configurable
1728 (with a sane default), so that the UDP plugin can tell how
1729 often to re-request STUN.
1731 struct StunExternalIP *se;
1733 /* Check if we had a prior response from this STUN server */
1734 for (se = se_head; NULL != se; se = se->next)
1736 if ( (se->stun_server_addr_len != sa_len) ||
1738 &se->stun_server_addr,
1740 continue; /* different STUN server */
1741 if (0 != memcmp (&external_addr,
1743 sizeof (struct sockaddr_in)))
1745 /* external IP changed, update! */
1746 notify_clients_stun_change (&se->external_addr,
1748 se->external_addr = external_addr;
1749 notify_clients_stun_change (&se->external_addr,
1752 /* update timeout */
1753 GNUNET_SCHEDULER_cancel (se->timeout_task);
1755 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1760 /* STUN server is completely new, create fresh entry */
1761 se = GNUNET_new (struct StunExternalIP);
1762 se->external_addr = external_addr;
1763 GNUNET_memcpy (&se->stun_server_addr,
1766 se->stun_server_addr_len = sa_len;
1767 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1770 GNUNET_CONTAINER_DLL_insert (se_head,
1773 notify_clients_stun_change (&se->external_addr,
1776 GNUNET_SERVICE_client_continue (ch->client);
1782 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1785 * @param cls client who sent the message
1786 * @param message the message received
1787 * @return #GNUNET_OK if message is well-formed
1790 check_request_connection_reversal (void *cls,
1791 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1795 expect = ntohs (message->local_addr_size)
1796 + ntohs (message->remote_addr_size);
1797 if (ntohs (message->header.size) - sizeof (*message) != expect)
1800 return GNUNET_SYSERR;
1807 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1808 * message from client.
1810 * @param cls client who sent the message
1811 * @param message the message received
1814 handle_request_connection_reversal (void *cls,
1815 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1817 struct ClientHandle *ch = cls;
1818 const char *buf = (const char *) &message[1];
1819 size_t local_sa_len = ntohs (message->local_addr_size);
1820 size_t remote_sa_len = ntohs (message->remote_addr_size);
1821 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1822 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1823 const struct sockaddr_in *l4 = NULL;
1824 const struct sockaddr_in *r4;
1827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828 "Received REQUEST CONNECTION REVERSAL message from client\n");
1829 switch (local_sa->sa_family)
1832 if (local_sa_len != sizeof (struct sockaddr_in))
1835 GNUNET_SERVICE_client_drop (ch->client);
1838 l4 = (const struct sockaddr_in *) local_sa;
1841 if (local_sa_len != sizeof (struct sockaddr_in6))
1844 GNUNET_SERVICE_client_drop (ch->client);
1847 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1848 _("Connection reversal for IPv6 not supported yet\n"));
1849 ret = GNUNET_SYSERR;
1853 GNUNET_SERVICE_client_drop (ch->client);
1856 switch (remote_sa->sa_family)
1859 if (remote_sa_len != sizeof (struct sockaddr_in))
1862 GNUNET_SERVICE_client_drop (ch->client);
1865 r4 = (const struct sockaddr_in *) remote_sa;
1866 ret = GN_request_connection_reversal (&l4->sin_addr,
1867 ntohs (l4->sin_port),
1871 if (remote_sa_len != sizeof (struct sockaddr_in6))
1874 GNUNET_SERVICE_client_drop (ch->client);
1877 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1878 _("Connection reversal for IPv6 not supported yet\n"));
1879 ret = GNUNET_SYSERR;
1883 GNUNET_SERVICE_client_drop (ch->client);
1886 if (GNUNET_OK != ret)
1887 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1888 _("Connection reversal request failed\n"));
1889 GNUNET_SERVICE_client_continue (ch->client);
1894 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1897 * @param cls client who sent the message
1898 * @param message the message received
1899 * @return #GNUNET_OK if message is well-formed
1902 check_autoconfig_request (void *cls,
1903 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1905 return GNUNET_OK; /* checked later */
1910 * Stop all pending activities with respect to the @a ac
1912 * @param ac autoconfiguration to terminate activities for
1915 terminate_ac_activities (struct AutoconfigContext *ac)
1917 if (NULL != ac->probe_external)
1919 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1920 ac->probe_external = NULL;
1922 if (NULL != ac->timeout_task)
1924 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1925 ac->timeout_task = NULL;
1931 * Finish handling the autoconfiguration request and send
1932 * the response to the client.
1934 * @param cls the `struct AutoconfigContext` to conclude
1937 conclude_autoconfig_request (void *cls)
1939 struct AutoconfigContext *ac = cls;
1940 struct ClientHandle *ch = ac->ch;
1941 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1942 struct GNUNET_MQ_Envelope *env;
1945 struct GNUNET_CONFIGURATION_Handle *diff;
1947 ac->timeout_task = NULL;
1948 terminate_ac_activities (ac);
1950 /* Send back response */
1951 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1953 buf = GNUNET_CONFIGURATION_serialize (diff,
1955 GNUNET_CONFIGURATION_destroy (diff);
1956 env = GNUNET_MQ_msg_extra (arm,
1958 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1959 arm->status_code = htonl ((uint32_t) ac->status_code);
1960 arm->type = htonl ((uint32_t) ac->type);
1961 GNUNET_memcpy (&arm[1],
1965 GNUNET_MQ_send (ch->mq,
1969 GNUNET_free (ac->system_type);
1970 GNUNET_CONFIGURATION_destroy (ac->orig);
1971 GNUNET_CONFIGURATION_destroy (ac->c);
1972 GNUNET_CONTAINER_DLL_remove (ac_head,
1976 GNUNET_SERVICE_client_continue (ch->client);
1981 * Check if all autoconfiguration operations have concluded,
1982 * and if they have, send the result back to the client.
1984 * @param ac autoconfiguation context to check
1987 check_autoconfig_finished (struct AutoconfigContext *ac)
1989 if (NULL != ac->probe_external)
1991 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1993 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1999 * Update ENABLE_UPNPC configuration option.
2001 * @param ac autoconfiguration to update
2004 update_enable_upnpc_option (struct AutoconfigContext *ac)
2006 switch (ac->enable_upnpc)
2009 GNUNET_CONFIGURATION_set_value_string (ac->c,
2015 GNUNET_CONFIGURATION_set_value_string (ac->c,
2021 /* We are unsure, do not change option */
2028 * Handle result from external IP address probe during
2029 * autoconfiguration.
2031 * @param cls our `struct AutoconfigContext`
2032 * @param addr the address, NULL on errors
2033 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
2036 auto_external_result_cb (void *cls,
2037 const struct in_addr *addr,
2038 enum GNUNET_NAT_StatusCode result)
2040 struct AutoconfigContext *ac = cls;
2042 ac->probe_external = NULL;
2045 case GNUNET_NAT_ERROR_SUCCESS:
2046 ac->enable_upnpc = GNUNET_YES;
2048 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
2049 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
2050 case GNUNET_NAT_ERROR_IPC_FAILURE:
2051 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2052 "Disabling UPNPC: %d\n",
2054 ac->enable_upnpc = GNUNET_NO; /* did not work */
2057 GNUNET_break (0); /* unexpected */
2058 ac->enable_upnpc = GNUNET_SYSERR;
2061 update_enable_upnpc_option (ac);
2062 check_autoconfig_finished (ac);
2067 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
2070 * @param cls client who sent the message
2071 * @param message the message received
2074 handle_autoconfig_request (void *cls,
2075 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
2077 struct ClientHandle *ch = cls;
2078 size_t left = ntohs (message->header.size) - sizeof (*message);
2079 struct LocalAddressList *lal;
2080 struct AutoconfigContext *ac;
2082 ac = GNUNET_new (struct AutoconfigContext);
2083 ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
2085 ac->c = GNUNET_CONFIGURATION_create ();
2087 GNUNET_CONFIGURATION_deserialize (ac->c,
2088 (const char *) &message[1],
2093 GNUNET_SERVICE_client_drop (ch->client);
2094 GNUNET_CONFIGURATION_destroy (ac->c);
2098 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2099 "Received REQUEST_AUTO_CONFIG message from client\n");
2102 GNUNET_CONFIGURATION_get_value_string (ac->c,
2106 ac->system_type = GNUNET_strdup ("UNKNOWN");
2108 GNUNET_CONTAINER_DLL_insert (ac_head,
2112 = GNUNET_CONFIGURATION_dup (ac->c);
2114 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
2115 &conclude_autoconfig_request,
2117 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
2119 /* Probe for upnpc */
2120 if (GNUNET_SYSERR ==
2121 GNUNET_OS_check_helper_binary ("upnpc",
2125 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2126 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
2127 ac->enable_upnpc = GNUNET_NO;
2131 for (lal = lal_head; NULL != lal; lal = lal->next)
2132 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
2133 /* we are behind NAT, useful to try upnpc */
2134 ac->enable_upnpc = GNUNET_YES;
2136 if (GNUNET_YES == ac->enable_upnpc)
2138 /* If we are a mobile device, always leave it on as the network
2139 may change to one that supports UPnP anytime. If we are
2140 stationary, check if our network actually supports UPnP, and if
2142 if ( (0 == strcasecmp (ac->system_type,
2143 "INFRASTRUCTURE")) ||
2144 (0 == strcasecmp (ac->system_type,
2147 /* Check if upnpc gives us an external IP */
2149 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
2153 if (NULL == ac->probe_external)
2154 update_enable_upnpc_option (ac);
2156 /* Finally, check if we are already done */
2157 check_autoconfig_finished (ac);
2162 * Task run during shutdown.
2167 shutdown_task (void *cls)
2169 struct StunExternalIP *se;
2170 struct AutoconfigContext *ac;
2172 while (NULL != (ac = ac_head))
2174 GNUNET_CONTAINER_DLL_remove (ac_head,
2177 terminate_ac_activities (ac);
2180 while (NULL != (se = se_head))
2182 GNUNET_CONTAINER_DLL_remove (se_head,
2185 GNUNET_SCHEDULER_cancel (se->timeout_task);
2188 GN_nat_status_changed (GNUNET_NO);
2189 if (NULL != scan_task)
2191 GNUNET_SCHEDULER_cancel (scan_task);
2196 GNUNET_STATISTICS_destroy (stats,
2205 * Setup NAT service.
2207 * @param cls closure
2208 * @param c configuration to use
2209 * @param service the initialized service
2213 const struct GNUNET_CONFIGURATION_Handle *c,
2214 struct GNUNET_SERVICE_Handle *service)
2218 GNUNET_CONFIGURATION_get_value_time (cfg,
2221 &stun_stale_timeout))
2222 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
2224 /* Check for UPnP */
2226 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2229 if (GNUNET_YES == enable_upnp)
2231 /* check if it works */
2232 if (GNUNET_SYSERR ==
2233 GNUNET_OS_check_helper_binary ("upnpc",
2237 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2238 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2239 enable_upnp = GNUNET_SYSERR;
2243 GNUNET_CONFIGURATION_get_value_time (cfg,
2247 dyndns_frequency = DYNDNS_FREQUENCY;
2249 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2251 stats = GNUNET_STATISTICS_create ("nat",
2253 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
2259 * Callback called when a client connects to the service.
2261 * @param cls closure for the service
2262 * @param c the new client that connected to the service
2263 * @param mq the message queue used to send messages to the client
2264 * @return a `struct ClientHandle`
2267 client_connect_cb (void *cls,
2268 struct GNUNET_SERVICE_Client *c,
2269 struct GNUNET_MQ_Handle *mq)
2271 struct ClientHandle *ch;
2273 ch = GNUNET_new (struct ClientHandle);
2276 GNUNET_CONTAINER_DLL_insert (ch_head,
2284 * Callback called when a client disconnected from the service
2286 * @param cls closure for the service
2287 * @param c the client that disconnected
2288 * @param internal_cls a `struct ClientHandle *`
2291 client_disconnect_cb (void *cls,
2292 struct GNUNET_SERVICE_Client *c,
2295 struct ClientHandle *ch = internal_cls;
2296 struct LocalAddressList *lal;
2298 GNUNET_CONTAINER_DLL_remove (ch_head,
2301 for (unsigned int i=0;i<ch->num_caddrs;i++)
2303 if (NULL != ch->caddrs[i].mh)
2305 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2306 ch->caddrs[i].mh = NULL;
2309 GNUNET_free_non_null (ch->caddrs);
2310 while (NULL != (lal = ch->ext_addr_head))
2312 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2317 if (NULL != ch->ext_dns_task)
2319 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2320 ch->ext_dns_task = NULL;
2322 if (NULL != ch->external_monitor)
2324 GN_external_ipv4_monitor_stop (ch->external_monitor);
2325 ch->external_monitor = NULL;
2327 if (NULL != ch->ext_dns)
2329 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2332 GNUNET_free (ch->hole_external);
2338 * Define "main" method using service macro.
2342 GNUNET_SERVICE_OPTION_NONE,
2345 &client_disconnect_cb,
2347 GNUNET_MQ_hd_var_size (register,
2348 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2349 struct GNUNET_NAT_RegisterMessage,
2351 GNUNET_MQ_hd_var_size (stun,
2352 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2353 struct GNUNET_NAT_HandleStunMessage,
2355 GNUNET_MQ_hd_var_size (request_connection_reversal,
2356 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2357 struct GNUNET_NAT_RequestConnectionReversalMessage,
2359 GNUNET_MQ_hd_var_size (autoconfig_request,
2360 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2361 struct GNUNET_NAT_AutoconfigRequestMessage,
2363 GNUNET_MQ_handler_end ());
2366 #if defined(LINUX) && defined(__GLIBC__)
2370 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2372 void __attribute__ ((constructor))
2373 GNUNET_ARM_memory_init ()
2375 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2376 mallopt (M_TOP_PAD, 1 * 1024);
2381 /* end of gnunet-service-nat.c */