2 This file is part of GNUnet.
3 Copyright (C) 2016 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 ICMP based NAT traversal
32 * - implement & test STUN processing to classify NAT;
33 * basically, open port & try different methods.
34 * - implement "more" autoconfig
35 * - implement NEW logic for external IP detection
39 #include "gnunet_util_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
42 #include "gnunet_statistics_service.h"
43 #include "gnunet_nat_service.h"
44 #include "gnunet-service-nat_stun.h"
45 #include "gnunet-service-nat_mini.h"
46 #include "gnunet-service-nat_helper.h"
52 * How often should we ask the OS about a list of active
55 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
58 * How long do we wait until we forcefully terminate autoconfiguration?
60 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
63 * How long do we wait until we re-try running `external-ip` if the
64 * command failed to terminate nicely?
66 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
69 * How long do we wait until we re-try running `external-ip` if the
70 * command failed (but terminated)?
72 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
75 * How long do we wait until we re-try running `external-ip` if the
78 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
82 * Information we track per client address.
87 * Network address used by the client.
89 struct sockaddr_storage ss;
92 * Handle to active UPnP request where we asked upnpc to open
93 * a port at the NAT. NULL if we do not have such a request
96 struct GNUNET_NAT_MiniHandle *mh;
102 * Internal data structure we track for each of our clients.
110 struct ClientHandle *next;
115 struct ClientHandle *prev;
118 * Underlying handle for this client with the service.
120 struct GNUNET_SERVICE_Client *client;
123 * Message queue for communicating with the client.
125 struct GNUNET_MQ_Handle *mq;
128 * Array of addresses used by the service.
130 struct ClientAddress *caddrs;
133 * What does this client care about?
135 enum GNUNET_NAT_RegisterFlags flags;
138 * Is any of the @e caddrs in a reserved subnet for NAT?
143 * Port we would like as we are configured to use this one for
144 * advertising (in addition to the one we are binding to).
149 * Number of addresses that this service is bound to.
150 * Length of the @e caddrs array.
155 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
163 * List of local addresses this system has.
165 struct LocalAddressList
168 * This is a linked list.
170 struct LocalAddressList *next;
175 struct LocalAddressList *prev;
178 * The address itself (i.e. `struct sockaddr_in` or `struct
179 * sockaddr_in6`, in the respective byte order).
181 struct sockaddr_storage addr;
189 * What type of address is this?
191 enum GNUNET_NAT_AddressClass ac;
197 * External IP address as given to us via some STUN server.
199 struct StunExternalIP
204 struct StunExternalIP *next;
209 struct StunExternalIP *prev;
212 * Task we run to remove this entry when it is stale.
214 struct GNUNET_SCHEDULER_Task *timeout_task;
217 * Our external IP address as reported by the
220 struct sockaddr_in external_addr;
223 * Address of the reporting STUN server. Used to
224 * detect when a STUN server changes its opinion
225 * to more quickly remove stale results.
227 struct sockaddr_storage stun_server_addr;
230 * Number of bytes used in @e stun_server_addr.
232 size_t stun_server_addr_len;
237 * Context for autoconfiguration operations.
239 struct AutoconfigContext
244 struct AutoconfigContext *prev;
249 struct AutoconfigContext *next;
252 * Which client asked the question.
254 struct ClientHandle *ch;
257 * Configuration we are creating.
259 struct GNUNET_CONFIGURATION_Handle *c;
262 * Original configuration (for diffing).
264 struct GNUNET_CONFIGURATION_Handle *orig;
267 * Timeout task to force termination.
269 struct GNUNET_SCHEDULER_Task *timeout_task;
272 * What type of system are we on?
277 * Handle to activity to probe for our external IP.
279 struct GNUNET_NAT_ExternalHandle *probe_external;
282 * #GNUNET_YES if upnpc should be used,
283 * #GNUNET_NO if upnpc should not be used,
284 * #GNUNET_SYSERR if we should simply not change the option.
289 * Status code to return to the client.
291 enum GNUNET_NAT_StatusCode status_code;
294 * NAT type to return to the client.
296 enum GNUNET_NAT_Type type;
301 * DLL of our autoconfiguration operations.
303 static struct AutoconfigContext *ac_head;
306 * DLL of our autoconfiguration operations.
308 static struct AutoconfigContext *ac_tail;
311 * Timeout to use when STUN data is considered stale.
313 static struct GNUNET_TIME_Relative stun_stale_timeout;
316 * Handle to our current configuration.
318 static const struct GNUNET_CONFIGURATION_Handle *cfg;
321 * Handle to the statistics service.
323 static struct GNUNET_STATISTICS_Handle *stats;
326 * Task scheduled to periodically scan our network interfaces.
328 static struct GNUNET_SCHEDULER_Task *scan_task;
331 * Head of client DLL.
333 static struct ClientHandle *ch_head;
336 * Tail of client DLL.
338 static struct ClientHandle *ch_tail;
341 * Head of DLL of local addresses.
343 static struct LocalAddressList *lal_head;
346 * Tail of DLL of local addresses.
348 static struct LocalAddressList *lal_tail;
353 static struct StunExternalIP *se_head;
358 static struct StunExternalIP *se_tail;
361 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
362 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
364 static int enable_upnp;
367 * Task run to obtain our external IP (if #enable_upnp is set
368 * and if we find we have a NATed IP address).
370 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
373 * Handle to our operation to run `external-ip`.
375 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
378 * What is our external IP address as claimed by `external-ip`?
381 static struct in_addr mini_external_ipv4;
385 * Free the DLL starting at #lal_head.
390 struct LocalAddressList *lal;
392 while (NULL != (lal = lal_head))
394 GNUNET_CONTAINER_DLL_remove (lal_head,
403 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
406 * @param cls client who sent the message
407 * @param message the message received
408 * @return #GNUNET_OK if message is well-formed
411 check_register (void *cls,
412 const struct GNUNET_NAT_RegisterMessage *message)
414 uint16_t num_addrs = ntohs (message->num_addrs);
415 const char *off = (const char *) &message[1];
416 size_t left = ntohs (message->header.size) - sizeof (*message);
418 for (unsigned int i=0;i<num_addrs;i++)
421 const struct sockaddr *sa = (const struct sockaddr *) off;
423 if (sizeof (sa_family_t) > left)
426 return GNUNET_SYSERR;
428 switch (sa->sa_family)
431 alen = sizeof (struct sockaddr_in);
434 alen = sizeof (struct sockaddr_in6);
438 alen = sizeof (struct sockaddr_un);
443 return GNUNET_SYSERR;
448 return GNUNET_SYSERR;
456 * Check if @a ip is in @a network with @a bits netmask.
458 * @param network to test
459 * @param ip IP address to test
460 * @param bits bitmask for the network
461 * @return #GNUNET_YES if @a ip is in @a network
464 match_ipv4 (const char *network,
465 const struct in_addr *ip,
474 GNUNET_assert (1 == inet_pton (AF_INET,
477 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
482 * Check if @a ip is in @a network with @a bits netmask.
484 * @param network to test
485 * @param ip IP address to test
486 * @param bits bitmask for the network
487 * @return #GNUNET_YES if @a ip is in @a network
490 match_ipv6 (const char *network,
491 const struct in6_addr *ip,
495 struct in6_addr mask;
500 GNUNET_assert (1 == inet_pton (AF_INET6,
503 memset (&mask, 0, sizeof (mask));
504 if (0 == memcmp (&mask,
511 mask.s6_addr[off++] = 0xFF;
516 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
519 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
520 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
521 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
528 * Test if the given IPv4 address is in a known range
529 * for private networks.
531 * @param ip address to test
532 * @return #GNUNET_YES if @a ip is in a NAT range
535 is_nat_v4 (const struct in_addr *ip)
538 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
539 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
540 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
541 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
542 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
547 * Test if the given IPv6 address is in a known range
548 * for private networks.
550 * @param ip address to test
551 * @return #GNUNET_YES if @a ip is in a NAT range
554 is_nat_v6 (const struct in6_addr *ip)
557 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
558 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
559 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
564 * Closure for #ifc_proc.
566 struct IfcProcContext
570 * Head of DLL of local addresses.
572 struct LocalAddressList *lal_head;
575 * Tail of DLL of local addresses.
577 struct LocalAddressList *lal_tail;
583 * Callback function invoked for each interface found. Adds them
584 * to our new address list.
586 * @param cls a `struct IfcProcContext *`
587 * @param name name of the interface (can be NULL for unknown)
588 * @param isDefault is this presumably the default interface
589 * @param addr address of this interface (can be NULL for unknown or unassigned)
590 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
591 * @param netmask the network mask (can be NULL for unknown or unassigned)
592 * @param addrlen length of the address
593 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
599 const struct sockaddr *addr,
600 const struct sockaddr *broadcast_addr,
601 const struct sockaddr *netmask,
604 struct IfcProcContext *ifc_ctx = cls;
605 struct LocalAddressList *lal;
607 const struct in_addr *ip4;
608 const struct in6_addr *ip6;
609 enum GNUNET_NAT_AddressClass ac;
611 switch (addr->sa_family)
614 alen = sizeof (struct sockaddr_in);
615 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
616 if (match_ipv4 ("127.0.0.0", ip4, 8))
617 ac = GNUNET_NAT_AC_LOOPBACK;
618 else if (is_nat_v4 (ip4))
619 ac = GNUNET_NAT_AC_LAN;
621 ac = GNUNET_NAT_AC_GLOBAL;
624 alen = sizeof (struct sockaddr_in6);
625 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
626 if (match_ipv6 ("::1", ip6, 128))
627 ac = GNUNET_NAT_AC_LOOPBACK;
628 else if (is_nat_v6 (ip6))
629 ac = GNUNET_NAT_AC_LAN;
631 ac = GNUNET_NAT_AC_GLOBAL;
632 if ( (ip6->s6_addr[11] == 0xFF) &&
633 (ip6->s6_addr[12] == 0xFE) )
635 /* contains a MAC, be extra careful! */
636 ac |= GNUNET_NAT_AC_PRIVATE;
648 lal = GNUNET_malloc (sizeof (*lal));
649 lal->af = addr->sa_family;
651 GNUNET_memcpy (&lal->addr,
654 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
662 * Notify client about a change in the list of addresses this peer
665 * @param ac address class of the entry in the list that changed
666 * @param ch client to contact
667 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
668 * @param addr the address that changed
669 * @param addr_len number of bytes in @a addr
672 notify_client (enum GNUNET_NAT_AddressClass ac,
673 struct ClientHandle *ch,
678 struct GNUNET_MQ_Envelope *env;
679 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
681 env = GNUNET_MQ_msg_extra (msg,
683 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
684 msg->add_remove = htonl (add);
685 msg->addr_class = htonl (ac);
686 GNUNET_memcpy (&msg[1],
689 GNUNET_MQ_send (ch->mq,
695 * Check if we should bother to notify this client about this
696 * address change, and if so, do it.
698 * @param delta the entry in the list that changed
699 * @param ch client to check
700 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
703 check_notify_client (struct LocalAddressList *delta,
704 struct ClientHandle *ch,
708 struct sockaddr_in v4;
709 struct sockaddr_in6 v6;
711 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
716 alen = sizeof (struct sockaddr_in);
720 for (unsigned int i=0;i<ch->num_caddrs;i++)
722 const struct sockaddr_in *c4;
724 if (AF_INET != ch->caddrs[i].ss.ss_family)
725 return; /* IPv4 not relevant */
726 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
727 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
728 (0 != c4->sin_addr.s_addr) &&
729 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
730 continue; /* bound to loopback, but this is not loopback */
731 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
732 (0 != c4->sin_addr.s_addr) &&
733 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
734 continue; /* bound to non-loopback, but this is loopback */
735 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
736 (0 != c4->sin_addr.s_addr) &&
737 (! is_nat_v4 (&v4.sin_addr)) )
738 continue; /* based on external-IP, but this IP is not
739 from private address range. */
740 if ( (0 != memcmp (&v4.sin_addr,
742 sizeof (struct in_addr))) &&
743 (0 != c4->sin_addr.s_addr) &&
744 ( (! is_nat_v4 (&c4->sin_addr)) ||
745 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
746 continue; /* this IP is not from private address range,
747 and IP does not match. */
749 /* OK, IP seems relevant, notify client */
750 v4.sin_port = c4->sin_port;
751 notify_client (delta->ac,
759 alen = sizeof (struct sockaddr_in6);
763 for (unsigned int i=0;i<ch->num_caddrs;i++)
765 const struct sockaddr_in6 *c6;
767 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
768 return; /* IPv4 not relevant */
769 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
770 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
771 (0 != memcmp (&c6->sin6_addr,
773 sizeof (struct in6_addr))) &&
774 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
775 continue; /* bound to loopback, but this is not loopback */
776 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
777 (0 != memcmp (&c6->sin6_addr,
779 sizeof (struct in6_addr))) &&
780 match_ipv6 ("::1", &v6.sin6_addr, 128) )
781 continue; /* bound to non-loopback, but this is loopback */
782 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
783 (0 != memcmp (&c6->sin6_addr,
785 sizeof (struct in6_addr))) &&
786 (! is_nat_v6 (&v6.sin6_addr)) )
787 continue; /* based on external-IP, but this IP is not
788 from private address range. */
789 if ( (0 != memcmp (&v6.sin6_addr,
791 sizeof (struct in6_addr))) &&
792 (0 != memcmp (&c6->sin6_addr,
794 sizeof (struct in6_addr))) &&
795 (! is_nat_v6 (&c6->sin6_addr)) )
796 continue; /* this IP is not from private address range,
797 and IP does not match. */
798 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
799 (0 != memcmp (&c6->sin6_addr,
801 sizeof (struct in6_addr))) &&
802 (0 != memcmp (&v6.sin6_addr,
804 sizeof (struct in6_addr))) &&
805 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
806 continue; /* client bound to link-local, and the other address
807 does not match and is not an external IP */
809 /* OK, IP seems relevant, notify client */
810 v6.sin6_port = c6->sin6_port;
811 notify_client (delta->ac,
826 * Notify all clients about a change in the list
827 * of addresses this peer has.
829 * @param delta the entry in the list that changed
830 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
833 notify_clients (struct LocalAddressList *delta,
836 for (struct ClientHandle *ch = ch_head;
839 check_notify_client (delta,
846 * Tell relevant client about a change in our external
849 * @param v4 the external address that changed
850 * @param ch client to check if it cares and possibly notify
851 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
854 check_notify_client_external_ipv4_change (const struct in_addr *v4,
855 struct ClientHandle *ch,
858 struct sockaddr_in sa;
862 /* (1) check if client cares. */
863 if (! ch->natted_address)
865 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
868 for (unsigned int i=0;i<ch->num_caddrs;i++)
870 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
872 if (AF_INET != ss->ss_family)
874 bport = ntohs (((const struct sockaddr_in *) ss)->sin_port);
877 return; /* IPv6-only */
879 /* (2) figure out external port, build sockaddr */
886 sa.sin_family = AF_INET;
888 sa.sin_port = htons (port);
890 /* (3) notify client of change */
891 notify_client (is_nat_v4 (v4)
892 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN_PRIVATE
893 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
902 * Tell relevant clients about a change in our external
905 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
906 * @param v4 the external address that changed
909 notify_clients_external_ipv4_change (int add,
910 const struct in_addr *v4)
912 for (struct ClientHandle *ch = ch_head;
915 check_notify_client_external_ipv4_change (v4,
922 * Task used to run `external-ip` to get our external IPv4
923 * address and pass it to NATed clients if possible.
928 run_external_ip (void *cls);
932 * We learn our current external IP address. If it changed,
933 * notify all of our applicable clients. Also re-schedule
934 * #run_external_ip with an appropriate timeout.
937 * @param addr the address, NULL on errors
938 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
941 handle_external_ip (void *cls,
942 const struct in_addr *addr,
943 enum GNUNET_NAT_StatusCode result)
945 char buf[INET_ADDRSTRLEN];
947 probe_external_ip_op = NULL;
948 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
949 probe_external_ip_task
950 = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
951 ? EXTERN_IP_RETRY_FAILURE
952 : EXTERN_IP_RETRY_SUCCESS,
957 case GNUNET_NAT_ERROR_SUCCESS:
958 if (addr->s_addr == mini_external_ipv4.s_addr)
959 return; /* not change */
960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961 "Our external IP is now %s\n",
966 if (0 != mini_external_ipv4.s_addr)
967 notify_clients_external_ipv4_change (GNUNET_NO,
968 &mini_external_ipv4);
969 mini_external_ipv4 = *addr;
970 notify_clients_external_ipv4_change (GNUNET_YES,
971 &mini_external_ipv4);
974 if (0 != mini_external_ipv4.s_addr)
975 notify_clients_external_ipv4_change (GNUNET_NO,
976 &mini_external_ipv4);
977 mini_external_ipv4.s_addr = 0;
984 * Task used to run `external-ip` to get our external IPv4
985 * address and pass it to NATed clients if possible.
990 run_external_ip (void *cls)
992 probe_external_ip_task
993 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
996 if (NULL != probe_external_ip_op)
998 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
999 probe_external_ip_op = NULL;
1001 probe_external_ip_op
1002 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
1008 * Task we run periodically to scan for network interfaces.
1013 run_scan (void *cls)
1015 struct IfcProcContext ifc_ctx;
1019 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1025 GNUNET_OS_network_interfaces_list (&ifc_proc,
1027 /* remove addresses that disappeared */
1028 for (struct LocalAddressList *lal = lal_head;
1033 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1037 if ( (pos->af == lal->af) &&
1038 (0 == memcmp (&lal->addr,
1040 (AF_INET == lal->af)
1041 ? sizeof (struct sockaddr_in)
1042 : sizeof (struct sockaddr_in6))) )
1045 if (GNUNET_NO == found)
1046 notify_clients (lal,
1050 /* add addresses that appeared */
1051 have_nat = GNUNET_NO;
1052 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1057 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1058 have_nat = GNUNET_YES;
1059 for (struct LocalAddressList *lal = lal_head;
1063 if ( (pos->af == lal->af) &&
1064 (0 == memcmp (&lal->addr,
1066 (AF_INET == lal->af)
1067 ? sizeof (struct sockaddr_in)
1068 : sizeof (struct sockaddr_in6))) )
1071 if (GNUNET_NO == found)
1072 notify_clients (pos,
1075 if ( (GNUNET_YES == have_nat) &&
1076 (GNUNET_YES == enable_upnp) &&
1077 (NULL == probe_external_ip_task) &&
1078 (NULL == probe_external_ip_op) )
1080 probe_external_ip_task
1081 = GNUNET_SCHEDULER_add_now (&run_external_ip,
1084 if ( (GNUNET_NO == have_nat) &&
1085 (GNUNET_YES == enable_upnp) )
1087 if (NULL != probe_external_ip_task)
1089 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1090 probe_external_ip_task = NULL;
1092 if (NULL != probe_external_ip_op)
1094 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1095 probe_external_ip_op = NULL;
1100 lal_head = ifc_ctx.lal_head;
1101 lal_tail = ifc_ctx.lal_tail;
1106 * Function called whenever our set of external addresses
1107 * as created by `upnpc` changes.
1109 * @param cls closure with our `struct ClientHandle *`
1110 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1111 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1112 * @param addr either the previous or the new public IP address
1113 * @param addrlen actual length of the @a addr
1114 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1117 upnp_addr_change_cb (void *cls,
1119 const struct sockaddr *addr,
1121 enum GNUNET_NAT_StatusCode result)
1123 struct ClientHandle *ch = cls;
1124 enum GNUNET_NAT_AddressClass ac;
1128 case GNUNET_NAT_ERROR_SUCCESS:
1129 GNUNET_assert (NULL != addr);
1131 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1132 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1133 case GNUNET_NAT_ERROR_IPC_FAILURE:
1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1135 "Running upnpc failed: %d\n",
1138 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1139 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1140 "external-ip binary not found\n");
1142 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1143 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1144 "external-ip binary could not be run\n");
1146 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1147 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1148 "upnpc failed to create port mapping\n");
1150 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152 "Invalid output from upnpc\n");
1154 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1156 "Invalid address returned by upnpc\n");
1159 GNUNET_break (0); /* should not be possible */
1162 switch (addr->sa_family)
1165 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1166 ? GNUNET_NAT_AC_LAN_PRIVATE
1167 : GNUNET_NAT_AC_EXTERN;
1170 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1171 ? GNUNET_NAT_AC_LAN_PRIVATE
1172 : GNUNET_NAT_AC_EXTERN;
1178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1179 "upnp external address %s: %s\n",
1180 add_remove ? "added" : "removed",
1192 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1193 * We remember the client for updates upon future NAT events.
1195 * @param cls client who sent the message
1196 * @param message the message received
1199 handle_register (void *cls,
1200 const struct GNUNET_NAT_RegisterMessage *message)
1202 struct ClientHandle *ch = cls;
1206 if ( (0 != ch->proto) ||
1207 (NULL != ch->caddrs) )
1209 /* double registration not allowed */
1211 GNUNET_SERVICE_client_drop (ch->client);
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215 "Received REGISTER message from client\n");
1216 ch->flags = message->flags;
1217 ch->proto = message->proto;
1218 ch->adv_port = ntohs (message->adv_port);
1219 ch->num_caddrs = ntohs (message->num_addrs);
1220 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1221 struct ClientAddress);
1222 left = ntohs (message->header.size) - sizeof (*message);
1223 off = (const char *) &message[1];
1224 for (unsigned int i=0;i<ch->num_caddrs;i++)
1227 const struct sockaddr *sa = (const struct sockaddr *) off;
1231 if (sizeof (sa_family_t) > left)
1234 GNUNET_SERVICE_client_drop (ch->client);
1238 switch (sa->sa_family)
1242 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1244 alen = sizeof (struct sockaddr_in);
1245 if (is_nat_v4 (&s4->sin_addr))
1246 is_nat = GNUNET_YES;
1247 port = ntohs (s4->sin_port);
1252 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1254 alen = sizeof (struct sockaddr_in6);
1255 if (is_nat_v6 (&s6->sin6_addr))
1256 is_nat = GNUNET_YES;
1257 port = ntohs (s6->sin6_port);
1262 alen = sizeof (struct sockaddr_un);
1268 GNUNET_SERVICE_client_drop (ch->client);
1272 GNUNET_assert (alen <= left);
1273 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1274 GNUNET_memcpy (&ch->caddrs[i].ss,
1278 /* If applicable, try UPNPC NAT punching */
1281 ( (IPPROTO_TCP == ch->proto) ||
1282 (IPPROTO_UDP == ch->proto) ) )
1284 ch->natted_address = GNUNET_YES;
1286 = GNUNET_NAT_mini_map_start (port,
1287 IPPROTO_TCP == ch->proto,
1288 &upnp_addr_change_cb,
1294 /* Actually send IP address list to client */
1295 for (struct LocalAddressList *lal = lal_head;
1299 check_notify_client (lal,
1303 /* Also consider IPv4 determined by `external-ip` */
1304 if (0 != mini_external_ipv4.s_addr)
1306 check_notify_client_external_ipv4_change (&mini_external_ipv4,
1310 GNUNET_SERVICE_client_continue (ch->client);
1315 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1318 * @param cls client who sent the message
1319 * @param message the message received
1320 * @return #GNUNET_OK if message is well-formed
1323 check_stun (void *cls,
1324 const struct GNUNET_NAT_HandleStunMessage *message)
1326 size_t sa_len = ntohs (message->sender_addr_size);
1327 size_t expect = sa_len + ntohs (message->payload_size);
1329 if (ntohs (message->header.size) - sizeof (*message) != expect)
1332 return GNUNET_SYSERR;
1334 if (sa_len < sizeof (sa_family_t))
1337 return GNUNET_SYSERR;
1344 * Notify all clients about our external IP address
1345 * as reported by the STUN server.
1347 * @param ip the external IP
1348 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1351 notify_clients_stun_change (const struct sockaddr_in *ip,
1354 for (struct ClientHandle *ch = ch_head;
1358 struct sockaddr_in v4;
1359 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1360 struct GNUNET_MQ_Envelope *env;
1362 if (! ch->natted_address)
1365 v4.sin_port = htons (ch->adv_port);
1366 env = GNUNET_MQ_msg_extra (msg,
1368 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1369 msg->add_remove = htonl ((int32_t) add);
1370 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1371 GNUNET_NAT_AC_GLOBAL);
1372 GNUNET_memcpy (&msg[1],
1375 GNUNET_MQ_send (ch->mq,
1382 * Function to be called when we decide that an
1383 * external IP address as told to us by a STUN
1384 * server has gone stale.
1386 * @param cls the `struct StunExternalIP` to drop
1389 stun_ip_timeout (void *cls)
1391 struct StunExternalIP *se = cls;
1393 se->timeout_task = NULL;
1394 notify_clients_stun_change (&se->external_addr,
1396 GNUNET_CONTAINER_DLL_remove (se_head,
1404 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1407 * @param cls client who sent the message
1408 * @param message the message received
1411 handle_stun (void *cls,
1412 const struct GNUNET_NAT_HandleStunMessage *message)
1414 struct ClientHandle *ch = cls;
1415 const char *buf = (const char *) &message[1];
1416 const struct sockaddr *sa;
1417 const void *payload;
1419 size_t payload_size;
1420 struct sockaddr_in external_addr;
1422 sa_len = ntohs (message->sender_addr_size);
1423 payload_size = ntohs (message->payload_size);
1424 sa = (const struct sockaddr *) &buf[0];
1425 payload = (const struct sockaddr *) &buf[sa_len];
1426 switch (sa->sa_family)
1429 if (sa_len != sizeof (struct sockaddr_in))
1432 GNUNET_SERVICE_client_drop (ch->client);
1437 if (sa_len != sizeof (struct sockaddr_in6))
1440 GNUNET_SERVICE_client_drop (ch->client);
1445 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1446 "Received HANDLE_STUN message from client\n");
1448 GNUNET_NAT_stun_handle_packet_ (payload,
1452 /* We now know that a server at "sa" claims that
1453 we are visible at IP "external_addr".
1455 We should (for some fixed period of time) tell
1456 all of our clients that listen to a NAT'ed address
1457 that they might want to consider the given 'external_ip'
1458 as their public IP address (this includes TCP and UDP
1459 clients, even if only UDP sends STUN requests).
1461 If we do not get a renewal, the "external_addr" should be
1462 removed again. The timeout frequency should be configurable
1463 (with a sane default), so that the UDP plugin can tell how
1464 often to re-request STUN.
1466 struct StunExternalIP *se;
1468 /* Check if we had a prior response from this STUN server */
1469 for (se = se_head; NULL != se; se = se->next)
1471 if ( (se->stun_server_addr_len != sa_len) ||
1473 &se->stun_server_addr,
1475 continue; /* different STUN server */
1476 if (0 != memcmp (&external_addr,
1478 sizeof (struct sockaddr_in)))
1480 /* external IP changed, update! */
1481 notify_clients_stun_change (&se->external_addr,
1483 se->external_addr = external_addr;
1484 notify_clients_stun_change (&se->external_addr,
1487 /* update timeout */
1488 GNUNET_SCHEDULER_cancel (se->timeout_task);
1490 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1495 /* STUN server is completely new, create fresh entry */
1496 se = GNUNET_new (struct StunExternalIP);
1497 se->external_addr = external_addr;
1498 GNUNET_memcpy (&se->stun_server_addr,
1501 se->stun_server_addr_len = sa_len;
1502 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1505 GNUNET_CONTAINER_DLL_insert (se_head,
1508 notify_clients_stun_change (&se->external_addr,
1511 GNUNET_SERVICE_client_continue (ch->client);
1517 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1520 * @param cls client who sent the message
1521 * @param message the message received
1522 * @return #GNUNET_OK if message is well-formed
1525 check_request_connection_reversal (void *cls,
1526 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1530 expect = ntohs (message->local_addr_size)
1531 + ntohs (message->remote_addr_size);
1532 if (ntohs (message->header.size) - sizeof (*message) != expect)
1535 return GNUNET_SYSERR;
1542 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1543 * message from client.
1545 * @param cls client who sent the message
1546 * @param message the message received
1549 handle_request_connection_reversal (void *cls,
1550 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1552 struct ClientHandle *ch = cls;
1553 const char *buf = (const char *) &message[1];
1554 size_t local_sa_len = ntohs (message->local_addr_size);
1555 size_t remote_sa_len = ntohs (message->remote_addr_size);
1556 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1557 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1558 const struct sockaddr_in *l4 = NULL;
1559 const struct sockaddr_in *r4;
1562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1563 "Received REQUEST CONNECTION REVERSAL message from client\n");
1564 switch (local_sa->sa_family)
1567 if (local_sa_len != sizeof (struct sockaddr_in))
1570 GNUNET_SERVICE_client_drop (ch->client);
1573 l4 = (const struct sockaddr_in *) local_sa;
1576 if (local_sa_len != sizeof (struct sockaddr_in6))
1579 GNUNET_SERVICE_client_drop (ch->client);
1582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1583 _("Connection reversal for IPv6 not supported yet\n"));
1584 ret = GNUNET_SYSERR;
1588 GNUNET_SERVICE_client_drop (ch->client);
1591 switch (remote_sa->sa_family)
1594 if (remote_sa_len != sizeof (struct sockaddr_in))
1597 GNUNET_SERVICE_client_drop (ch->client);
1600 r4 = (const struct sockaddr_in *) remote_sa;
1601 ret = GN_request_connection_reversal (&l4->sin_addr,
1602 ntohs (l4->sin_port),
1606 if (remote_sa_len != sizeof (struct sockaddr_in6))
1609 GNUNET_SERVICE_client_drop (ch->client);
1612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1613 _("Connection reversal for IPv6 not supported yet\n"));
1614 ret = GNUNET_SYSERR;
1618 GNUNET_SERVICE_client_drop (ch->client);
1621 if (GNUNET_OK != ret)
1622 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1623 _("Connection reversal request failed\n"));
1624 GNUNET_SERVICE_client_continue (ch->client);
1629 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1632 * @param cls client who sent the message
1633 * @param message the message received
1634 * @return #GNUNET_OK if message is well-formed
1637 check_autoconfig_request (void *cls,
1638 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1640 return GNUNET_OK; /* checked later */
1645 * Stop all pending activities with respect to the @a ac
1647 * @param ac autoconfiguration to terminate activities for
1650 terminate_ac_activities (struct AutoconfigContext *ac)
1652 if (NULL != ac->probe_external)
1654 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1655 ac->probe_external = NULL;
1657 if (NULL != ac->timeout_task)
1659 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1660 ac->timeout_task = NULL;
1666 * Finish handling the autoconfiguration request and send
1667 * the response to the client.
1669 * @param cls the `struct AutoconfigContext` to conclude
1672 conclude_autoconfig_request (void *cls)
1674 struct AutoconfigContext *ac = cls;
1675 struct ClientHandle *ch = ac->ch;
1676 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1677 struct GNUNET_MQ_Envelope *env;
1680 struct GNUNET_CONFIGURATION_Handle *diff;
1682 ac->timeout_task = NULL;
1683 terminate_ac_activities (ac);
1685 /* Send back response */
1686 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1688 buf = GNUNET_CONFIGURATION_serialize (diff,
1690 GNUNET_CONFIGURATION_destroy (diff);
1691 env = GNUNET_MQ_msg_extra (arm,
1693 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1694 arm->status_code = htonl ((uint32_t) ac->status_code);
1695 arm->type = htonl ((uint32_t) ac->type);
1696 GNUNET_memcpy (&arm[1],
1700 GNUNET_MQ_send (ch->mq,
1704 GNUNET_free (ac->system_type);
1705 GNUNET_CONFIGURATION_destroy (ac->orig);
1706 GNUNET_CONFIGURATION_destroy (ac->c);
1707 GNUNET_CONTAINER_DLL_remove (ac_head,
1711 GNUNET_SERVICE_client_continue (ch->client);
1716 * Check if all autoconfiguration operations have concluded,
1717 * and if they have, send the result back to the client.
1719 * @param ac autoconfiguation context to check
1722 check_autoconfig_finished (struct AutoconfigContext *ac)
1724 if (NULL != ac->probe_external)
1726 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1728 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1734 * Update ENABLE_UPNPC configuration option.
1736 * @param ac autoconfiguration to update
1739 update_enable_upnpc_option (struct AutoconfigContext *ac)
1741 switch (ac->enable_upnpc)
1744 GNUNET_CONFIGURATION_set_value_string (ac->c,
1750 GNUNET_CONFIGURATION_set_value_string (ac->c,
1756 /* We are unsure, do not change option */
1763 * Handle result from external IP address probe during
1764 * autoconfiguration.
1766 * @param cls our `struct AutoconfigContext`
1767 * @param addr the address, NULL on errors
1768 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1771 auto_external_result_cb (void *cls,
1772 const struct in_addr *addr,
1773 enum GNUNET_NAT_StatusCode result)
1775 struct AutoconfigContext *ac = cls;
1777 ac->probe_external = NULL;
1780 case GNUNET_NAT_ERROR_SUCCESS:
1781 ac->enable_upnpc = GNUNET_YES;
1783 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1784 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1785 case GNUNET_NAT_ERROR_IPC_FAILURE:
1786 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1787 "Disabling UPNPC: %d\n",
1789 ac->enable_upnpc = GNUNET_NO; /* did not work */
1792 GNUNET_break (0); /* unexpected */
1793 ac->enable_upnpc = GNUNET_SYSERR;
1796 update_enable_upnpc_option (ac);
1797 check_autoconfig_finished (ac);
1802 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1805 * @param cls client who sent the message
1806 * @param message the message received
1809 handle_autoconfig_request (void *cls,
1810 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1812 struct ClientHandle *ch = cls;
1813 size_t left = ntohs (message->header.size) - sizeof (*message);
1814 struct LocalAddressList *lal;
1815 struct AutoconfigContext *ac;
1817 ac = GNUNET_new (struct AutoconfigContext);
1818 ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
1820 ac->c = GNUNET_CONFIGURATION_create ();
1822 GNUNET_CONFIGURATION_deserialize (ac->c,
1823 (const char *) &message[1],
1828 GNUNET_SERVICE_client_drop (ch->client);
1829 GNUNET_CONFIGURATION_destroy (ac->c);
1833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1834 "Received REQUEST_AUTO_CONFIG message from client\n");
1837 GNUNET_CONFIGURATION_get_value_string (ac->c,
1841 ac->system_type = GNUNET_strdup ("UNKNOWN");
1843 GNUNET_CONTAINER_DLL_insert (ac_head,
1847 = GNUNET_CONFIGURATION_dup (ac->c);
1849 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1850 &conclude_autoconfig_request,
1852 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1854 /* Probe for upnpc */
1855 if (GNUNET_SYSERR ==
1856 GNUNET_OS_check_helper_binary ("upnpc",
1860 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1861 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1862 ac->enable_upnpc = GNUNET_NO;
1866 for (lal = lal_head; NULL != lal; lal = lal->next)
1867 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1868 /* we are behind NAT, useful to try upnpc */
1869 ac->enable_upnpc = GNUNET_YES;
1871 if (GNUNET_YES == ac->enable_upnpc)
1873 /* If we are a mobile device, always leave it on as the network
1874 may change to one that supports UPnP anytime. If we are
1875 stationary, check if our network actually supports UPnP, and if
1877 if ( (0 == strcasecmp (ac->system_type,
1878 "INFRASTRUCTURE")) ||
1879 (0 == strcasecmp (ac->system_type,
1882 /* Check if upnpc gives us an external IP */
1884 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1888 if (NULL == ac->probe_external)
1889 update_enable_upnpc_option (ac);
1891 /* Finally, check if we are already done */
1892 check_autoconfig_finished (ac);
1897 * Task run during shutdown.
1902 shutdown_task (void *cls)
1904 struct StunExternalIP *se;
1905 struct AutoconfigContext *ac;
1907 while (NULL != (ac = ac_head))
1909 GNUNET_CONTAINER_DLL_remove (ac_head,
1912 terminate_ac_activities (ac);
1915 while (NULL != (se = se_head))
1917 GNUNET_CONTAINER_DLL_remove (se_head,
1920 GNUNET_SCHEDULER_cancel (se->timeout_task);
1923 if (NULL != probe_external_ip_task)
1925 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1926 probe_external_ip_task = NULL;
1928 if (NULL != probe_external_ip_op)
1930 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1931 probe_external_ip_op = NULL;
1933 if (NULL != scan_task)
1935 GNUNET_SCHEDULER_cancel (scan_task);
1940 GNUNET_STATISTICS_destroy (stats,
1949 * Setup NAT service.
1951 * @param cls closure
1952 * @param c configuration to use
1953 * @param service the initialized service
1957 const struct GNUNET_CONFIGURATION_Handle *c,
1958 struct GNUNET_SERVICE_Handle *service)
1962 GNUNET_CONFIGURATION_get_value_time (cfg,
1965 &stun_stale_timeout))
1966 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1968 /* Check for UPnP */
1970 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1973 if (GNUNET_YES == enable_upnp)
1975 /* check if it works */
1976 if (GNUNET_SYSERR ==
1977 GNUNET_OS_check_helper_binary ("upnpc",
1981 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1982 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1983 enable_upnp = GNUNET_SYSERR;
1987 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1989 stats = GNUNET_STATISTICS_create ("nat",
1991 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1997 * Callback called when a client connects to the service.
1999 * @param cls closure for the service
2000 * @param c the new client that connected to the service
2001 * @param mq the message queue used to send messages to the client
2002 * @return a `struct ClientHandle`
2005 client_connect_cb (void *cls,
2006 struct GNUNET_SERVICE_Client *c,
2007 struct GNUNET_MQ_Handle *mq)
2009 struct ClientHandle *ch;
2011 ch = GNUNET_new (struct ClientHandle);
2014 GNUNET_CONTAINER_DLL_insert (ch_head,
2022 * Callback called when a client disconnected from the service
2024 * @param cls closure for the service
2025 * @param c the client that disconnected
2026 * @param internal_cls a `struct ClientHandle *`
2029 client_disconnect_cb (void *cls,
2030 struct GNUNET_SERVICE_Client *c,
2033 struct ClientHandle *ch = internal_cls;
2035 GNUNET_CONTAINER_DLL_remove (ch_head,
2038 for (unsigned int i=0;i<ch->num_caddrs;i++)
2040 if (NULL != ch->caddrs[i].mh)
2042 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2043 ch->caddrs[i].mh = NULL;
2046 GNUNET_free_non_null (ch->caddrs);
2052 * Define "main" method using service macro.
2056 GNUNET_SERVICE_OPTION_NONE,
2059 &client_disconnect_cb,
2061 GNUNET_MQ_hd_var_size (register,
2062 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2063 struct GNUNET_NAT_RegisterMessage,
2065 GNUNET_MQ_hd_var_size (stun,
2066 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2067 struct GNUNET_NAT_HandleStunMessage,
2069 GNUNET_MQ_hd_var_size (request_connection_reversal,
2070 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2071 struct GNUNET_NAT_RequestConnectionReversalMessage,
2073 GNUNET_MQ_hd_var_size (autoconfig_request,
2074 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2075 struct GNUNET_NAT_AutoconfigRequestMessage,
2077 GNUNET_MQ_handler_end ());
2080 #if defined(LINUX) && defined(__GLIBC__)
2084 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2086 void __attribute__ ((constructor))
2087 GNUNET_ARM_memory_init ()
2089 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2090 mallopt (M_TOP_PAD, 1 * 1024);
2095 /* end of gnunet-service-nat.c */