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 * - test manual hole punching support
33 * - adapt existing transports to use new NAT logic
34 * - abandon legacy NAT code
36 * - implement "more" autoconfig:
37 * + consider moving autoconfig-logic into separate service!
38 * + re-work gnunet-nat-server & integrate!
39 * + test manually punched NAT (how?)
41 * - implement & test STUN processing to classify NAT;
42 * basically, open port & try different methods.
46 #include "gnunet_util_lib.h"
47 #include "gnunet_protocols.h"
48 #include "gnunet_signatures.h"
49 #include "gnunet_statistics_service.h"
50 #include "gnunet_resolver_service.h"
51 #include "gnunet_nat_service.h"
52 #include "gnunet-service-nat.h"
53 #include "gnunet-service-nat_externalip.h"
54 #include "gnunet-service-nat_stun.h"
55 #include "gnunet-service-nat_mini.h"
56 #include "gnunet-service-nat_helper.h"
62 * How often should we ask the OS about a list of active
65 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
68 * How long do we wait until we forcefully terminate autoconfiguration?
70 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
73 * How often do we scan for changes in how our external (dyndns) hostname resolves?
75 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
79 * Information we track per client address.
84 * Network address used by the client.
86 struct sockaddr_storage ss;
89 * Handle to active UPnP request where we asked upnpc to open
90 * a port at the NAT. NULL if we do not have such a request
93 struct GNUNET_NAT_MiniHandle *mh;
99 * List of local addresses this system has.
101 struct LocalAddressList
104 * This is a linked list.
106 struct LocalAddressList *next;
111 struct LocalAddressList *prev;
114 * Context for a gnunet-helper-nat-server used to listen
115 * for ICMP messages to this client for connection reversal.
117 struct HelperContext *hc;
120 * The address itself (i.e. `struct sockaddr_in` or `struct
121 * sockaddr_in6`, in the respective byte order).
123 struct sockaddr_storage addr;
126 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
131 * #GNUNET_YES if we saw this one in the previous iteration,
132 * but not in the current iteration and thus might need to
133 * remove it at the end.
138 * What type of address is this?
140 enum GNUNET_NAT_AddressClass ac;
146 * Internal data structure we track for each of our clients.
154 struct ClientHandle *next;
159 struct ClientHandle *prev;
162 * Underlying handle for this client with the service.
164 struct GNUNET_SERVICE_Client *client;
167 * Message queue for communicating with the client.
169 struct GNUNET_MQ_Handle *mq;
172 * Array of addresses used by the service.
174 struct ClientAddress *caddrs;
177 * External DNS name and port given by user due to manual
178 * hole punching. Special DNS name 'AUTO' is used to indicate
179 * desire for automatic determination of the external IP
180 * (instead of DNS or manual configuration, i.e. to be used
181 * if the IP keeps changing and we have no DynDNS, but we do
182 * have a hole punched).
187 * Name of the configuration section this client cares about.
192 * Task for periodically re-running the @e ext_dns DNS lookup.
194 struct GNUNET_SCHEDULER_Task *ext_dns_task;
197 * Handle for (DYN)DNS lookup of our external IP as given in
200 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
203 * Handle for monitoring external IP changes.
205 struct GN_ExternalIPMonitor *external_monitor;
208 * DLL of external IP addresses as given in @e hole_external.
210 struct LocalAddressList *ext_addr_head;
213 * DLL of external IP addresses as given in @e hole_external.
215 struct LocalAddressList *ext_addr_tail;
218 * Port number we found in @e hole_external.
220 uint16_t ext_dns_port;
223 * What does this client care about?
225 enum GNUNET_NAT_RegisterFlags flags;
228 * Is any of the @e caddrs in a reserved subnet for NAT?
233 * Number of addresses that this service is bound to.
234 * Length of the @e caddrs array.
239 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
247 * External IP address as given to us via some STUN server.
249 struct StunExternalIP
254 struct StunExternalIP *next;
259 struct StunExternalIP *prev;
262 * Task we run to remove this entry when it is stale.
264 struct GNUNET_SCHEDULER_Task *timeout_task;
267 * Our external IP address as reported by the
270 struct sockaddr_in external_addr;
273 * Address of the reporting STUN server. Used to
274 * detect when a STUN server changes its opinion
275 * to more quickly remove stale results.
277 struct sockaddr_storage stun_server_addr;
280 * Number of bytes used in @e stun_server_addr.
282 size_t stun_server_addr_len;
287 * Timeout to use when STUN data is considered stale.
289 static struct GNUNET_TIME_Relative stun_stale_timeout;
292 * How often do we scan for changes in how our external (dyndns) hostname resolves?
294 static struct GNUNET_TIME_Relative dyndns_frequency;
297 * Handle to our current configuration.
299 static const struct GNUNET_CONFIGURATION_Handle *cfg;
302 * Handle to the statistics service.
304 static struct GNUNET_STATISTICS_Handle *stats;
307 * Task scheduled to periodically scan our network interfaces.
309 static struct GNUNET_SCHEDULER_Task *scan_task;
312 * Head of client DLL.
314 static struct ClientHandle *ch_head;
317 * Tail of client DLL.
319 static struct ClientHandle *ch_tail;
322 * Head of DLL of local addresses.
324 static struct LocalAddressList *lal_head;
327 * Tail of DLL of local addresses.
329 static struct LocalAddressList *lal_tail;
334 static struct StunExternalIP *se_head;
339 static struct StunExternalIP *se_tail;
342 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
343 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
349 * Remove and free an entry from the #lal_head DLL.
351 * @param lal entry to free
354 free_lal (struct LocalAddressList *lal)
356 GNUNET_CONTAINER_DLL_remove (lal_head,
361 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
362 "Lost NATed local address %s, stopping NAT server\n",
363 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
364 sizeof (struct sockaddr_in)));
366 GN_stop_gnunet_nat_server_ (lal->hc);
374 * Free the DLL starting at #lal_head.
379 struct LocalAddressList *lal;
381 while (NULL != (lal = lal_head))
387 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
390 * @param cls client who sent the message
391 * @param message the message received
392 * @return #GNUNET_OK if message is well-formed
395 check_register (void *cls,
396 const struct GNUNET_NAT_RegisterMessage *message)
398 uint16_t num_addrs = ntohs (message->num_addrs);
399 const char *off = (const char *) &message[1];
400 size_t left = ntohs (message->header.size) - sizeof (*message);
402 for (unsigned int i=0;i<num_addrs;i++)
405 const struct sockaddr *sa = (const struct sockaddr *) off;
407 if (sizeof (sa_family_t) > left)
410 return GNUNET_SYSERR;
412 switch (sa->sa_family)
415 alen = sizeof (struct sockaddr_in);
418 alen = sizeof (struct sockaddr_in6);
422 alen = sizeof (struct sockaddr_un);
427 return GNUNET_SYSERR;
432 return GNUNET_SYSERR;
437 if (left != ntohs (message->str_len))
440 return GNUNET_SYSERR;
447 * Check if @a ip is in @a network with @a bits netmask.
449 * @param network to test
450 * @param ip IP address to test
451 * @param bits bitmask for the network
452 * @return #GNUNET_YES if @a ip is in @a network
455 match_ipv4 (const char *network,
456 const struct in_addr *ip,
465 GNUNET_assert (1 == inet_pton (AF_INET,
468 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
473 * Check if @a ip is in @a network with @a bits netmask.
475 * @param network to test
476 * @param ip IP address to test
477 * @param bits bitmask for the network
478 * @return #GNUNET_YES if @a ip is in @a network
481 match_ipv6 (const char *network,
482 const struct in6_addr *ip,
486 struct in6_addr mask;
491 GNUNET_assert (1 == inet_pton (AF_INET6,
494 memset (&mask, 0, sizeof (mask));
495 if (0 == memcmp (&mask,
502 mask.s6_addr[off++] = 0xFF;
507 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
510 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
511 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
512 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
519 * Test if the given IPv4 address is in a known range
520 * for private networks.
522 * @param ip address to test
523 * @return #GNUNET_YES if @a ip is in a NAT range
526 is_nat_v4 (const struct in_addr *ip)
529 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
530 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
531 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
532 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
533 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
538 * Test if the given IPv6 address is in a known range
539 * for private networks.
541 * @param ip address to test
542 * @return #GNUNET_YES if @a ip is in a NAT range
545 is_nat_v6 (const struct in6_addr *ip)
548 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
549 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
550 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
555 * Closure for #ifc_proc.
557 struct IfcProcContext
561 * Head of DLL of local addresses.
563 struct LocalAddressList *lal_head;
566 * Tail of DLL of local addresses.
568 struct LocalAddressList *lal_tail;
574 * Callback function invoked for each interface found. Adds them
575 * to our new address list.
577 * @param cls a `struct IfcProcContext *`
578 * @param name name of the interface (can be NULL for unknown)
579 * @param isDefault is this presumably the default interface
580 * @param addr address of this interface (can be NULL for unknown or unassigned)
581 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
582 * @param netmask the network mask (can be NULL for unknown or unassigned)
583 * @param addrlen length of the address
584 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
590 const struct sockaddr *addr,
591 const struct sockaddr *broadcast_addr,
592 const struct sockaddr *netmask,
595 struct IfcProcContext *ifc_ctx = cls;
596 struct LocalAddressList *lal;
598 const struct in_addr *ip4;
599 const struct in6_addr *ip6;
600 enum GNUNET_NAT_AddressClass ac;
602 switch (addr->sa_family)
605 alen = sizeof (struct sockaddr_in);
606 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
607 if (match_ipv4 ("127.0.0.0", ip4, 8))
608 ac = GNUNET_NAT_AC_LOOPBACK;
609 else if (is_nat_v4 (ip4))
610 ac = GNUNET_NAT_AC_LAN;
612 ac = GNUNET_NAT_AC_GLOBAL;
615 alen = sizeof (struct sockaddr_in6);
616 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
617 if (match_ipv6 ("::1", ip6, 128))
618 ac = GNUNET_NAT_AC_LOOPBACK;
619 else if (is_nat_v6 (ip6))
620 ac = GNUNET_NAT_AC_LAN;
622 ac = GNUNET_NAT_AC_GLOBAL;
623 if ( (ip6->s6_addr[11] == 0xFF) &&
624 (ip6->s6_addr[12] == 0xFE) )
626 /* contains a MAC, be extra careful! */
627 ac |= GNUNET_NAT_AC_PRIVATE;
639 lal = GNUNET_malloc (sizeof (*lal));
640 lal->af = addr->sa_family;
642 GNUNET_memcpy (&lal->addr,
645 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
653 * Notify client about a change in the list of addresses this peer
656 * @param ac address class of the entry in the list that changed
657 * @param ch client to contact
658 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
659 * @param addr the address that changed
660 * @param addr_len number of bytes in @a addr
663 notify_client (enum GNUNET_NAT_AddressClass ac,
664 struct ClientHandle *ch,
669 struct GNUNET_MQ_Envelope *env;
670 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
672 env = GNUNET_MQ_msg_extra (msg,
674 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
675 msg->add_remove = htonl (add);
676 msg->addr_class = htonl (ac);
677 GNUNET_memcpy (&msg[1],
680 GNUNET_MQ_send (ch->mq,
686 * Check if we should bother to notify this client about this
687 * address change, and if so, do it.
689 * @param delta the entry in the list that changed
690 * @param ch client to check
691 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
694 check_notify_client (struct LocalAddressList *delta,
695 struct ClientHandle *ch,
699 struct sockaddr_in v4;
700 struct sockaddr_in6 v6;
702 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
707 alen = sizeof (struct sockaddr_in);
712 /* Check for client notifications */
713 for (unsigned int i=0;i<ch->num_caddrs;i++)
715 const struct sockaddr_in *c4;
717 if (AF_INET != ch->caddrs[i].ss.ss_family)
718 continue; /* IPv4 not relevant */
719 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
720 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
721 (0 != c4->sin_addr.s_addr) &&
722 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
723 continue; /* bound to loopback, but this is not loopback */
724 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
725 (0 != c4->sin_addr.s_addr) &&
726 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
727 continue; /* bound to non-loopback, but this is loopback */
728 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
729 (0 != c4->sin_addr.s_addr) &&
730 (! is_nat_v4 (&v4.sin_addr)) )
731 continue; /* based on external-IP, but this IP is not
732 from private address range. */
733 if ( (0 != memcmp (&v4.sin_addr,
735 sizeof (struct in_addr))) &&
736 (0 != c4->sin_addr.s_addr) &&
737 ( (! is_nat_v4 (&c4->sin_addr)) ||
738 (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
739 continue; /* this IP is not from private address range,
740 and IP does not match. */
742 /* OK, IP seems relevant, notify client */
743 v4.sin_port = c4->sin_port;
744 notify_client (delta->ac,
752 alen = sizeof (struct sockaddr_in6);
756 for (unsigned int i=0;i<ch->num_caddrs;i++)
758 const struct sockaddr_in6 *c6;
760 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
761 continue; /* IPv4 not relevant */
762 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
763 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
764 (0 != memcmp (&c6->sin6_addr,
766 sizeof (struct in6_addr))) &&
767 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
768 continue; /* bound to loopback, but this is not loopback */
769 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
770 (0 != memcmp (&c6->sin6_addr,
772 sizeof (struct in6_addr))) &&
773 match_ipv6 ("::1", &v6.sin6_addr, 128) )
774 continue; /* bound to non-loopback, but this is loopback */
775 if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
776 (0 != memcmp (&c6->sin6_addr,
778 sizeof (struct in6_addr))) &&
779 (! is_nat_v6 (&v6.sin6_addr)) )
780 continue; /* based on external-IP, but this IP is not
781 from private address range. */
782 if ( (0 != memcmp (&v6.sin6_addr,
784 sizeof (struct in6_addr))) &&
785 (0 != memcmp (&c6->sin6_addr,
787 sizeof (struct in6_addr))) &&
788 (! is_nat_v6 (&c6->sin6_addr)) )
789 continue; /* this IP is not from private address range,
790 and IP does not match. */
791 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
792 (0 != memcmp (&c6->sin6_addr,
794 sizeof (struct in6_addr))) &&
795 (0 != memcmp (&v6.sin6_addr,
797 sizeof (struct in6_addr))) &&
798 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
799 continue; /* client bound to link-local, and the other address
800 does not match and is not an external IP */
802 /* OK, IP seems relevant, notify client */
803 v6.sin6_port = c6->sin6_port;
804 notify_client (delta->ac,
819 * Notify all clients about a change in the list
820 * of addresses this peer has.
822 * @param delta the entry in the list that changed
823 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
826 notify_clients (struct LocalAddressList *delta,
829 for (struct ClientHandle *ch = ch_head;
832 check_notify_client (delta,
839 * Tell relevant client about a change in our external
842 * @param cls client to check if it cares and possibly notify
843 * @param v4 the external address that changed
844 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
847 notify_client_external_ipv4_change (void *cls,
848 const struct in_addr *v4,
851 struct ClientHandle *ch = cls;
852 struct sockaddr_in sa;
855 /* (0) check if this impacts 'hole_external' */
856 if (0 == strcasecmp (ch->hole_external,
859 struct LocalAddressList lal;
860 struct sockaddr_in *s4;
862 memset (&lal, 0, sizeof (lal));
863 s4 = (struct sockaddr_in *) &lal.addr;
864 s4->sin_family = AF_INET;
865 s4->sin_port = htons (ch->ext_dns_port);
867 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
868 check_notify_client (&lal,
873 /* (1) check if client cares. */
874 if (! ch->natted_address)
876 if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
879 for (unsigned int i=0;i<ch->num_caddrs;i++)
881 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
883 if (AF_INET != ss->ss_family)
885 have_v4 = GNUNET_YES;
888 if (GNUNET_NO == have_v4)
889 return; /* IPv6-only */
891 /* (2) build address info */
895 sa.sin_family = AF_INET;
897 sa.sin_port = htons (0);
899 /* (3) notify client of change */
900 notify_client (is_nat_v4 (v4)
901 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
902 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
911 * We got a connection reversal request from another peer.
912 * Notify applicable clients.
914 * @param cls closure with the `struct LocalAddressList`
915 * @param ra IP address of the peer who wants us to connect to it
918 reversal_callback (void *cls,
919 const struct sockaddr_in *ra)
921 struct LocalAddressList *lal = cls;
922 const struct sockaddr_in *l4;
924 GNUNET_assert (AF_INET == lal->af);
925 l4 = (const struct sockaddr_in *) &lal->addr;
926 for (struct ClientHandle *ch = ch_head;
930 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
931 struct GNUNET_MQ_Envelope *env;
934 /* Check if client is in applicable range for ICMP NAT traversal
935 for this local address */
936 if (! ch->natted_address)
939 for (unsigned int i=0;i<ch->num_caddrs;i++)
941 struct ClientAddress *ca = &ch->caddrs[i];
942 const struct sockaddr_in *c4;
944 if (AF_INET != ca->ss.ss_family)
946 c4 = (const struct sockaddr_in *) &ca->ss;
947 if ( (0 != c4->sin_addr.s_addr) &&
948 (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
956 /* Notify applicable client about connection reversal request */
957 env = GNUNET_MQ_msg_extra (crrm,
958 sizeof (struct sockaddr_in),
959 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
960 GNUNET_memcpy (&crrm[1],
962 sizeof (struct sockaddr_in));
963 GNUNET_MQ_send (ch->mq,
970 * Task we run periodically to scan for network interfaces.
977 struct IfcProcContext ifc_ctx;
980 struct LocalAddressList *lnext;
982 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
988 GNUNET_OS_network_interfaces_list (&ifc_proc,
990 /* remove addresses that disappeared */
991 for (struct LocalAddressList *lal = lal_head;
997 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1001 if ( (pos->af == lal->af) &&
1002 (0 == memcmp (&lal->addr,
1004 (AF_INET == lal->af)
1005 ? sizeof (struct sockaddr_in)
1006 : sizeof (struct sockaddr_in6))) )
1011 if (GNUNET_NO == found)
1013 notify_clients (lal,
1019 /* add addresses that appeared */
1020 have_nat = GNUNET_NO;
1021 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1023 pos = ifc_ctx.lal_head)
1026 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1027 have_nat = GNUNET_YES;
1028 for (struct LocalAddressList *lal = lal_head;
1032 if ( (pos->af == lal->af) &&
1033 (0 == memcmp (&lal->addr,
1035 (AF_INET == lal->af)
1036 ? sizeof (struct sockaddr_in)
1037 : sizeof (struct sockaddr_in6))) )
1040 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1043 if (GNUNET_YES == found)
1049 notify_clients (pos,
1051 GNUNET_CONTAINER_DLL_insert (lal_head,
1054 if ( (AF_INET == pos->af) &&
1055 (NULL == pos->hc) &&
1056 (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1058 const struct sockaddr_in *s4
1059 = (const struct sockaddr_in *) &pos->addr;
1061 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1062 "Found NATed local address %s, starting NAT server\n",
1063 GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
1064 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1070 GN_nat_status_changed (have_nat);
1075 * Function called whenever our set of external addresses
1076 * as created by `upnpc` changes.
1078 * @param cls closure with our `struct ClientHandle *`
1079 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1080 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1081 * @param addr either the previous or the new public IP address
1082 * @param addrlen actual length of the @a addr
1083 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1086 upnp_addr_change_cb (void *cls,
1088 const struct sockaddr *addr,
1090 enum GNUNET_NAT_StatusCode result)
1092 struct ClientHandle *ch = cls;
1093 enum GNUNET_NAT_AddressClass ac;
1097 case GNUNET_NAT_ERROR_SUCCESS:
1098 GNUNET_assert (NULL != addr);
1100 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1101 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1102 case GNUNET_NAT_ERROR_IPC_FAILURE:
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "Running upnpc failed: %d\n",
1107 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1108 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1109 "external-ip binary not found\n");
1111 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1112 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1113 "external-ip binary could not be run\n");
1115 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1116 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1117 "upnpc failed to create port mapping\n");
1119 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1121 "Invalid output from upnpc\n");
1123 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125 "Invalid address returned by upnpc\n");
1128 GNUNET_break (0); /* should not be possible */
1131 switch (addr->sa_family)
1134 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1136 : GNUNET_NAT_AC_EXTERN;
1139 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1141 : GNUNET_NAT_AC_EXTERN;
1147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1148 "upnp external address %s: %s\n",
1149 add_remove ? "added" : "removed",
1161 * Resolve the `hole_external` name to figure out our
1162 * external address from a manually punched hole. The
1163 * port number has already been parsed, this task is
1164 * responsible for periodically doing a DNS lookup.
1166 * @param ch client handle to act upon
1169 dyndns_lookup (void *cls);
1173 * Our (external) hostname was resolved. Update lists of
1174 * current external IPs (note that DNS may return multiple
1175 * addresses!) and notify client accordingly.
1177 * @param cls the `struct ClientHandle`
1178 * @param addr NULL on error, otherwise result of DNS lookup
1179 * @param addrlen number of bytes in @a addr
1182 process_external_ip (void *cls,
1183 const struct sockaddr *addr,
1186 struct ClientHandle *ch = cls;
1187 struct LocalAddressList *lal;
1188 struct sockaddr_storage ss;
1189 struct sockaddr_in *v4;
1190 struct sockaddr_in6 *v6;
1194 struct LocalAddressList *laln;
1198 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1201 /* Current iteration is over, remove 'old' IPs now */
1202 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1205 if (GNUNET_YES == lal->old)
1207 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1210 check_notify_client (lal,
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Got IP `%s' for external address `%s'\n",
1224 /* build sockaddr storage with port number */
1225 memset (&ss, 0, sizeof (ss));
1226 memcpy (&ss, addr, addrlen);
1227 switch (addr->sa_family)
1230 v4 = (struct sockaddr_in *) &ss;
1231 v4->sin_port = htons (ch->ext_dns_port);
1234 v6 = (struct sockaddr_in6 *) &ss;
1235 v6->sin6_port = htons (ch->ext_dns_port);
1241 /* See if 'ss' matches any of our known addresses */
1242 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1244 if (GNUNET_NO == lal->old)
1245 continue; /* already processed, skip */
1246 if ( (addr->sa_family == lal->addr.ss_family) &&
1251 /* Address unchanged, remember so we do not remove */
1252 lal->old = GNUNET_NO;
1253 return; /* done here */
1256 /* notify client, and remember IP for later removal! */
1257 lal = GNUNET_new (struct LocalAddressList);
1259 lal->af = ss.ss_family;
1260 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1261 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1264 check_notify_client (lal,
1271 * Resolve the `hole_external` name to figure out our
1272 * external address from a manually punched hole. The
1273 * port number has already been parsed, this task is
1274 * responsible for periodically doing a DNS lookup.
1276 * @param ch client handle to act upon
1279 dyndns_lookup (void *cls)
1281 struct ClientHandle *ch = cls;
1282 struct LocalAddressList *lal;
1284 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1285 lal->old = GNUNET_YES;
1286 ch->ext_dns_task = NULL;
1287 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1289 GNUNET_TIME_UNIT_MINUTES,
1290 &process_external_ip,
1296 * Resolve the `hole_external` name to figure out our
1297 * external address from a manually punched hole. The
1298 * given name may be "AUTO" in which case we should use
1299 * the IP address(es) we have from upnpc or other methods.
1300 * The name can also be an IP address, in which case we
1301 * do not need to do DNS resolution. Finally, we also
1302 * need to parse the port number.
1304 * @param ch client handle to act upon
1307 lookup_hole_external (struct ClientHandle *ch)
1311 struct sockaddr_in *s4;
1312 struct LocalAddressList *lal;
1314 port = strrchr (ch->hole_external, ':');
1317 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1318 _("Malformed punched hole specification `%s' (lacks port)\n"),
1322 if ( (1 != sscanf (port + 1,
1327 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1328 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1332 ch->ext_dns_port = (uint16_t) pnum;
1335 lal = GNUNET_new (struct LocalAddressList);
1336 if ('[' == *ch->hole_external)
1338 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1340 s6->sin6_family = AF_INET6;
1341 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1344 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1349 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1350 if (1 != inet_pton (AF_INET6,
1351 ch->hole_external + 1,
1354 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1355 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1356 ch->hole_external + 1);
1360 s6->sin6_port = htons (ch->ext_dns_port);
1362 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1363 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1366 check_notify_client (lal,
1372 s4 = (struct sockaddr_in *) &lal->addr;
1373 s4->sin_family = AF_INET;
1374 if (1 == inet_pton (AF_INET,
1378 s4->sin_port = htons (ch->ext_dns_port);
1380 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1381 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1384 check_notify_client (lal,
1389 if (0 == strcasecmp (ch->hole_external,
1392 /* handled in #notify_client_external_ipv4_change() */
1396 /* got a DNS name, trigger lookup! */
1399 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1405 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1406 * We remember the client for updates upon future NAT events.
1408 * @param cls client who sent the message
1409 * @param message the message received
1412 handle_register (void *cls,
1413 const struct GNUNET_NAT_RegisterMessage *message)
1415 struct ClientHandle *ch = cls;
1419 if ( (0 != ch->proto) ||
1420 (NULL != ch->caddrs) )
1422 /* double registration not allowed */
1424 GNUNET_SERVICE_client_drop (ch->client);
1427 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1428 "Received REGISTER message from client\n");
1429 ch->flags = message->flags;
1430 ch->proto = message->proto;
1431 ch->num_caddrs = ntohs (message->num_addrs);
1432 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1433 struct ClientAddress);
1434 left = ntohs (message->header.size) - sizeof (*message);
1435 off = (const char *) &message[1];
1436 for (unsigned int i=0;i<ch->num_caddrs;i++)
1439 const struct sockaddr *sa = (const struct sockaddr *) off;
1443 if (sizeof (sa_family_t) > left)
1446 GNUNET_SERVICE_client_drop (ch->client);
1450 switch (sa->sa_family)
1454 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1456 alen = sizeof (struct sockaddr_in);
1457 if (is_nat_v4 (&s4->sin_addr))
1458 is_nat = GNUNET_YES;
1459 port = ntohs (s4->sin_port);
1464 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1466 alen = sizeof (struct sockaddr_in6);
1467 if (is_nat_v6 (&s6->sin6_addr))
1468 is_nat = GNUNET_YES;
1469 port = ntohs (s6->sin6_port);
1474 alen = sizeof (struct sockaddr_un);
1480 GNUNET_SERVICE_client_drop (ch->client);
1484 GNUNET_assert (alen <= left);
1485 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1486 GNUNET_memcpy (&ch->caddrs[i].ss,
1490 /* If applicable, try UPNPC NAT punching */
1493 ( (IPPROTO_TCP == ch->proto) ||
1494 (IPPROTO_UDP == ch->proto) ) )
1496 ch->natted_address = GNUNET_YES;
1498 = GNUNET_NAT_mini_map_start (port,
1499 IPPROTO_TCP == ch->proto,
1500 &upnp_addr_change_cb,
1508 = GNUNET_strndup (off,
1509 ntohs (message->str_len));
1511 GNUNET_CONFIGURATION_get_value_string (cfg,
1514 &ch->hole_external))
1515 lookup_hole_external (ch);
1517 /* Actually send IP address list to client */
1518 for (struct LocalAddressList *lal = lal_head;
1522 check_notify_client (lal,
1526 /* Also consider IPv4 determined by `external-ip` */
1527 ch->external_monitor
1528 = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change,
1530 GNUNET_SERVICE_client_continue (ch->client);
1535 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1538 * @param cls client who sent the message
1539 * @param message the message received
1540 * @return #GNUNET_OK if message is well-formed
1543 check_stun (void *cls,
1544 const struct GNUNET_NAT_HandleStunMessage *message)
1546 size_t sa_len = ntohs (message->sender_addr_size);
1547 size_t expect = sa_len + ntohs (message->payload_size);
1549 if (ntohs (message->header.size) - sizeof (*message) != expect)
1552 return GNUNET_SYSERR;
1554 if (sa_len < sizeof (sa_family_t))
1557 return GNUNET_SYSERR;
1564 * Notify all clients about our external IP address
1565 * as reported by the STUN server.
1567 * @param ip the external IP
1568 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1571 notify_clients_stun_change (const struct sockaddr_in *ip,
1574 for (struct ClientHandle *ch = ch_head;
1578 struct sockaddr_in v4;
1579 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1580 struct GNUNET_MQ_Envelope *env;
1582 if (! ch->natted_address)
1585 v4.sin_port = htons (0);
1586 env = GNUNET_MQ_msg_extra (msg,
1588 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1589 msg->add_remove = htonl ((int32_t) add);
1590 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1591 GNUNET_NAT_AC_GLOBAL);
1592 GNUNET_memcpy (&msg[1],
1595 GNUNET_MQ_send (ch->mq,
1602 * Function to be called when we decide that an
1603 * external IP address as told to us by a STUN
1604 * server has gone stale.
1606 * @param cls the `struct StunExternalIP` to drop
1609 stun_ip_timeout (void *cls)
1611 struct StunExternalIP *se = cls;
1613 se->timeout_task = NULL;
1614 notify_clients_stun_change (&se->external_addr,
1616 GNUNET_CONTAINER_DLL_remove (se_head,
1624 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1627 * @param cls client who sent the message
1628 * @param message the message received
1631 handle_stun (void *cls,
1632 const struct GNUNET_NAT_HandleStunMessage *message)
1634 struct ClientHandle *ch = cls;
1635 const char *buf = (const char *) &message[1];
1636 const struct sockaddr *sa;
1637 const void *payload;
1639 size_t payload_size;
1640 struct sockaddr_in external_addr;
1642 sa_len = ntohs (message->sender_addr_size);
1643 payload_size = ntohs (message->payload_size);
1644 sa = (const struct sockaddr *) &buf[0];
1645 payload = (const struct sockaddr *) &buf[sa_len];
1646 switch (sa->sa_family)
1649 if (sa_len != sizeof (struct sockaddr_in))
1652 GNUNET_SERVICE_client_drop (ch->client);
1657 if (sa_len != sizeof (struct sockaddr_in6))
1660 GNUNET_SERVICE_client_drop (ch->client);
1665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1666 "Received HANDLE_STUN message from client\n");
1668 GNUNET_NAT_stun_handle_packet_ (payload,
1672 /* We now know that a server at "sa" claims that
1673 we are visible at IP "external_addr".
1675 We should (for some fixed period of time) tell
1676 all of our clients that listen to a NAT'ed address
1677 that they might want to consider the given 'external_ip'
1678 as their public IP address (this includes TCP and UDP
1679 clients, even if only UDP sends STUN requests).
1681 If we do not get a renewal, the "external_addr" should be
1682 removed again. The timeout frequency should be configurable
1683 (with a sane default), so that the UDP plugin can tell how
1684 often to re-request STUN.
1686 struct StunExternalIP *se;
1688 /* Check if we had a prior response from this STUN server */
1689 for (se = se_head; NULL != se; se = se->next)
1691 if ( (se->stun_server_addr_len != sa_len) ||
1693 &se->stun_server_addr,
1695 continue; /* different STUN server */
1696 if (0 != memcmp (&external_addr,
1698 sizeof (struct sockaddr_in)))
1700 /* external IP changed, update! */
1701 notify_clients_stun_change (&se->external_addr,
1703 se->external_addr = external_addr;
1704 notify_clients_stun_change (&se->external_addr,
1707 /* update timeout */
1708 GNUNET_SCHEDULER_cancel (se->timeout_task);
1710 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1715 /* STUN server is completely new, create fresh entry */
1716 se = GNUNET_new (struct StunExternalIP);
1717 se->external_addr = external_addr;
1718 GNUNET_memcpy (&se->stun_server_addr,
1721 se->stun_server_addr_len = sa_len;
1722 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1725 GNUNET_CONTAINER_DLL_insert (se_head,
1728 notify_clients_stun_change (&se->external_addr,
1731 GNUNET_SERVICE_client_continue (ch->client);
1737 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1740 * @param cls client who sent the message
1741 * @param message the message received
1742 * @return #GNUNET_OK if message is well-formed
1745 check_request_connection_reversal (void *cls,
1746 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1750 expect = ntohs (message->local_addr_size)
1751 + ntohs (message->remote_addr_size);
1752 if (ntohs (message->header.size) - sizeof (*message) != expect)
1755 return GNUNET_SYSERR;
1762 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1763 * message from client.
1765 * @param cls client who sent the message
1766 * @param message the message received
1769 handle_request_connection_reversal (void *cls,
1770 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1772 struct ClientHandle *ch = cls;
1773 const char *buf = (const char *) &message[1];
1774 size_t local_sa_len = ntohs (message->local_addr_size);
1775 size_t remote_sa_len = ntohs (message->remote_addr_size);
1776 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1777 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1778 const struct sockaddr_in *l4 = NULL;
1779 const struct sockaddr_in *r4;
1782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783 "Received REQUEST CONNECTION REVERSAL message from client\n");
1784 switch (local_sa->sa_family)
1787 if (local_sa_len != sizeof (struct sockaddr_in))
1790 GNUNET_SERVICE_client_drop (ch->client);
1793 l4 = (const struct sockaddr_in *) local_sa;
1796 if (local_sa_len != sizeof (struct sockaddr_in6))
1799 GNUNET_SERVICE_client_drop (ch->client);
1802 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1803 _("Connection reversal for IPv6 not supported yet\n"));
1804 ret = GNUNET_SYSERR;
1808 GNUNET_SERVICE_client_drop (ch->client);
1811 switch (remote_sa->sa_family)
1814 if (remote_sa_len != sizeof (struct sockaddr_in))
1817 GNUNET_SERVICE_client_drop (ch->client);
1820 r4 = (const struct sockaddr_in *) remote_sa;
1821 ret = GN_request_connection_reversal (&l4->sin_addr,
1822 ntohs (l4->sin_port),
1826 if (remote_sa_len != sizeof (struct sockaddr_in6))
1829 GNUNET_SERVICE_client_drop (ch->client);
1832 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1833 _("Connection reversal for IPv6 not supported yet\n"));
1834 ret = GNUNET_SYSERR;
1838 GNUNET_SERVICE_client_drop (ch->client);
1841 if (GNUNET_OK != ret)
1842 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1843 _("Connection reversal request failed\n"));
1844 GNUNET_SERVICE_client_continue (ch->client);
1849 * Task run during shutdown.
1854 shutdown_task (void *cls)
1856 struct StunExternalIP *se;
1858 while (NULL != (se = se_head))
1860 GNUNET_CONTAINER_DLL_remove (se_head,
1863 GNUNET_SCHEDULER_cancel (se->timeout_task);
1866 GN_nat_status_changed (GNUNET_NO);
1867 if (NULL != scan_task)
1869 GNUNET_SCHEDULER_cancel (scan_task);
1874 GNUNET_STATISTICS_destroy (stats,
1883 * Setup NAT service.
1885 * @param cls closure
1886 * @param c configuration to use
1887 * @param service the initialized service
1891 const struct GNUNET_CONFIGURATION_Handle *c,
1892 struct GNUNET_SERVICE_Handle *service)
1896 GNUNET_CONFIGURATION_get_value_time (cfg,
1899 &stun_stale_timeout))
1900 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1902 /* Check for UPnP */
1904 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1907 if (GNUNET_YES == enable_upnp)
1909 /* check if it works */
1910 if (GNUNET_SYSERR ==
1911 GNUNET_OS_check_helper_binary ("upnpc",
1915 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1916 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1917 enable_upnp = GNUNET_SYSERR;
1921 GNUNET_CONFIGURATION_get_value_time (cfg,
1925 dyndns_frequency = DYNDNS_FREQUENCY;
1927 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1929 stats = GNUNET_STATISTICS_create ("nat",
1931 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1937 * Callback called when a client connects to the service.
1939 * @param cls closure for the service
1940 * @param c the new client that connected to the service
1941 * @param mq the message queue used to send messages to the client
1942 * @return a `struct ClientHandle`
1945 client_connect_cb (void *cls,
1946 struct GNUNET_SERVICE_Client *c,
1947 struct GNUNET_MQ_Handle *mq)
1949 struct ClientHandle *ch;
1951 ch = GNUNET_new (struct ClientHandle);
1954 GNUNET_CONTAINER_DLL_insert (ch_head,
1962 * Callback called when a client disconnected from the service
1964 * @param cls closure for the service
1965 * @param c the client that disconnected
1966 * @param internal_cls a `struct ClientHandle *`
1969 client_disconnect_cb (void *cls,
1970 struct GNUNET_SERVICE_Client *c,
1973 struct ClientHandle *ch = internal_cls;
1974 struct LocalAddressList *lal;
1976 GNUNET_CONTAINER_DLL_remove (ch_head,
1979 for (unsigned int i=0;i<ch->num_caddrs;i++)
1981 if (NULL != ch->caddrs[i].mh)
1983 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
1984 ch->caddrs[i].mh = NULL;
1987 GNUNET_free_non_null (ch->caddrs);
1988 while (NULL != (lal = ch->ext_addr_head))
1990 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1995 if (NULL != ch->ext_dns_task)
1997 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
1998 ch->ext_dns_task = NULL;
2000 if (NULL != ch->external_monitor)
2002 GN_external_ipv4_monitor_stop (ch->external_monitor);
2003 ch->external_monitor = NULL;
2005 if (NULL != ch->ext_dns)
2007 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2010 GNUNET_free (ch->hole_external);
2011 GNUNET_free (ch->section_name);
2017 * Define "main" method using service macro.
2021 GNUNET_SERVICE_OPTION_NONE,
2024 &client_disconnect_cb,
2026 GNUNET_MQ_hd_var_size (register,
2027 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2028 struct GNUNET_NAT_RegisterMessage,
2030 GNUNET_MQ_hd_var_size (stun,
2031 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2032 struct GNUNET_NAT_HandleStunMessage,
2034 GNUNET_MQ_hd_var_size (request_connection_reversal,
2035 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2036 struct GNUNET_NAT_RequestConnectionReversalMessage,
2038 GNUNET_MQ_handler_end ());
2041 #if defined(LINUX) && defined(__GLIBC__)
2045 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2047 void __attribute__ ((constructor))
2048 GNUNET_ARM_memory_init ()
2050 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2051 mallopt (M_TOP_PAD, 1 * 1024);
2056 /* end of gnunet-service-nat.c */