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 "more" autoconfig:
33 * re-work gnunet-nat-server & integrate!
34 * - implement & test STUN processing to classify NAT;
35 * basically, open port & try different methods.
36 * - implement NEW logic for external IP detection
40 #include "gnunet_util_lib.h"
41 #include "gnunet_protocols.h"
42 #include "gnunet_signatures.h"
43 #include "gnunet_statistics_service.h"
44 #include "gnunet_nat_service.h"
45 #include "gnunet-service-nat_stun.h"
46 #include "gnunet-service-nat_mini.h"
47 #include "gnunet-service-nat_helper.h"
53 * How often should we ask the OS about a list of active
56 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
59 * How long do we wait until we forcefully terminate autoconfiguration?
61 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
64 * How long do we wait until we re-try running `external-ip` if the
65 * command failed to terminate nicely?
67 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
70 * How long do we wait until we re-try running `external-ip` if the
71 * command failed (but terminated)?
73 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
76 * How long do we wait until we re-try running `external-ip` if the
79 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
83 * Information we track per client address.
88 * Network address used by the client.
90 struct sockaddr_storage ss;
93 * Handle to active UPnP request where we asked upnpc to open
94 * a port at the NAT. NULL if we do not have such a request
97 struct GNUNET_NAT_MiniHandle *mh;
103 * Internal data structure we track for each of our clients.
111 struct ClientHandle *next;
116 struct ClientHandle *prev;
119 * Underlying handle for this client with the service.
121 struct GNUNET_SERVICE_Client *client;
124 * Message queue for communicating with the client.
126 struct GNUNET_MQ_Handle *mq;
129 * Array of addresses used by the service.
131 struct ClientAddress *caddrs;
134 * What does this client care about?
136 enum GNUNET_NAT_RegisterFlags flags;
139 * Is any of the @e caddrs in a reserved subnet for NAT?
144 * Port we would like as we are configured to use this one for
145 * advertising (in addition to the one we are binding to).
150 * Number of addresses that this service is bound to.
151 * Length of the @e caddrs array.
156 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
164 * List of local addresses this system has.
166 struct LocalAddressList
169 * This is a linked list.
171 struct LocalAddressList *next;
176 struct LocalAddressList *prev;
179 * The address itself (i.e. `struct sockaddr_in` or `struct
180 * sockaddr_in6`, in the respective byte order).
182 struct sockaddr_storage addr;
190 * What type of address is this?
192 enum GNUNET_NAT_AddressClass ac;
198 * External IP address as given to us via some STUN server.
200 struct StunExternalIP
205 struct StunExternalIP *next;
210 struct StunExternalIP *prev;
213 * Task we run to remove this entry when it is stale.
215 struct GNUNET_SCHEDULER_Task *timeout_task;
218 * Our external IP address as reported by the
221 struct sockaddr_in external_addr;
224 * Address of the reporting STUN server. Used to
225 * detect when a STUN server changes its opinion
226 * to more quickly remove stale results.
228 struct sockaddr_storage stun_server_addr;
231 * Number of bytes used in @e stun_server_addr.
233 size_t stun_server_addr_len;
238 * Context for autoconfiguration operations.
240 struct AutoconfigContext
245 struct AutoconfigContext *prev;
250 struct AutoconfigContext *next;
253 * Which client asked the question.
255 struct ClientHandle *ch;
258 * Configuration we are creating.
260 struct GNUNET_CONFIGURATION_Handle *c;
263 * Original configuration (for diffing).
265 struct GNUNET_CONFIGURATION_Handle *orig;
268 * Timeout task to force termination.
270 struct GNUNET_SCHEDULER_Task *timeout_task;
273 * What type of system are we on?
278 * Handle to activity to probe for our external IP.
280 struct GNUNET_NAT_ExternalHandle *probe_external;
283 * #GNUNET_YES if upnpc should be used,
284 * #GNUNET_NO if upnpc should not be used,
285 * #GNUNET_SYSERR if we should simply not change the option.
290 * Status code to return to the client.
292 enum GNUNET_NAT_StatusCode status_code;
295 * NAT type to return to the client.
297 enum GNUNET_NAT_Type type;
302 * DLL of our autoconfiguration operations.
304 static struct AutoconfigContext *ac_head;
307 * DLL of our autoconfiguration operations.
309 static struct AutoconfigContext *ac_tail;
312 * Timeout to use when STUN data is considered stale.
314 static struct GNUNET_TIME_Relative stun_stale_timeout;
317 * Handle to our current configuration.
319 static const struct GNUNET_CONFIGURATION_Handle *cfg;
322 * Handle to the statistics service.
324 static struct GNUNET_STATISTICS_Handle *stats;
327 * Task scheduled to periodically scan our network interfaces.
329 static struct GNUNET_SCHEDULER_Task *scan_task;
332 * Head of client DLL.
334 static struct ClientHandle *ch_head;
337 * Tail of client DLL.
339 static struct ClientHandle *ch_tail;
342 * Head of DLL of local addresses.
344 static struct LocalAddressList *lal_head;
347 * Tail of DLL of local addresses.
349 static struct LocalAddressList *lal_tail;
354 static struct StunExternalIP *se_head;
359 static struct StunExternalIP *se_tail;
362 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
363 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
365 static int enable_upnp;
368 * Task run to obtain our external IP (if #enable_upnp is set
369 * and if we find we have a NATed IP address).
371 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
374 * Handle to our operation to run `external-ip`.
376 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
379 * What is our external IP address as claimed by `external-ip`?
382 static struct in_addr mini_external_ipv4;
386 * Free the DLL starting at #lal_head.
391 struct LocalAddressList *lal;
393 while (NULL != (lal = lal_head))
395 GNUNET_CONTAINER_DLL_remove (lal_head,
404 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
407 * @param cls client who sent the message
408 * @param message the message received
409 * @return #GNUNET_OK if message is well-formed
412 check_register (void *cls,
413 const struct GNUNET_NAT_RegisterMessage *message)
415 uint16_t num_addrs = ntohs (message->num_addrs);
416 const char *off = (const char *) &message[1];
417 size_t left = ntohs (message->header.size) - sizeof (*message);
419 for (unsigned int i=0;i<num_addrs;i++)
422 const struct sockaddr *sa = (const struct sockaddr *) off;
424 if (sizeof (sa_family_t) > left)
427 return GNUNET_SYSERR;
429 switch (sa->sa_family)
432 alen = sizeof (struct sockaddr_in);
435 alen = sizeof (struct sockaddr_in6);
439 alen = sizeof (struct sockaddr_un);
444 return GNUNET_SYSERR;
449 return GNUNET_SYSERR;
457 * Check if @a ip is in @a network with @a bits netmask.
459 * @param network to test
460 * @param ip IP address to test
461 * @param bits bitmask for the network
462 * @return #GNUNET_YES if @a ip is in @a network
465 match_ipv4 (const char *network,
466 const struct in_addr *ip,
475 GNUNET_assert (1 == inet_pton (AF_INET,
478 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
483 * Check if @a ip is in @a network with @a bits netmask.
485 * @param network to test
486 * @param ip IP address to test
487 * @param bits bitmask for the network
488 * @return #GNUNET_YES if @a ip is in @a network
491 match_ipv6 (const char *network,
492 const struct in6_addr *ip,
496 struct in6_addr mask;
501 GNUNET_assert (1 == inet_pton (AF_INET6,
504 memset (&mask, 0, sizeof (mask));
505 if (0 == memcmp (&mask,
512 mask.s6_addr[off++] = 0xFF;
517 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
520 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
521 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
522 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
529 * Test if the given IPv4 address is in a known range
530 * for private networks.
532 * @param ip address to test
533 * @return #GNUNET_YES if @a ip is in a NAT range
536 is_nat_v4 (const struct in_addr *ip)
539 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
540 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
541 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
542 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
543 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
548 * Test if the given IPv6 address is in a known range
549 * for private networks.
551 * @param ip address to test
552 * @return #GNUNET_YES if @a ip is in a NAT range
555 is_nat_v6 (const struct in6_addr *ip)
558 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
559 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
560 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
565 * Closure for #ifc_proc.
567 struct IfcProcContext
571 * Head of DLL of local addresses.
573 struct LocalAddressList *lal_head;
576 * Tail of DLL of local addresses.
578 struct LocalAddressList *lal_tail;
584 * Callback function invoked for each interface found. Adds them
585 * to our new address list.
587 * @param cls a `struct IfcProcContext *`
588 * @param name name of the interface (can be NULL for unknown)
589 * @param isDefault is this presumably the default interface
590 * @param addr address of this interface (can be NULL for unknown or unassigned)
591 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
592 * @param netmask the network mask (can be NULL for unknown or unassigned)
593 * @param addrlen length of the address
594 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
600 const struct sockaddr *addr,
601 const struct sockaddr *broadcast_addr,
602 const struct sockaddr *netmask,
605 struct IfcProcContext *ifc_ctx = cls;
606 struct LocalAddressList *lal;
608 const struct in_addr *ip4;
609 const struct in6_addr *ip6;
610 enum GNUNET_NAT_AddressClass ac;
612 switch (addr->sa_family)
615 alen = sizeof (struct sockaddr_in);
616 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
617 if (match_ipv4 ("127.0.0.0", ip4, 8))
618 ac = GNUNET_NAT_AC_LOOPBACK;
619 else if (is_nat_v4 (ip4))
620 ac = GNUNET_NAT_AC_LAN;
622 ac = GNUNET_NAT_AC_GLOBAL;
625 alen = sizeof (struct sockaddr_in6);
626 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
627 if (match_ipv6 ("::1", ip6, 128))
628 ac = GNUNET_NAT_AC_LOOPBACK;
629 else if (is_nat_v6 (ip6))
630 ac = GNUNET_NAT_AC_LAN;
632 ac = GNUNET_NAT_AC_GLOBAL;
633 if ( (ip6->s6_addr[11] == 0xFF) &&
634 (ip6->s6_addr[12] == 0xFE) )
636 /* contains a MAC, be extra careful! */
637 ac |= GNUNET_NAT_AC_PRIVATE;
649 lal = GNUNET_malloc (sizeof (*lal));
650 lal->af = addr->sa_family;
652 GNUNET_memcpy (&lal->addr,
655 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
663 * Notify client about a change in the list of addresses this peer
666 * @param ac address class of the entry in the list that changed
667 * @param ch client to contact
668 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
669 * @param addr the address that changed
670 * @param addr_len number of bytes in @a addr
673 notify_client (enum GNUNET_NAT_AddressClass ac,
674 struct ClientHandle *ch,
679 struct GNUNET_MQ_Envelope *env;
680 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
682 env = GNUNET_MQ_msg_extra (msg,
684 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
685 msg->add_remove = htonl (add);
686 msg->addr_class = htonl (ac);
687 GNUNET_memcpy (&msg[1],
690 GNUNET_MQ_send (ch->mq,
696 * Check if we should bother to notify this client about this
697 * address change, and if so, do it.
699 * @param delta the entry in the list that changed
700 * @param ch client to check
701 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
704 check_notify_client (struct LocalAddressList *delta,
705 struct ClientHandle *ch,
709 struct sockaddr_in v4;
710 struct sockaddr_in6 v6;
712 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
717 alen = sizeof (struct sockaddr_in);
721 for (unsigned int i=0;i<ch->num_caddrs;i++)
723 const struct sockaddr_in *c4;
725 if (AF_INET != ch->caddrs[i].ss.ss_family)
726 return; /* IPv4 not relevant */
727 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
728 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
729 (0 != c4->sin_addr.s_addr) &&
730 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
731 continue; /* bound to loopback, but this is not loopback */
732 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
733 (0 != c4->sin_addr.s_addr) &&
734 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
735 continue; /* bound to non-loopback, but this is loopback */
736 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
737 (0 != c4->sin_addr.s_addr) &&
738 (! is_nat_v4 (&v4.sin_addr)) )
739 continue; /* based on external-IP, but this IP is not
740 from private address range. */
741 if ( (0 != memcmp (&v4.sin_addr,
743 sizeof (struct in_addr))) &&
744 (0 != c4->sin_addr.s_addr) &&
745 ( (! is_nat_v4 (&c4->sin_addr)) ||
746 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
747 continue; /* this IP is not from private address range,
748 and IP does not match. */
750 /* OK, IP seems relevant, notify client */
751 v4.sin_port = c4->sin_port;
752 notify_client (delta->ac,
760 alen = sizeof (struct sockaddr_in6);
764 for (unsigned int i=0;i<ch->num_caddrs;i++)
766 const struct sockaddr_in6 *c6;
768 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
769 return; /* IPv4 not relevant */
770 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
771 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
772 (0 != memcmp (&c6->sin6_addr,
774 sizeof (struct in6_addr))) &&
775 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
776 continue; /* bound to loopback, but this is not loopback */
777 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
778 (0 != memcmp (&c6->sin6_addr,
780 sizeof (struct in6_addr))) &&
781 match_ipv6 ("::1", &v6.sin6_addr, 128) )
782 continue; /* bound to non-loopback, but this is loopback */
783 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
784 (0 != memcmp (&c6->sin6_addr,
786 sizeof (struct in6_addr))) &&
787 (! is_nat_v6 (&v6.sin6_addr)) )
788 continue; /* based on external-IP, but this IP is not
789 from private address range. */
790 if ( (0 != memcmp (&v6.sin6_addr,
792 sizeof (struct in6_addr))) &&
793 (0 != memcmp (&c6->sin6_addr,
795 sizeof (struct in6_addr))) &&
796 (! is_nat_v6 (&c6->sin6_addr)) )
797 continue; /* this IP is not from private address range,
798 and IP does not match. */
799 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
800 (0 != memcmp (&c6->sin6_addr,
802 sizeof (struct in6_addr))) &&
803 (0 != memcmp (&v6.sin6_addr,
805 sizeof (struct in6_addr))) &&
806 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
807 continue; /* client bound to link-local, and the other address
808 does not match and is not an external IP */
810 /* OK, IP seems relevant, notify client */
811 v6.sin6_port = c6->sin6_port;
812 notify_client (delta->ac,
827 * Notify all clients about a change in the list
828 * of addresses this peer has.
830 * @param delta the entry in the list that changed
831 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
834 notify_clients (struct LocalAddressList *delta,
837 for (struct ClientHandle *ch = ch_head;
840 check_notify_client (delta,
847 * Tell relevant client about a change in our external
850 * @param v4 the external address that changed
851 * @param ch client to check if it cares and possibly notify
852 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
855 check_notify_client_external_ipv4_change (const struct in_addr *v4,
856 struct ClientHandle *ch,
859 struct sockaddr_in sa;
863 /* (1) check if client cares. */
864 if (! ch->natted_address)
866 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
869 for (unsigned int i=0;i<ch->num_caddrs;i++)
871 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
873 if (AF_INET != ss->ss_family)
875 bport = ntohs (((const struct sockaddr_in *) ss)->sin_port);
878 return; /* IPv6-only */
880 /* (2) figure out external port, build sockaddr */
887 sa.sin_family = AF_INET;
889 sa.sin_port = htons (port);
891 /* (3) notify client of change */
892 notify_client (is_nat_v4 (v4)
893 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN_PRIVATE
894 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
903 * Tell relevant clients about a change in our external
906 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
907 * @param v4 the external address that changed
910 notify_clients_external_ipv4_change (int add,
911 const struct in_addr *v4)
913 for (struct ClientHandle *ch = ch_head;
916 check_notify_client_external_ipv4_change (v4,
923 * Task used to run `external-ip` to get our external IPv4
924 * address and pass it to NATed clients if possible.
929 run_external_ip (void *cls);
933 * We learn our current external IP address. If it changed,
934 * notify all of our applicable clients. Also re-schedule
935 * #run_external_ip with an appropriate timeout.
938 * @param addr the address, NULL on errors
939 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
942 handle_external_ip (void *cls,
943 const struct in_addr *addr,
944 enum GNUNET_NAT_StatusCode result)
946 char buf[INET_ADDRSTRLEN];
948 probe_external_ip_op = NULL;
949 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
950 probe_external_ip_task
951 = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
952 ? EXTERN_IP_RETRY_FAILURE
953 : EXTERN_IP_RETRY_SUCCESS,
958 case GNUNET_NAT_ERROR_SUCCESS:
959 if (addr->s_addr == mini_external_ipv4.s_addr)
960 return; /* not change */
961 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
962 "Our external IP is now %s\n",
967 if (0 != mini_external_ipv4.s_addr)
968 notify_clients_external_ipv4_change (GNUNET_NO,
969 &mini_external_ipv4);
970 mini_external_ipv4 = *addr;
971 notify_clients_external_ipv4_change (GNUNET_YES,
972 &mini_external_ipv4);
975 if (0 != mini_external_ipv4.s_addr)
976 notify_clients_external_ipv4_change (GNUNET_NO,
977 &mini_external_ipv4);
978 mini_external_ipv4.s_addr = 0;
985 * Task used to run `external-ip` to get our external IPv4
986 * address and pass it to NATed clients if possible.
991 run_external_ip (void *cls)
993 probe_external_ip_task
994 = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
997 if (NULL != probe_external_ip_op)
999 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1000 probe_external_ip_op = NULL;
1002 probe_external_ip_op
1003 = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
1009 * Task we run periodically to scan for network interfaces.
1014 run_scan (void *cls)
1016 struct IfcProcContext ifc_ctx;
1020 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1026 GNUNET_OS_network_interfaces_list (&ifc_proc,
1028 /* remove addresses that disappeared */
1029 for (struct LocalAddressList *lal = lal_head;
1034 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1038 if ( (pos->af == lal->af) &&
1039 (0 == memcmp (&lal->addr,
1041 (AF_INET == lal->af)
1042 ? sizeof (struct sockaddr_in)
1043 : sizeof (struct sockaddr_in6))) )
1046 if (GNUNET_NO == found)
1047 notify_clients (lal,
1051 /* add addresses that appeared */
1052 have_nat = GNUNET_NO;
1053 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1058 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1059 have_nat = GNUNET_YES;
1060 for (struct LocalAddressList *lal = lal_head;
1064 if ( (pos->af == lal->af) &&
1065 (0 == memcmp (&lal->addr,
1067 (AF_INET == lal->af)
1068 ? sizeof (struct sockaddr_in)
1069 : sizeof (struct sockaddr_in6))) )
1072 if (GNUNET_NO == found)
1073 notify_clients (pos,
1076 if ( (GNUNET_YES == have_nat) &&
1077 (GNUNET_YES == enable_upnp) &&
1078 (NULL == probe_external_ip_task) &&
1079 (NULL == probe_external_ip_op) )
1081 probe_external_ip_task
1082 = GNUNET_SCHEDULER_add_now (&run_external_ip,
1085 if ( (GNUNET_NO == have_nat) &&
1086 (GNUNET_YES == enable_upnp) )
1088 if (NULL != probe_external_ip_task)
1090 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1091 probe_external_ip_task = NULL;
1093 if (NULL != probe_external_ip_op)
1095 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1096 probe_external_ip_op = NULL;
1101 lal_head = ifc_ctx.lal_head;
1102 lal_tail = ifc_ctx.lal_tail;
1107 * Function called whenever our set of external addresses
1108 * as created by `upnpc` changes.
1110 * @param cls closure with our `struct ClientHandle *`
1111 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1112 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1113 * @param addr either the previous or the new public IP address
1114 * @param addrlen actual length of the @a addr
1115 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1118 upnp_addr_change_cb (void *cls,
1120 const struct sockaddr *addr,
1122 enum GNUNET_NAT_StatusCode result)
1124 struct ClientHandle *ch = cls;
1125 enum GNUNET_NAT_AddressClass ac;
1129 case GNUNET_NAT_ERROR_SUCCESS:
1130 GNUNET_assert (NULL != addr);
1132 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1133 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1134 case GNUNET_NAT_ERROR_IPC_FAILURE:
1135 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1136 "Running upnpc failed: %d\n",
1139 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1140 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1141 "external-ip binary not found\n");
1143 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1144 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1145 "external-ip binary could not be run\n");
1147 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1148 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1149 "upnpc failed to create port mapping\n");
1151 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1153 "Invalid output from upnpc\n");
1155 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1157 "Invalid address returned by upnpc\n");
1160 GNUNET_break (0); /* should not be possible */
1163 switch (addr->sa_family)
1166 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1167 ? GNUNET_NAT_AC_LAN_PRIVATE
1168 : GNUNET_NAT_AC_EXTERN;
1171 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1172 ? GNUNET_NAT_AC_LAN_PRIVATE
1173 : GNUNET_NAT_AC_EXTERN;
1179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1180 "upnp external address %s: %s\n",
1181 add_remove ? "added" : "removed",
1193 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1194 * We remember the client for updates upon future NAT events.
1196 * @param cls client who sent the message
1197 * @param message the message received
1200 handle_register (void *cls,
1201 const struct GNUNET_NAT_RegisterMessage *message)
1203 struct ClientHandle *ch = cls;
1207 if ( (0 != ch->proto) ||
1208 (NULL != ch->caddrs) )
1210 /* double registration not allowed */
1212 GNUNET_SERVICE_client_drop (ch->client);
1215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1216 "Received REGISTER message from client\n");
1217 ch->flags = message->flags;
1218 ch->proto = message->proto;
1219 ch->adv_port = ntohs (message->adv_port);
1220 ch->num_caddrs = ntohs (message->num_addrs);
1221 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1222 struct ClientAddress);
1223 left = ntohs (message->header.size) - sizeof (*message);
1224 off = (const char *) &message[1];
1225 for (unsigned int i=0;i<ch->num_caddrs;i++)
1228 const struct sockaddr *sa = (const struct sockaddr *) off;
1232 if (sizeof (sa_family_t) > left)
1235 GNUNET_SERVICE_client_drop (ch->client);
1239 switch (sa->sa_family)
1243 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1245 alen = sizeof (struct sockaddr_in);
1246 if (is_nat_v4 (&s4->sin_addr))
1247 is_nat = GNUNET_YES;
1248 port = ntohs (s4->sin_port);
1253 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1255 alen = sizeof (struct sockaddr_in6);
1256 if (is_nat_v6 (&s6->sin6_addr))
1257 is_nat = GNUNET_YES;
1258 port = ntohs (s6->sin6_port);
1263 alen = sizeof (struct sockaddr_un);
1269 GNUNET_SERVICE_client_drop (ch->client);
1273 GNUNET_assert (alen <= left);
1274 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1275 GNUNET_memcpy (&ch->caddrs[i].ss,
1279 /* If applicable, try UPNPC NAT punching */
1282 ( (IPPROTO_TCP == ch->proto) ||
1283 (IPPROTO_UDP == ch->proto) ) )
1285 ch->natted_address = GNUNET_YES;
1287 = GNUNET_NAT_mini_map_start (port,
1288 IPPROTO_TCP == ch->proto,
1289 &upnp_addr_change_cb,
1295 /* Actually send IP address list to client */
1296 for (struct LocalAddressList *lal = lal_head;
1300 check_notify_client (lal,
1304 /* Also consider IPv4 determined by `external-ip` */
1305 if (0 != mini_external_ipv4.s_addr)
1307 check_notify_client_external_ipv4_change (&mini_external_ipv4,
1311 GNUNET_SERVICE_client_continue (ch->client);
1316 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1319 * @param cls client who sent the message
1320 * @param message the message received
1321 * @return #GNUNET_OK if message is well-formed
1324 check_stun (void *cls,
1325 const struct GNUNET_NAT_HandleStunMessage *message)
1327 size_t sa_len = ntohs (message->sender_addr_size);
1328 size_t expect = sa_len + ntohs (message->payload_size);
1330 if (ntohs (message->header.size) - sizeof (*message) != expect)
1333 return GNUNET_SYSERR;
1335 if (sa_len < sizeof (sa_family_t))
1338 return GNUNET_SYSERR;
1345 * Notify all clients about our external IP address
1346 * as reported by the STUN server.
1348 * @param ip the external IP
1349 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1352 notify_clients_stun_change (const struct sockaddr_in *ip,
1355 for (struct ClientHandle *ch = ch_head;
1359 struct sockaddr_in v4;
1360 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1361 struct GNUNET_MQ_Envelope *env;
1363 if (! ch->natted_address)
1366 v4.sin_port = htons (ch->adv_port);
1367 env = GNUNET_MQ_msg_extra (msg,
1369 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1370 msg->add_remove = htonl ((int32_t) add);
1371 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1372 GNUNET_NAT_AC_GLOBAL);
1373 GNUNET_memcpy (&msg[1],
1376 GNUNET_MQ_send (ch->mq,
1383 * Function to be called when we decide that an
1384 * external IP address as told to us by a STUN
1385 * server has gone stale.
1387 * @param cls the `struct StunExternalIP` to drop
1390 stun_ip_timeout (void *cls)
1392 struct StunExternalIP *se = cls;
1394 se->timeout_task = NULL;
1395 notify_clients_stun_change (&se->external_addr,
1397 GNUNET_CONTAINER_DLL_remove (se_head,
1405 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1408 * @param cls client who sent the message
1409 * @param message the message received
1412 handle_stun (void *cls,
1413 const struct GNUNET_NAT_HandleStunMessage *message)
1415 struct ClientHandle *ch = cls;
1416 const char *buf = (const char *) &message[1];
1417 const struct sockaddr *sa;
1418 const void *payload;
1420 size_t payload_size;
1421 struct sockaddr_in external_addr;
1423 sa_len = ntohs (message->sender_addr_size);
1424 payload_size = ntohs (message->payload_size);
1425 sa = (const struct sockaddr *) &buf[0];
1426 payload = (const struct sockaddr *) &buf[sa_len];
1427 switch (sa->sa_family)
1430 if (sa_len != sizeof (struct sockaddr_in))
1433 GNUNET_SERVICE_client_drop (ch->client);
1438 if (sa_len != sizeof (struct sockaddr_in6))
1441 GNUNET_SERVICE_client_drop (ch->client);
1446 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1447 "Received HANDLE_STUN message from client\n");
1449 GNUNET_NAT_stun_handle_packet_ (payload,
1453 /* We now know that a server at "sa" claims that
1454 we are visible at IP "external_addr".
1456 We should (for some fixed period of time) tell
1457 all of our clients that listen to a NAT'ed address
1458 that they might want to consider the given 'external_ip'
1459 as their public IP address (this includes TCP and UDP
1460 clients, even if only UDP sends STUN requests).
1462 If we do not get a renewal, the "external_addr" should be
1463 removed again. The timeout frequency should be configurable
1464 (with a sane default), so that the UDP plugin can tell how
1465 often to re-request STUN.
1467 struct StunExternalIP *se;
1469 /* Check if we had a prior response from this STUN server */
1470 for (se = se_head; NULL != se; se = se->next)
1472 if ( (se->stun_server_addr_len != sa_len) ||
1474 &se->stun_server_addr,
1476 continue; /* different STUN server */
1477 if (0 != memcmp (&external_addr,
1479 sizeof (struct sockaddr_in)))
1481 /* external IP changed, update! */
1482 notify_clients_stun_change (&se->external_addr,
1484 se->external_addr = external_addr;
1485 notify_clients_stun_change (&se->external_addr,
1488 /* update timeout */
1489 GNUNET_SCHEDULER_cancel (se->timeout_task);
1491 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1496 /* STUN server is completely new, create fresh entry */
1497 se = GNUNET_new (struct StunExternalIP);
1498 se->external_addr = external_addr;
1499 GNUNET_memcpy (&se->stun_server_addr,
1502 se->stun_server_addr_len = sa_len;
1503 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1506 GNUNET_CONTAINER_DLL_insert (se_head,
1509 notify_clients_stun_change (&se->external_addr,
1512 GNUNET_SERVICE_client_continue (ch->client);
1518 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1521 * @param cls client who sent the message
1522 * @param message the message received
1523 * @return #GNUNET_OK if message is well-formed
1526 check_request_connection_reversal (void *cls,
1527 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1531 expect = ntohs (message->local_addr_size)
1532 + ntohs (message->remote_addr_size);
1533 if (ntohs (message->header.size) - sizeof (*message) != expect)
1536 return GNUNET_SYSERR;
1543 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1544 * message from client.
1546 * @param cls client who sent the message
1547 * @param message the message received
1550 handle_request_connection_reversal (void *cls,
1551 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1553 struct ClientHandle *ch = cls;
1554 const char *buf = (const char *) &message[1];
1555 size_t local_sa_len = ntohs (message->local_addr_size);
1556 size_t remote_sa_len = ntohs (message->remote_addr_size);
1557 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1558 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1559 const struct sockaddr_in *l4 = NULL;
1560 const struct sockaddr_in *r4;
1563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1564 "Received REQUEST CONNECTION REVERSAL message from client\n");
1565 switch (local_sa->sa_family)
1568 if (local_sa_len != sizeof (struct sockaddr_in))
1571 GNUNET_SERVICE_client_drop (ch->client);
1574 l4 = (const struct sockaddr_in *) local_sa;
1577 if (local_sa_len != sizeof (struct sockaddr_in6))
1580 GNUNET_SERVICE_client_drop (ch->client);
1583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1584 _("Connection reversal for IPv6 not supported yet\n"));
1585 ret = GNUNET_SYSERR;
1589 GNUNET_SERVICE_client_drop (ch->client);
1592 switch (remote_sa->sa_family)
1595 if (remote_sa_len != sizeof (struct sockaddr_in))
1598 GNUNET_SERVICE_client_drop (ch->client);
1601 r4 = (const struct sockaddr_in *) remote_sa;
1602 ret = GN_request_connection_reversal (&l4->sin_addr,
1603 ntohs (l4->sin_port),
1607 if (remote_sa_len != sizeof (struct sockaddr_in6))
1610 GNUNET_SERVICE_client_drop (ch->client);
1613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1614 _("Connection reversal for IPv6 not supported yet\n"));
1615 ret = GNUNET_SYSERR;
1619 GNUNET_SERVICE_client_drop (ch->client);
1622 if (GNUNET_OK != ret)
1623 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1624 _("Connection reversal request failed\n"));
1625 GNUNET_SERVICE_client_continue (ch->client);
1630 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1633 * @param cls client who sent the message
1634 * @param message the message received
1635 * @return #GNUNET_OK if message is well-formed
1638 check_autoconfig_request (void *cls,
1639 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1641 return GNUNET_OK; /* checked later */
1646 * Stop all pending activities with respect to the @a ac
1648 * @param ac autoconfiguration to terminate activities for
1651 terminate_ac_activities (struct AutoconfigContext *ac)
1653 if (NULL != ac->probe_external)
1655 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1656 ac->probe_external = NULL;
1658 if (NULL != ac->timeout_task)
1660 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1661 ac->timeout_task = NULL;
1667 * Finish handling the autoconfiguration request and send
1668 * the response to the client.
1670 * @param cls the `struct AutoconfigContext` to conclude
1673 conclude_autoconfig_request (void *cls)
1675 struct AutoconfigContext *ac = cls;
1676 struct ClientHandle *ch = ac->ch;
1677 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1678 struct GNUNET_MQ_Envelope *env;
1681 struct GNUNET_CONFIGURATION_Handle *diff;
1683 ac->timeout_task = NULL;
1684 terminate_ac_activities (ac);
1686 /* Send back response */
1687 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1689 buf = GNUNET_CONFIGURATION_serialize (diff,
1691 GNUNET_CONFIGURATION_destroy (diff);
1692 env = GNUNET_MQ_msg_extra (arm,
1694 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1695 arm->status_code = htonl ((uint32_t) ac->status_code);
1696 arm->type = htonl ((uint32_t) ac->type);
1697 GNUNET_memcpy (&arm[1],
1701 GNUNET_MQ_send (ch->mq,
1705 GNUNET_free (ac->system_type);
1706 GNUNET_CONFIGURATION_destroy (ac->orig);
1707 GNUNET_CONFIGURATION_destroy (ac->c);
1708 GNUNET_CONTAINER_DLL_remove (ac_head,
1712 GNUNET_SERVICE_client_continue (ch->client);
1717 * Check if all autoconfiguration operations have concluded,
1718 * and if they have, send the result back to the client.
1720 * @param ac autoconfiguation context to check
1723 check_autoconfig_finished (struct AutoconfigContext *ac)
1725 if (NULL != ac->probe_external)
1727 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1729 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1735 * Update ENABLE_UPNPC configuration option.
1737 * @param ac autoconfiguration to update
1740 update_enable_upnpc_option (struct AutoconfigContext *ac)
1742 switch (ac->enable_upnpc)
1745 GNUNET_CONFIGURATION_set_value_string (ac->c,
1751 GNUNET_CONFIGURATION_set_value_string (ac->c,
1757 /* We are unsure, do not change option */
1764 * Handle result from external IP address probe during
1765 * autoconfiguration.
1767 * @param cls our `struct AutoconfigContext`
1768 * @param addr the address, NULL on errors
1769 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1772 auto_external_result_cb (void *cls,
1773 const struct in_addr *addr,
1774 enum GNUNET_NAT_StatusCode result)
1776 struct AutoconfigContext *ac = cls;
1778 ac->probe_external = NULL;
1781 case GNUNET_NAT_ERROR_SUCCESS:
1782 ac->enable_upnpc = GNUNET_YES;
1784 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1785 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1786 case GNUNET_NAT_ERROR_IPC_FAILURE:
1787 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1788 "Disabling UPNPC: %d\n",
1790 ac->enable_upnpc = GNUNET_NO; /* did not work */
1793 GNUNET_break (0); /* unexpected */
1794 ac->enable_upnpc = GNUNET_SYSERR;
1797 update_enable_upnpc_option (ac);
1798 check_autoconfig_finished (ac);
1803 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1806 * @param cls client who sent the message
1807 * @param message the message received
1810 handle_autoconfig_request (void *cls,
1811 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1813 struct ClientHandle *ch = cls;
1814 size_t left = ntohs (message->header.size) - sizeof (*message);
1815 struct LocalAddressList *lal;
1816 struct AutoconfigContext *ac;
1818 ac = GNUNET_new (struct AutoconfigContext);
1819 ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
1821 ac->c = GNUNET_CONFIGURATION_create ();
1823 GNUNET_CONFIGURATION_deserialize (ac->c,
1824 (const char *) &message[1],
1829 GNUNET_SERVICE_client_drop (ch->client);
1830 GNUNET_CONFIGURATION_destroy (ac->c);
1834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1835 "Received REQUEST_AUTO_CONFIG message from client\n");
1838 GNUNET_CONFIGURATION_get_value_string (ac->c,
1842 ac->system_type = GNUNET_strdup ("UNKNOWN");
1844 GNUNET_CONTAINER_DLL_insert (ac_head,
1848 = GNUNET_CONFIGURATION_dup (ac->c);
1850 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1851 &conclude_autoconfig_request,
1853 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1855 /* Probe for upnpc */
1856 if (GNUNET_SYSERR ==
1857 GNUNET_OS_check_helper_binary ("upnpc",
1861 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1862 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1863 ac->enable_upnpc = GNUNET_NO;
1867 for (lal = lal_head; NULL != lal; lal = lal->next)
1868 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1869 /* we are behind NAT, useful to try upnpc */
1870 ac->enable_upnpc = GNUNET_YES;
1872 if (GNUNET_YES == ac->enable_upnpc)
1874 /* If we are a mobile device, always leave it on as the network
1875 may change to one that supports UPnP anytime. If we are
1876 stationary, check if our network actually supports UPnP, and if
1878 if ( (0 == strcasecmp (ac->system_type,
1879 "INFRASTRUCTURE")) ||
1880 (0 == strcasecmp (ac->system_type,
1883 /* Check if upnpc gives us an external IP */
1885 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1889 if (NULL == ac->probe_external)
1890 update_enable_upnpc_option (ac);
1892 /* Finally, check if we are already done */
1893 check_autoconfig_finished (ac);
1898 * Task run during shutdown.
1903 shutdown_task (void *cls)
1905 struct StunExternalIP *se;
1906 struct AutoconfigContext *ac;
1908 while (NULL != (ac = ac_head))
1910 GNUNET_CONTAINER_DLL_remove (ac_head,
1913 terminate_ac_activities (ac);
1916 while (NULL != (se = se_head))
1918 GNUNET_CONTAINER_DLL_remove (se_head,
1921 GNUNET_SCHEDULER_cancel (se->timeout_task);
1924 if (NULL != probe_external_ip_task)
1926 GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1927 probe_external_ip_task = NULL;
1929 if (NULL != probe_external_ip_op)
1931 GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1932 probe_external_ip_op = NULL;
1934 if (NULL != scan_task)
1936 GNUNET_SCHEDULER_cancel (scan_task);
1941 GNUNET_STATISTICS_destroy (stats,
1950 * Setup NAT service.
1952 * @param cls closure
1953 * @param c configuration to use
1954 * @param service the initialized service
1958 const struct GNUNET_CONFIGURATION_Handle *c,
1959 struct GNUNET_SERVICE_Handle *service)
1963 GNUNET_CONFIGURATION_get_value_time (cfg,
1966 &stun_stale_timeout))
1967 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1969 /* Check for UPnP */
1971 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1974 if (GNUNET_YES == enable_upnp)
1976 /* check if it works */
1977 if (GNUNET_SYSERR ==
1978 GNUNET_OS_check_helper_binary ("upnpc",
1982 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1983 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1984 enable_upnp = GNUNET_SYSERR;
1988 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1990 stats = GNUNET_STATISTICS_create ("nat",
1992 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1998 * Callback called when a client connects to the service.
2000 * @param cls closure for the service
2001 * @param c the new client that connected to the service
2002 * @param mq the message queue used to send messages to the client
2003 * @return a `struct ClientHandle`
2006 client_connect_cb (void *cls,
2007 struct GNUNET_SERVICE_Client *c,
2008 struct GNUNET_MQ_Handle *mq)
2010 struct ClientHandle *ch;
2012 ch = GNUNET_new (struct ClientHandle);
2015 GNUNET_CONTAINER_DLL_insert (ch_head,
2023 * Callback called when a client disconnected from the service
2025 * @param cls closure for the service
2026 * @param c the client that disconnected
2027 * @param internal_cls a `struct ClientHandle *`
2030 client_disconnect_cb (void *cls,
2031 struct GNUNET_SERVICE_Client *c,
2034 struct ClientHandle *ch = internal_cls;
2036 GNUNET_CONTAINER_DLL_remove (ch_head,
2039 for (unsigned int i=0;i<ch->num_caddrs;i++)
2041 if (NULL != ch->caddrs[i].mh)
2043 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2044 ch->caddrs[i].mh = NULL;
2047 GNUNET_free_non_null (ch->caddrs);
2053 * Define "main" method using service macro.
2057 GNUNET_SERVICE_OPTION_NONE,
2060 &client_disconnect_cb,
2062 GNUNET_MQ_hd_var_size (register,
2063 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2064 struct GNUNET_NAT_RegisterMessage,
2066 GNUNET_MQ_hd_var_size (stun,
2067 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2068 struct GNUNET_NAT_HandleStunMessage,
2070 GNUNET_MQ_hd_var_size (request_connection_reversal,
2071 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2072 struct GNUNET_NAT_RequestConnectionReversalMessage,
2074 GNUNET_MQ_hd_var_size (autoconfig_request,
2075 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2076 struct GNUNET_NAT_AutoconfigRequestMessage,
2078 GNUNET_MQ_handler_end ());
2081 #if defined(LINUX) && defined(__GLIBC__)
2085 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2087 void __attribute__ ((constructor))
2088 GNUNET_ARM_memory_init ()
2090 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2091 mallopt (M_TOP_PAD, 1 * 1024);
2096 /* end of gnunet-service-nat.c */