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 (incl. DNS
33 * lookup for DynDNS setups!)
34 * - implement "more" autoconfig:
35 * re-work gnunet-nat-server & integrate!
36 * + test manually punched NAT (how?)
37 * - implement & test STUN processing to classify NAT;
38 * basically, open port & try different methods.
39 * - implement NEW logic for external IP detection
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_nat_service.h"
48 #include "gnunet-service-nat_stun.h"
49 #include "gnunet-service-nat_mini.h"
50 #include "gnunet-service-nat_helper.h"
56 * How often should we ask the OS about a list of active
59 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
62 * How long do we wait until we forcefully terminate autoconfiguration?
64 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
67 * How long do we wait until we re-try running `external-ip` if the
68 * command failed to terminate nicely?
70 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
73 * How long do we wait until we re-try running `external-ip` if the
74 * command failed (but terminated)?
76 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
79 * How long do we wait until we re-try running `external-ip` if the
82 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
86 * Information we track per client address.
91 * Network address used by the client.
93 struct sockaddr_storage ss;
96 * Handle to active UPnP request where we asked upnpc to open
97 * a port at the NAT. NULL if we do not have such a request
100 struct GNUNET_NAT_MiniHandle *mh;
106 * Internal data structure we track for each of our clients.
114 struct ClientHandle *next;
119 struct ClientHandle *prev;
122 * Underlying handle for this client with the service.
124 struct GNUNET_SERVICE_Client *client;
127 * Message queue for communicating with the client.
129 struct GNUNET_MQ_Handle *mq;
132 * Array of addresses used by the service.
134 struct ClientAddress *caddrs;
137 * External DNS name and port given by user due to manual
138 * hole punching. Special DNS name 'AUTO' is used to indicate
139 * desire for automatic determination of the external IP
140 * (instead of DNS or manual configuration, i.e. to be used
141 * if the IP keeps changing and we have no DynDNS, but we do
142 * have a hole punched).
147 * What does this client care about?
149 enum GNUNET_NAT_RegisterFlags flags;
152 * Is any of the @e caddrs in a reserved subnet for NAT?
157 * Number of addresses that this service is bound to.
158 * Length of the @e caddrs array.
163 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
171 * List of local addresses this system has.
173 struct LocalAddressList
176 * This is a linked list.
178 struct LocalAddressList *next;
183 struct LocalAddressList *prev;
186 * Context for a gnunet-helper-nat-server used to listen
187 * for ICMP messages to this client for connection reversal.
189 struct HelperContext *hc;
192 * The address itself (i.e. `struct sockaddr_in` or `struct
193 * sockaddr_in6`, in the respective byte order).
195 struct sockaddr_storage addr;
203 * What type of address is this?
205 enum GNUNET_NAT_AddressClass ac;
211 * External IP address as given to us via some STUN server.
213 struct StunExternalIP
218 struct StunExternalIP *next;
223 struct StunExternalIP *prev;
226 * Task we run to remove this entry when it is stale.
228 struct GNUNET_SCHEDULER_Task *timeout_task;
231 * Our external IP address as reported by the
234 struct sockaddr_in external_addr;
237 * Address of the reporting STUN server. Used to
238 * detect when a STUN server changes its opinion
239 * to more quickly remove stale results.
241 struct sockaddr_storage stun_server_addr;
244 * Number of bytes used in @e stun_server_addr.
246 size_t stun_server_addr_len;
251 * Context for autoconfiguration operations.
253 struct AutoconfigContext
258 struct AutoconfigContext *prev;
263 struct AutoconfigContext *next;
266 * Which client asked the question.
268 struct ClientHandle *ch;
271 * Configuration we are creating.
273 struct GNUNET_CONFIGURATION_Handle *c;
276 * Original configuration (for diffing).
278 struct GNUNET_CONFIGURATION_Handle *orig;
281 * Timeout task to force termination.
283 struct GNUNET_SCHEDULER_Task *timeout_task;
286 * What type of system are we on?
291 * Handle to activity to probe for our external IP.
293 struct GNUNET_NAT_ExternalHandle *probe_external;
296 * #GNUNET_YES if upnpc should be used,
297 * #GNUNET_NO if upnpc should not be used,
298 * #GNUNET_SYSERR if we should simply not change the option.
303 * Status code to return to the client.
305 enum GNUNET_NAT_StatusCode status_code;
308 * NAT type to return to the client.
310 enum GNUNET_NAT_Type type;
315 * DLL of our autoconfiguration operations.
317 static struct AutoconfigContext *ac_head;
320 * DLL of our autoconfiguration operations.
322 static struct AutoconfigContext *ac_tail;
325 * Timeout to use when STUN data is considered stale.
327 static struct GNUNET_TIME_Relative stun_stale_timeout;
330 * Handle to our current configuration.
332 static const struct GNUNET_CONFIGURATION_Handle *cfg;
335 * Handle to the statistics service.
337 static struct GNUNET_STATISTICS_Handle *stats;
340 * Task scheduled to periodically scan our network interfaces.
342 static struct GNUNET_SCHEDULER_Task *scan_task;
345 * Head of client DLL.
347 static struct ClientHandle *ch_head;
350 * Tail of client DLL.
352 static struct ClientHandle *ch_tail;
355 * Head of DLL of local addresses.
357 static struct LocalAddressList *lal_head;
360 * Tail of DLL of local addresses.
362 static struct LocalAddressList *lal_tail;
367 static struct StunExternalIP *se_head;
372 static struct StunExternalIP *se_tail;
375 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
376 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
378 static int enable_upnp;
381 * Task run to obtain our external IP (if #enable_upnp is set
382 * and if we find we have a NATed IP address).
384 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
387 * Handle to our operation to run `external-ip`.
389 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
392 * What is our external IP address as claimed by `external-ip`?
395 static struct in_addr mini_external_ipv4;
399 * Remove and free an entry from the #lal_head DLL.
401 * @param lal entry to free
404 free_lal (struct LocalAddressList *lal)
406 GNUNET_CONTAINER_DLL_remove (lal_head,
411 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
412 "Lost NATed local address %s, stopping NAT server\n",
413 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
414 sizeof (struct sockaddr_in)));
416 GN_stop_gnunet_nat_server_ (lal->hc);
424 * Free the DLL starting at #lal_head.
429 struct LocalAddressList *lal;
431 while (NULL != (lal = lal_head))
437 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
440 * @param cls client who sent the message
441 * @param message the message received
442 * @return #GNUNET_OK if message is well-formed
445 check_register (void *cls,
446 const struct GNUNET_NAT_RegisterMessage *message)
448 uint16_t num_addrs = ntohs (message->num_addrs);
449 const char *off = (const char *) &message[1];
450 size_t left = ntohs (message->header.size) - sizeof (*message);
452 for (unsigned int i=0;i<num_addrs;i++)
455 const struct sockaddr *sa = (const struct sockaddr *) off;
457 if (sizeof (sa_family_t) > left)
460 return GNUNET_SYSERR;
462 switch (sa->sa_family)
465 alen = sizeof (struct sockaddr_in);
468 alen = sizeof (struct sockaddr_in6);
472 alen = sizeof (struct sockaddr_un);
477 return GNUNET_SYSERR;
482 return GNUNET_SYSERR;
487 if (left != ntohs (message->hole_external_len))
490 return GNUNET_SYSERR;
497 * Check if @a ip is in @a network with @a bits netmask.
499 * @param network to test
500 * @param ip IP address to test
501 * @param bits bitmask for the network
502 * @return #GNUNET_YES if @a ip is in @a network
505 match_ipv4 (const char *network,
506 const struct in_addr *ip,
515 GNUNET_assert (1 == inet_pton (AF_INET,
518 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
523 * Check if @a ip is in @a network with @a bits netmask.
525 * @param network to test
526 * @param ip IP address to test
527 * @param bits bitmask for the network
528 * @return #GNUNET_YES if @a ip is in @a network
531 match_ipv6 (const char *network,
532 const struct in6_addr *ip,
536 struct in6_addr mask;
541 GNUNET_assert (1 == inet_pton (AF_INET6,
544 memset (&mask, 0, sizeof (mask));
545 if (0 == memcmp (&mask,
552 mask.s6_addr[off++] = 0xFF;
557 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
560 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
561 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
562 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
569 * Test if the given IPv4 address is in a known range
570 * for private networks.
572 * @param ip address to test
573 * @return #GNUNET_YES if @a ip is in a NAT range
576 is_nat_v4 (const struct in_addr *ip)
579 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
580 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
581 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
582 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
583 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
588 * Test if the given IPv6 address is in a known range
589 * for private networks.
591 * @param ip address to test
592 * @return #GNUNET_YES if @a ip is in a NAT range
595 is_nat_v6 (const struct in6_addr *ip)
598 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
599 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
600 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
605 * Closure for #ifc_proc.
607 struct IfcProcContext
611 * Head of DLL of local addresses.
613 struct LocalAddressList *lal_head;
616 * Tail of DLL of local addresses.
618 struct LocalAddressList *lal_tail;
624 * Callback function invoked for each interface found. Adds them
625 * to our new address list.
627 * @param cls a `struct IfcProcContext *`
628 * @param name name of the interface (can be NULL for unknown)
629 * @param isDefault is this presumably the default interface
630 * @param addr address of this interface (can be NULL for unknown or unassigned)
631 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
632 * @param netmask the network mask (can be NULL for unknown or unassigned)
633 * @param addrlen length of the address
634 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
640 const struct sockaddr *addr,
641 const struct sockaddr *broadcast_addr,
642 const struct sockaddr *netmask,
645 struct IfcProcContext *ifc_ctx = cls;
646 struct LocalAddressList *lal;
648 const struct in_addr *ip4;
649 const struct in6_addr *ip6;
650 enum GNUNET_NAT_AddressClass ac;
652 switch (addr->sa_family)
655 alen = sizeof (struct sockaddr_in);
656 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
657 if (match_ipv4 ("127.0.0.0", ip4, 8))
658 ac = GNUNET_NAT_AC_LOOPBACK;
659 else if (is_nat_v4 (ip4))
660 ac = GNUNET_NAT_AC_LAN;
662 ac = GNUNET_NAT_AC_GLOBAL;
665 alen = sizeof (struct sockaddr_in6);
666 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
667 if (match_ipv6 ("::1", ip6, 128))
668 ac = GNUNET_NAT_AC_LOOPBACK;
669 else if (is_nat_v6 (ip6))
670 ac = GNUNET_NAT_AC_LAN;
672 ac = GNUNET_NAT_AC_GLOBAL;
673 if ( (ip6->s6_addr[11] == 0xFF) &&
674 (ip6->s6_addr[12] == 0xFE) )
676 /* contains a MAC, be extra careful! */
677 ac |= GNUNET_NAT_AC_PRIVATE;
689 lal = GNUNET_malloc (sizeof (*lal));
690 lal->af = addr->sa_family;
692 GNUNET_memcpy (&lal->addr,
695 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
703 * Notify client about a change in the list of addresses this peer
706 * @param ac address class of the entry in the list that changed
707 * @param ch client to contact
708 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
709 * @param addr the address that changed
710 * @param addr_len number of bytes in @a addr
713 notify_client (enum GNUNET_NAT_AddressClass ac,
714 struct ClientHandle *ch,
719 struct GNUNET_MQ_Envelope *env;
720 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
722 env = GNUNET_MQ_msg_extra (msg,
724 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
725 msg->add_remove = htonl (add);
726 msg->addr_class = htonl (ac);
727 GNUNET_memcpy (&msg[1],
730 GNUNET_MQ_send (ch->mq,
736 * Check if we should bother to notify this client about this
737 * address change, and if so, do it.
739 * @param delta the entry in the list that changed
740 * @param ch client to check
741 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
744 check_notify_client (struct LocalAddressList *delta,
745 struct ClientHandle *ch,
749 struct sockaddr_in v4;
750 struct sockaddr_in6 v6;
752 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
757 alen = sizeof (struct sockaddr_in);
762 /* Check for client notifications */
763 for (unsigned int i=0;i<ch->num_caddrs;i++)
765 const struct sockaddr_in *c4;
767 if (AF_INET != ch->caddrs[i].ss.ss_family)
768 return; /* IPv4 not relevant */
769 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
770 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
771 (0 != c4->sin_addr.s_addr) &&
772 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
773 continue; /* bound to loopback, but this is not loopback */
774 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
775 (0 != c4->sin_addr.s_addr) &&
776 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
777 continue; /* bound to non-loopback, but this is loopback */
778 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
779 (0 != c4->sin_addr.s_addr) &&
780 (! is_nat_v4 (&v4.sin_addr)) )
781 continue; /* based on external-IP, but this IP is not
782 from private address range. */
783 if ( (0 != memcmp (&v4.sin_addr,
785 sizeof (struct in_addr))) &&
786 (0 != c4->sin_addr.s_addr) &&
787 ( (! is_nat_v4 (&c4->sin_addr)) ||
788 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
789 continue; /* this IP is not from private address range,
790 and IP does not match. */
792 /* OK, IP seems relevant, notify client */
793 v4.sin_port = c4->sin_port;
794 notify_client (delta->ac,
802 alen = sizeof (struct sockaddr_in6);
806 for (unsigned int i=0;i<ch->num_caddrs;i++)
808 const struct sockaddr_in6 *c6;
810 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
811 return; /* IPv4 not relevant */
812 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
813 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
814 (0 != memcmp (&c6->sin6_addr,
816 sizeof (struct in6_addr))) &&
817 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
818 continue; /* bound to loopback, but this is not loopback */
819 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
820 (0 != memcmp (&c6->sin6_addr,
822 sizeof (struct in6_addr))) &&
823 match_ipv6 ("::1", &v6.sin6_addr, 128) )
824 continue; /* bound to non-loopback, but this is loopback */
825 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
826 (0 != memcmp (&c6->sin6_addr,
828 sizeof (struct in6_addr))) &&
829 (! is_nat_v6 (&v6.sin6_addr)) )
830 continue; /* based on external-IP, but this IP is not
831 from private address range. */
832 if ( (0 != memcmp (&v6.sin6_addr,
834 sizeof (struct in6_addr))) &&
835 (0 != memcmp (&c6->sin6_addr,
837 sizeof (struct in6_addr))) &&
838 (! is_nat_v6 (&c6->sin6_addr)) )
839 continue; /* this IP is not from private address range,
840 and IP does not match. */
841 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
842 (0 != memcmp (&c6->sin6_addr,
844 sizeof (struct in6_addr))) &&
845 (0 != memcmp (&v6.sin6_addr,
847 sizeof (struct in6_addr))) &&
848 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
849 continue; /* client bound to link-local, and the other address
850 does not match and is not an external IP */
852 /* OK, IP seems relevant, notify client */
853 v6.sin6_port = c6->sin6_port;
854 notify_client (delta->ac,
869 * Notify all clients about a change in the list
870 * of addresses this peer has.
872 * @param delta the entry in the list that changed
873 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
876 notify_clients (struct LocalAddressList *delta,
879 for (struct ClientHandle *ch = ch_head;
882 check_notify_client (delta,
889 * Tell relevant client about a change in our external
892 * @param v4 the external address that changed
893 * @param ch client to check if it cares and possibly notify
894 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
897 check_notify_client_external_ipv4_change (const struct in_addr *v4,
898 struct ClientHandle *ch,
901 struct sockaddr_in sa;
904 /* (1) check if client cares. */
905 if (! ch->natted_address)
907 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
910 for (unsigned int i=0;i<ch->num_caddrs;i++)
912 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
914 if (AF_INET != ss->ss_family)
916 have_v4 = GNUNET_YES;
919 if (GNUNET_NO == have_v4)
920 return; /* IPv6-only */
922 /* build address info */
926 sa.sin_family = AF_INET;
928 sa.sin_port = htons (0);
930 /* (3) notify client of change */
931 notify_client (is_nat_v4 (v4)
932 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
933 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
942 * Tell relevant clients about a change in our external
945 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
946 * @param v4 the external address that changed
949 notify_clients_external_ipv4_change (int add,
950 const struct in_addr *v4)
952 for (struct ClientHandle *ch = ch_head;
955 check_notify_client_external_ipv4_change (v4,
962 * Task used to run `external-ip` to get our external IPv4
963 * address and pass it to NATed clients if possible.
968 run_external_ip (void *cls);
972 * We learn our current external IP address. If it changed,
973 * notify all of our applicable clients. Also re-schedule
974 * #run_external_ip with an appropriate timeout.
977 * @param addr the address, NULL on errors
978 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
981 handle_external_ip (void *cls,
982 const struct in_addr *addr,
983 enum GNUNET_NAT_StatusCode result)
985 char buf[INET_ADDRSTRLEN];
987 probe_external_ip_op = NULL;
988 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
989 probe_external_ip_task
990 = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
991 ? EXTERN_IP_RETRY_FAILURE
992 : EXTERN_IP_RETRY_SUCCESS,
997 case GNUNET_NAT_ERROR_SUCCESS:
998 if (addr->s_addr == mini_external_ipv4.s_addr)
999 return; /* not change */
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 "Our external IP is now %s\n",
1006 if (0 != mini_external_ipv4.s_addr)
1007 notify_clients_external_ipv4_change (GNUNET_NO,
1008 &mini_external_ipv4);
1009 mini_external_ipv4 = *addr;
1010 notify_clients_external_ipv4_change (GNUNET_YES,
1011 &mini_external_ipv4);
1014 if (0 != mini_external_ipv4.s_addr)
1015 notify_clients_external_ipv4_change (GNUNET_NO,
1016 &mini_external_ipv4);
1017 mini_external_ipv4.s_addr = 0;
1024 * Task used to run `external-ip` to get our external IPv4
1025 * address and pass it to NATed clients if possible.
1030 run_external_ip (void *cls)
1032 probe_external_ip_task
1033 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
1036 if (NULL != probe_external_ip_op)
1038 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1039 probe_external_ip_op = NULL;
1041 probe_external_ip_op
1042 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
1048 * We got a connection reversal request from another peer.
1049 * Notify applicable clients.
1051 * @param cls closure with the `struct LocalAddressList`
1052 * @param ra IP address of the peer who wants us to connect to it
1055 reversal_callback (void *cls,
1056 const struct sockaddr_in *ra)
1058 struct LocalAddressList *lal = cls;
1059 const struct sockaddr_in *l4;
1061 GNUNET_assert (AF_INET == lal->af);
1062 l4 = (const struct sockaddr_in *) &lal->addr;
1063 for (struct ClientHandle *ch = ch_head;
1067 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
1068 struct GNUNET_MQ_Envelope *env;
1071 /* Check if client is in applicable range for ICMP NAT traversal
1072 for this local address */
1073 if (! ch->natted_address)
1076 for (unsigned int i=0;i<ch->num_caddrs;i++)
1078 struct ClientAddress *ca = &ch->caddrs[i];
1079 const struct sockaddr_in *c4;
1081 if (AF_INET != ca->ss.ss_family)
1083 c4 = (const struct sockaddr_in *) &ca->ss;
1084 if ( (0 != c4->sin_addr.s_addr) &&
1085 (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
1093 /* Notify applicable client about connection reversal request */
1094 env = GNUNET_MQ_msg_extra (crrm,
1095 sizeof (struct sockaddr_in),
1096 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
1097 GNUNET_memcpy (&crrm[1],
1099 sizeof (struct sockaddr_in));
1100 GNUNET_MQ_send (ch->mq,
1107 * Task we run periodically to scan for network interfaces.
1112 run_scan (void *cls)
1114 struct IfcProcContext ifc_ctx;
1117 struct LocalAddressList *lnext;
1119 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1125 GNUNET_OS_network_interfaces_list (&ifc_proc,
1127 /* remove addresses that disappeared */
1128 for (struct LocalAddressList *lal = lal_head;
1134 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1138 if ( (pos->af == lal->af) &&
1139 (0 == memcmp (&lal->addr,
1141 (AF_INET == lal->af)
1142 ? sizeof (struct sockaddr_in)
1143 : sizeof (struct sockaddr_in6))) )
1148 if (GNUNET_NO == found)
1150 notify_clients (lal,
1156 /* add addresses that appeared */
1157 have_nat = GNUNET_NO;
1158 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1160 pos = ifc_ctx.lal_head)
1163 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1164 have_nat = GNUNET_YES;
1165 for (struct LocalAddressList *lal = lal_head;
1169 if ( (pos->af == lal->af) &&
1170 (0 == memcmp (&lal->addr,
1172 (AF_INET == lal->af)
1173 ? sizeof (struct sockaddr_in)
1174 : sizeof (struct sockaddr_in6))) )
1177 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1180 if (GNUNET_YES == found)
1186 notify_clients (pos,
1188 GNUNET_CONTAINER_DLL_insert (lal_head,
1191 if ( (AF_INET == pos->af) &&
1192 (NULL == pos->hc) &&
1193 (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1195 const struct sockaddr_in *s4
1196 = (const struct sockaddr_in *) &pos->addr;
1198 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1199 "Found NATed local address %s, starting NAT server\n",
1200 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
1201 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1207 if ( (GNUNET_YES == have_nat) &&
1208 (GNUNET_YES == enable_upnp) &&
1209 (NULL == probe_external_ip_task) &&
1210 (NULL == probe_external_ip_op) )
1212 probe_external_ip_task
1213 = GNUNET_SCHEDULER_add_now (&run_external_ip,
1216 if ( (GNUNET_NO == have_nat) &&
1217 (GNUNET_YES == enable_upnp) )
1219 if (NULL != probe_external_ip_task)
1221 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1222 probe_external_ip_task = NULL;
1224 if (NULL != probe_external_ip_op)
1226 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1227 probe_external_ip_op = NULL;
1234 * Function called whenever our set of external addresses
1235 * as created by `upnpc` changes.
1237 * @param cls closure with our `struct ClientHandle *`
1238 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1239 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1240 * @param addr either the previous or the new public IP address
1241 * @param addrlen actual length of the @a addr
1242 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1245 upnp_addr_change_cb (void *cls,
1247 const struct sockaddr *addr,
1249 enum GNUNET_NAT_StatusCode result)
1251 struct ClientHandle *ch = cls;
1252 enum GNUNET_NAT_AddressClass ac;
1256 case GNUNET_NAT_ERROR_SUCCESS:
1257 GNUNET_assert (NULL != addr);
1259 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1260 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1261 case GNUNET_NAT_ERROR_IPC_FAILURE:
1262 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263 "Running upnpc failed: %d\n",
1266 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1267 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1268 "external-ip binary not found\n");
1270 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1271 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1272 "external-ip binary could not be run\n");
1274 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1275 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1276 "upnpc failed to create port mapping\n");
1278 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1279 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1280 "Invalid output from upnpc\n");
1282 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284 "Invalid address returned by upnpc\n");
1287 GNUNET_break (0); /* should not be possible */
1290 switch (addr->sa_family)
1293 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1295 : GNUNET_NAT_AC_EXTERN;
1298 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1300 : GNUNET_NAT_AC_EXTERN;
1306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307 "upnp external address %s: %s\n",
1308 add_remove ? "added" : "removed",
1320 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1321 * We remember the client for updates upon future NAT events.
1323 * @param cls client who sent the message
1324 * @param message the message received
1327 handle_register (void *cls,
1328 const struct GNUNET_NAT_RegisterMessage *message)
1330 struct ClientHandle *ch = cls;
1334 if ( (0 != ch->proto) ||
1335 (NULL != ch->caddrs) )
1337 /* double registration not allowed */
1339 GNUNET_SERVICE_client_drop (ch->client);
1342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343 "Received REGISTER message from client\n");
1344 ch->flags = message->flags;
1345 ch->proto = message->proto;
1346 ch->num_caddrs = ntohs (message->num_addrs);
1347 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1348 struct ClientAddress);
1349 left = ntohs (message->header.size) - sizeof (*message);
1350 off = (const char *) &message[1];
1351 for (unsigned int i=0;i<ch->num_caddrs;i++)
1354 const struct sockaddr *sa = (const struct sockaddr *) off;
1358 if (sizeof (sa_family_t) > left)
1361 GNUNET_SERVICE_client_drop (ch->client);
1365 switch (sa->sa_family)
1369 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1371 alen = sizeof (struct sockaddr_in);
1372 if (is_nat_v4 (&s4->sin_addr))
1373 is_nat = GNUNET_YES;
1374 port = ntohs (s4->sin_port);
1379 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1381 alen = sizeof (struct sockaddr_in6);
1382 if (is_nat_v6 (&s6->sin6_addr))
1383 is_nat = GNUNET_YES;
1384 port = ntohs (s6->sin6_port);
1389 alen = sizeof (struct sockaddr_un);
1395 GNUNET_SERVICE_client_drop (ch->client);
1399 GNUNET_assert (alen <= left);
1400 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1401 GNUNET_memcpy (&ch->caddrs[i].ss,
1405 /* If applicable, try UPNPC NAT punching */
1408 ( (IPPROTO_TCP == ch->proto) ||
1409 (IPPROTO_UDP == ch->proto) ) )
1411 ch->natted_address = GNUNET_YES;
1413 = GNUNET_NAT_mini_map_start (port,
1414 IPPROTO_TCP == ch->proto,
1415 &upnp_addr_change_cb,
1423 = GNUNET_strndup (off,
1424 ntohs (message->hole_external_len));
1426 /* Actually send IP address list to client */
1427 for (struct LocalAddressList *lal = lal_head;
1431 check_notify_client (lal,
1435 /* Also consider IPv4 determined by `external-ip` */
1436 if (0 != mini_external_ipv4.s_addr)
1438 check_notify_client_external_ipv4_change (&mini_external_ipv4,
1442 GNUNET_SERVICE_client_continue (ch->client);
1447 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1450 * @param cls client who sent the message
1451 * @param message the message received
1452 * @return #GNUNET_OK if message is well-formed
1455 check_stun (void *cls,
1456 const struct GNUNET_NAT_HandleStunMessage *message)
1458 size_t sa_len = ntohs (message->sender_addr_size);
1459 size_t expect = sa_len + ntohs (message->payload_size);
1461 if (ntohs (message->header.size) - sizeof (*message) != expect)
1464 return GNUNET_SYSERR;
1466 if (sa_len < sizeof (sa_family_t))
1469 return GNUNET_SYSERR;
1476 * Notify all clients about our external IP address
1477 * as reported by the STUN server.
1479 * @param ip the external IP
1480 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1483 notify_clients_stun_change (const struct sockaddr_in *ip,
1486 for (struct ClientHandle *ch = ch_head;
1490 struct sockaddr_in v4;
1491 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1492 struct GNUNET_MQ_Envelope *env;
1494 if (! ch->natted_address)
1497 v4.sin_port = htons (0);
1498 env = GNUNET_MQ_msg_extra (msg,
1500 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1501 msg->add_remove = htonl ((int32_t) add);
1502 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1503 GNUNET_NAT_AC_GLOBAL);
1504 GNUNET_memcpy (&msg[1],
1507 GNUNET_MQ_send (ch->mq,
1514 * Function to be called when we decide that an
1515 * external IP address as told to us by a STUN
1516 * server has gone stale.
1518 * @param cls the `struct StunExternalIP` to drop
1521 stun_ip_timeout (void *cls)
1523 struct StunExternalIP *se = cls;
1525 se->timeout_task = NULL;
1526 notify_clients_stun_change (&se->external_addr,
1528 GNUNET_CONTAINER_DLL_remove (se_head,
1536 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1539 * @param cls client who sent the message
1540 * @param message the message received
1543 handle_stun (void *cls,
1544 const struct GNUNET_NAT_HandleStunMessage *message)
1546 struct ClientHandle *ch = cls;
1547 const char *buf = (const char *) &message[1];
1548 const struct sockaddr *sa;
1549 const void *payload;
1551 size_t payload_size;
1552 struct sockaddr_in external_addr;
1554 sa_len = ntohs (message->sender_addr_size);
1555 payload_size = ntohs (message->payload_size);
1556 sa = (const struct sockaddr *) &buf[0];
1557 payload = (const struct sockaddr *) &buf[sa_len];
1558 switch (sa->sa_family)
1561 if (sa_len != sizeof (struct sockaddr_in))
1564 GNUNET_SERVICE_client_drop (ch->client);
1569 if (sa_len != sizeof (struct sockaddr_in6))
1572 GNUNET_SERVICE_client_drop (ch->client);
1577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1578 "Received HANDLE_STUN message from client\n");
1580 GNUNET_NAT_stun_handle_packet_ (payload,
1584 /* We now know that a server at "sa" claims that
1585 we are visible at IP "external_addr".
1587 We should (for some fixed period of time) tell
1588 all of our clients that listen to a NAT'ed address
1589 that they might want to consider the given 'external_ip'
1590 as their public IP address (this includes TCP and UDP
1591 clients, even if only UDP sends STUN requests).
1593 If we do not get a renewal, the "external_addr" should be
1594 removed again. The timeout frequency should be configurable
1595 (with a sane default), so that the UDP plugin can tell how
1596 often to re-request STUN.
1598 struct StunExternalIP *se;
1600 /* Check if we had a prior response from this STUN server */
1601 for (se = se_head; NULL != se; se = se->next)
1603 if ( (se->stun_server_addr_len != sa_len) ||
1605 &se->stun_server_addr,
1607 continue; /* different STUN server */
1608 if (0 != memcmp (&external_addr,
1610 sizeof (struct sockaddr_in)))
1612 /* external IP changed, update! */
1613 notify_clients_stun_change (&se->external_addr,
1615 se->external_addr = external_addr;
1616 notify_clients_stun_change (&se->external_addr,
1619 /* update timeout */
1620 GNUNET_SCHEDULER_cancel (se->timeout_task);
1622 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1627 /* STUN server is completely new, create fresh entry */
1628 se = GNUNET_new (struct StunExternalIP);
1629 se->external_addr = external_addr;
1630 GNUNET_memcpy (&se->stun_server_addr,
1633 se->stun_server_addr_len = sa_len;
1634 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1637 GNUNET_CONTAINER_DLL_insert (se_head,
1640 notify_clients_stun_change (&se->external_addr,
1643 GNUNET_SERVICE_client_continue (ch->client);
1649 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1652 * @param cls client who sent the message
1653 * @param message the message received
1654 * @return #GNUNET_OK if message is well-formed
1657 check_request_connection_reversal (void *cls,
1658 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1662 expect = ntohs (message->local_addr_size)
1663 + ntohs (message->remote_addr_size);
1664 if (ntohs (message->header.size) - sizeof (*message) != expect)
1667 return GNUNET_SYSERR;
1674 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1675 * message from client.
1677 * @param cls client who sent the message
1678 * @param message the message received
1681 handle_request_connection_reversal (void *cls,
1682 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1684 struct ClientHandle *ch = cls;
1685 const char *buf = (const char *) &message[1];
1686 size_t local_sa_len = ntohs (message->local_addr_size);
1687 size_t remote_sa_len = ntohs (message->remote_addr_size);
1688 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1689 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1690 const struct sockaddr_in *l4 = NULL;
1691 const struct sockaddr_in *r4;
1694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695 "Received REQUEST CONNECTION REVERSAL message from client\n");
1696 switch (local_sa->sa_family)
1699 if (local_sa_len != sizeof (struct sockaddr_in))
1702 GNUNET_SERVICE_client_drop (ch->client);
1705 l4 = (const struct sockaddr_in *) local_sa;
1708 if (local_sa_len != sizeof (struct sockaddr_in6))
1711 GNUNET_SERVICE_client_drop (ch->client);
1714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1715 _("Connection reversal for IPv6 not supported yet\n"));
1716 ret = GNUNET_SYSERR;
1720 GNUNET_SERVICE_client_drop (ch->client);
1723 switch (remote_sa->sa_family)
1726 if (remote_sa_len != sizeof (struct sockaddr_in))
1729 GNUNET_SERVICE_client_drop (ch->client);
1732 r4 = (const struct sockaddr_in *) remote_sa;
1733 ret = GN_request_connection_reversal (&l4->sin_addr,
1734 ntohs (l4->sin_port),
1738 if (remote_sa_len != sizeof (struct sockaddr_in6))
1741 GNUNET_SERVICE_client_drop (ch->client);
1744 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1745 _("Connection reversal for IPv6 not supported yet\n"));
1746 ret = GNUNET_SYSERR;
1750 GNUNET_SERVICE_client_drop (ch->client);
1753 if (GNUNET_OK != ret)
1754 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1755 _("Connection reversal request failed\n"));
1756 GNUNET_SERVICE_client_continue (ch->client);
1761 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1764 * @param cls client who sent the message
1765 * @param message the message received
1766 * @return #GNUNET_OK if message is well-formed
1769 check_autoconfig_request (void *cls,
1770 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1772 return GNUNET_OK; /* checked later */
1777 * Stop all pending activities with respect to the @a ac
1779 * @param ac autoconfiguration to terminate activities for
1782 terminate_ac_activities (struct AutoconfigContext *ac)
1784 if (NULL != ac->probe_external)
1786 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1787 ac->probe_external = NULL;
1789 if (NULL != ac->timeout_task)
1791 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1792 ac->timeout_task = NULL;
1798 * Finish handling the autoconfiguration request and send
1799 * the response to the client.
1801 * @param cls the `struct AutoconfigContext` to conclude
1804 conclude_autoconfig_request (void *cls)
1806 struct AutoconfigContext *ac = cls;
1807 struct ClientHandle *ch = ac->ch;
1808 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1809 struct GNUNET_MQ_Envelope *env;
1812 struct GNUNET_CONFIGURATION_Handle *diff;
1814 ac->timeout_task = NULL;
1815 terminate_ac_activities (ac);
1817 /* Send back response */
1818 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1820 buf = GNUNET_CONFIGURATION_serialize (diff,
1822 GNUNET_CONFIGURATION_destroy (diff);
1823 env = GNUNET_MQ_msg_extra (arm,
1825 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1826 arm->status_code = htonl ((uint32_t) ac->status_code);
1827 arm->type = htonl ((uint32_t) ac->type);
1828 GNUNET_memcpy (&arm[1],
1832 GNUNET_MQ_send (ch->mq,
1836 GNUNET_free (ac->system_type);
1837 GNUNET_CONFIGURATION_destroy (ac->orig);
1838 GNUNET_CONFIGURATION_destroy (ac->c);
1839 GNUNET_CONTAINER_DLL_remove (ac_head,
1843 GNUNET_SERVICE_client_continue (ch->client);
1848 * Check if all autoconfiguration operations have concluded,
1849 * and if they have, send the result back to the client.
1851 * @param ac autoconfiguation context to check
1854 check_autoconfig_finished (struct AutoconfigContext *ac)
1856 if (NULL != ac->probe_external)
1858 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1860 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1866 * Update ENABLE_UPNPC configuration option.
1868 * @param ac autoconfiguration to update
1871 update_enable_upnpc_option (struct AutoconfigContext *ac)
1873 switch (ac->enable_upnpc)
1876 GNUNET_CONFIGURATION_set_value_string (ac->c,
1882 GNUNET_CONFIGURATION_set_value_string (ac->c,
1888 /* We are unsure, do not change option */
1895 * Handle result from external IP address probe during
1896 * autoconfiguration.
1898 * @param cls our `struct AutoconfigContext`
1899 * @param addr the address, NULL on errors
1900 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1903 auto_external_result_cb (void *cls,
1904 const struct in_addr *addr,
1905 enum GNUNET_NAT_StatusCode result)
1907 struct AutoconfigContext *ac = cls;
1909 ac->probe_external = NULL;
1912 case GNUNET_NAT_ERROR_SUCCESS:
1913 ac->enable_upnpc = GNUNET_YES;
1915 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1916 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1917 case GNUNET_NAT_ERROR_IPC_FAILURE:
1918 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1919 "Disabling UPNPC: %d\n",
1921 ac->enable_upnpc = GNUNET_NO; /* did not work */
1924 GNUNET_break (0); /* unexpected */
1925 ac->enable_upnpc = GNUNET_SYSERR;
1928 update_enable_upnpc_option (ac);
1929 check_autoconfig_finished (ac);
1934 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1937 * @param cls client who sent the message
1938 * @param message the message received
1941 handle_autoconfig_request (void *cls,
1942 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1944 struct ClientHandle *ch = cls;
1945 size_t left = ntohs (message->header.size) - sizeof (*message);
1946 struct LocalAddressList *lal;
1947 struct AutoconfigContext *ac;
1949 ac = GNUNET_new (struct AutoconfigContext);
1950 ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
1952 ac->c = GNUNET_CONFIGURATION_create ();
1954 GNUNET_CONFIGURATION_deserialize (ac->c,
1955 (const char *) &message[1],
1960 GNUNET_SERVICE_client_drop (ch->client);
1961 GNUNET_CONFIGURATION_destroy (ac->c);
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966 "Received REQUEST_AUTO_CONFIG message from client\n");
1969 GNUNET_CONFIGURATION_get_value_string (ac->c,
1973 ac->system_type = GNUNET_strdup ("UNKNOWN");
1975 GNUNET_CONTAINER_DLL_insert (ac_head,
1979 = GNUNET_CONFIGURATION_dup (ac->c);
1981 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1982 &conclude_autoconfig_request,
1984 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1986 /* Probe for upnpc */
1987 if (GNUNET_SYSERR ==
1988 GNUNET_OS_check_helper_binary ("upnpc",
1992 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1993 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1994 ac->enable_upnpc = GNUNET_NO;
1998 for (lal = lal_head; NULL != lal; lal = lal->next)
1999 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
2000 /* we are behind NAT, useful to try upnpc */
2001 ac->enable_upnpc = GNUNET_YES;
2003 if (GNUNET_YES == ac->enable_upnpc)
2005 /* If we are a mobile device, always leave it on as the network
2006 may change to one that supports UPnP anytime. If we are
2007 stationary, check if our network actually supports UPnP, and if
2009 if ( (0 == strcasecmp (ac->system_type,
2010 "INFRASTRUCTURE")) ||
2011 (0 == strcasecmp (ac->system_type,
2014 /* Check if upnpc gives us an external IP */
2016 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
2020 if (NULL == ac->probe_external)
2021 update_enable_upnpc_option (ac);
2023 /* Finally, check if we are already done */
2024 check_autoconfig_finished (ac);
2029 * Task run during shutdown.
2034 shutdown_task (void *cls)
2036 struct StunExternalIP *se;
2037 struct AutoconfigContext *ac;
2039 while (NULL != (ac = ac_head))
2041 GNUNET_CONTAINER_DLL_remove (ac_head,
2044 terminate_ac_activities (ac);
2047 while (NULL != (se = se_head))
2049 GNUNET_CONTAINER_DLL_remove (se_head,
2052 GNUNET_SCHEDULER_cancel (se->timeout_task);
2055 if (NULL != probe_external_ip_task)
2057 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
2058 probe_external_ip_task = NULL;
2060 if (NULL != probe_external_ip_op)
2062 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
2063 probe_external_ip_op = NULL;
2065 if (NULL != scan_task)
2067 GNUNET_SCHEDULER_cancel (scan_task);
2072 GNUNET_STATISTICS_destroy (stats,
2081 * Setup NAT service.
2083 * @param cls closure
2084 * @param c configuration to use
2085 * @param service the initialized service
2089 const struct GNUNET_CONFIGURATION_Handle *c,
2090 struct GNUNET_SERVICE_Handle *service)
2094 GNUNET_CONFIGURATION_get_value_time (cfg,
2097 &stun_stale_timeout))
2098 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
2100 /* Check for UPnP */
2102 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2105 if (GNUNET_YES == enable_upnp)
2107 /* check if it works */
2108 if (GNUNET_SYSERR ==
2109 GNUNET_OS_check_helper_binary ("upnpc",
2113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2114 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2115 enable_upnp = GNUNET_SYSERR;
2119 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2121 stats = GNUNET_STATISTICS_create ("nat",
2123 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
2129 * Callback called when a client connects to the service.
2131 * @param cls closure for the service
2132 * @param c the new client that connected to the service
2133 * @param mq the message queue used to send messages to the client
2134 * @return a `struct ClientHandle`
2137 client_connect_cb (void *cls,
2138 struct GNUNET_SERVICE_Client *c,
2139 struct GNUNET_MQ_Handle *mq)
2141 struct ClientHandle *ch;
2143 ch = GNUNET_new (struct ClientHandle);
2146 GNUNET_CONTAINER_DLL_insert (ch_head,
2154 * Callback called when a client disconnected from the service
2156 * @param cls closure for the service
2157 * @param c the client that disconnected
2158 * @param internal_cls a `struct ClientHandle *`
2161 client_disconnect_cb (void *cls,
2162 struct GNUNET_SERVICE_Client *c,
2165 struct ClientHandle *ch = internal_cls;
2167 GNUNET_CONTAINER_DLL_remove (ch_head,
2170 for (unsigned int i=0;i<ch->num_caddrs;i++)
2172 if (NULL != ch->caddrs[i].mh)
2174 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2175 ch->caddrs[i].mh = NULL;
2178 GNUNET_free_non_null (ch->caddrs);
2179 GNUNET_free (ch->hole_external);
2185 * Define "main" method using service macro.
2189 GNUNET_SERVICE_OPTION_NONE,
2192 &client_disconnect_cb,
2194 GNUNET_MQ_hd_var_size (register,
2195 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2196 struct GNUNET_NAT_RegisterMessage,
2198 GNUNET_MQ_hd_var_size (stun,
2199 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2200 struct GNUNET_NAT_HandleStunMessage,
2202 GNUNET_MQ_hd_var_size (request_connection_reversal,
2203 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2204 struct GNUNET_NAT_RequestConnectionReversalMessage,
2206 GNUNET_MQ_hd_var_size (autoconfig_request,
2207 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2208 struct GNUNET_NAT_AutoconfigRequestMessage,
2210 GNUNET_MQ_handler_end ());
2213 #if defined(LINUX) && defined(__GLIBC__)
2217 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2219 void __attribute__ ((constructor))
2220 GNUNET_ARM_memory_init ()
2222 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2223 mallopt (M_TOP_PAD, 1 * 1024);
2228 /* end of gnunet-service-nat.c */