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 it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * @file nat/gnunet-service-nat.c
21 * @brief network address translation traversal service
22 * @author Christian Grothoff
24 * The purpose of this service is to enable transports to
25 * traverse NAT routers, by providing traversal options and
26 * knowledge about the local network topology.
29 * - migrate test cases to new NAT service
30 * - add new traceroute-based logic for external IP detection
32 * - implement & test STUN processing to classify NAT;
33 * basically, open port & try different methods.
37 #include "gnunet_util_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_statistics_service.h"
41 #include "gnunet_resolver_service.h"
42 #include "gnunet_nat_service.h"
43 #include "gnunet-service-nat.h"
44 #include "gnunet-service-nat_externalip.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 often do we scan for changes in how our external (dyndns) hostname resolves?
66 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
70 * Information we track per client address.
75 * Network address used by the client.
77 struct sockaddr_storage ss;
80 * Handle to active UPnP request where we asked upnpc to open
81 * a port at the NAT. NULL if we do not have such a request
84 struct GNUNET_NAT_MiniHandle *mh;
90 * List of local addresses this system has.
92 struct LocalAddressList
95 * This is a linked list.
97 struct LocalAddressList *next;
102 struct LocalAddressList *prev;
105 * Context for a gnunet-helper-nat-server used to listen
106 * for ICMP messages to this client for connection reversal.
108 struct HelperContext *hc;
111 * The address itself (i.e. `struct sockaddr_in` or `struct
112 * sockaddr_in6`, in the respective byte order).
114 struct sockaddr_storage addr;
117 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
122 * #GNUNET_YES if we saw this one in the previous iteration,
123 * but not in the current iteration and thus might need to
124 * remove it at the end.
129 * What type of address is this?
131 enum GNUNET_NAT_AddressClass ac;
137 * Internal data structure we track for each of our clients.
145 struct ClientHandle *next;
150 struct ClientHandle *prev;
153 * Underlying handle for this client with the service.
155 struct GNUNET_SERVICE_Client *client;
158 * Message queue for communicating with the client.
160 struct GNUNET_MQ_Handle *mq;
163 * Array of addresses used by the service.
165 struct ClientAddress *caddrs;
168 * External DNS name and port given by user due to manual
169 * hole punching. Special DNS name 'AUTO' is used to indicate
170 * desire for automatic determination of the external IP
171 * (instead of DNS or manual configuration, i.e. to be used
172 * if the IP keeps changing and we have no DynDNS, but we do
173 * have a hole punched).
178 * Name of the configuration section this client cares about.
183 * Task for periodically re-running the @e ext_dns DNS lookup.
185 struct GNUNET_SCHEDULER_Task *ext_dns_task;
188 * Handle for (DYN)DNS lookup of our external IP as given in
191 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
194 * Handle for monitoring external IP changes.
196 struct GN_ExternalIPMonitor *external_monitor;
199 * DLL of external IP addresses as given in @e hole_external.
201 struct LocalAddressList *ext_addr_head;
204 * DLL of external IP addresses as given in @e hole_external.
206 struct LocalAddressList *ext_addr_tail;
209 * Port number we found in @e hole_external.
211 uint16_t ext_dns_port;
214 * What does this client care about?
216 enum GNUNET_NAT_RegisterFlags flags;
219 * Is any of the @e caddrs in a reserved subnet for NAT?
224 * Number of addresses that this service is bound to.
225 * Length of the @e caddrs array.
230 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
238 * External IP address as given to us via some STUN server.
240 struct StunExternalIP
245 struct StunExternalIP *next;
250 struct StunExternalIP *prev;
253 * Task we run to remove this entry when it is stale.
255 struct GNUNET_SCHEDULER_Task *timeout_task;
258 * Our external IP address as reported by the
261 struct sockaddr_in external_addr;
264 * Address of the reporting STUN server. Used to
265 * detect when a STUN server changes its opinion
266 * to more quickly remove stale results.
268 struct sockaddr_storage stun_server_addr;
271 * Number of bytes used in @e stun_server_addr.
273 size_t stun_server_addr_len;
278 * Timeout to use when STUN data is considered stale.
280 static struct GNUNET_TIME_Relative stun_stale_timeout;
283 * How often do we scan for changes in how our external (dyndns) hostname resolves?
285 static struct GNUNET_TIME_Relative dyndns_frequency;
288 * Handle to our current configuration.
290 static const struct GNUNET_CONFIGURATION_Handle *cfg;
293 * Handle to the statistics service.
295 static struct GNUNET_STATISTICS_Handle *stats;
298 * Task scheduled to periodically scan our network interfaces.
300 static struct GNUNET_SCHEDULER_Task *scan_task;
303 * Head of client DLL.
305 static struct ClientHandle *ch_head;
308 * Tail of client DLL.
310 static struct ClientHandle *ch_tail;
313 * Head of DLL of local addresses.
315 static struct LocalAddressList *lal_head;
318 * Tail of DLL of local addresses.
320 static struct LocalAddressList *lal_tail;
325 static struct StunExternalIP *se_head;
330 static struct StunExternalIP *se_tail;
333 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
334 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
340 * Remove and free an entry from the #lal_head DLL.
342 * @param lal entry to free
345 free_lal (struct LocalAddressList *lal)
347 GNUNET_CONTAINER_DLL_remove (lal_head,
352 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
353 "Lost NATed local address %s, stopping NAT server\n",
354 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
355 sizeof (struct sockaddr_in)));
357 GN_stop_gnunet_nat_server_ (lal->hc);
365 * Free the DLL starting at #lal_head.
370 struct LocalAddressList *lal;
372 while (NULL != (lal = lal_head))
378 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
381 * @param cls client who sent the message
382 * @param message the message received
383 * @return #GNUNET_OK if message is well-formed
386 check_register (void *cls,
387 const struct GNUNET_NAT_RegisterMessage *message)
389 uint16_t num_addrs = ntohs (message->num_addrs);
390 const char *off = (const char *) &message[1];
391 size_t left = ntohs (message->header.size) - sizeof (*message);
393 for (unsigned int i=0;i<num_addrs;i++)
396 const struct sockaddr *sa = (const struct sockaddr *) off;
398 if (sizeof (sa_family_t) > left)
401 return GNUNET_SYSERR;
403 switch (sa->sa_family)
406 alen = sizeof (struct sockaddr_in);
409 alen = sizeof (struct sockaddr_in6);
413 alen = sizeof (struct sockaddr_un);
418 return GNUNET_SYSERR;
423 return GNUNET_SYSERR;
428 if (left != ntohs (message->str_len))
431 return GNUNET_SYSERR;
438 * Check if @a ip is in @a network with @a bits netmask.
440 * @param network to test
441 * @param ip IP address to test
442 * @param bits bitmask for the network
443 * @return #GNUNET_YES if @a ip is in @a network
446 match_ipv4 (const char *network,
447 const struct in_addr *ip,
456 GNUNET_assert (1 == inet_pton (AF_INET,
459 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
464 * Check if @a ip is in @a network with @a bits netmask.
466 * @param network to test
467 * @param ip IP address to test
468 * @param bits bitmask for the network
469 * @return #GNUNET_YES if @a ip is in @a network
472 match_ipv6 (const char *network,
473 const struct in6_addr *ip,
477 struct in6_addr mask;
482 GNUNET_assert (1 == inet_pton (AF_INET6,
485 memset (&mask, 0, sizeof (mask));
486 if (0 == memcmp (&mask,
493 mask.s6_addr[off++] = 0xFF;
498 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
501 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
502 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
503 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
510 * Test if the given IPv4 address is in a known range
511 * for private networks.
513 * @param ip address to test
514 * @return #GNUNET_YES if @a ip is in a NAT range
517 is_nat_v4 (const struct in_addr *ip)
520 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
521 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
522 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
523 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
524 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
529 * Test if the given IPv6 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_v6 (const struct in6_addr *ip)
539 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
540 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
541 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
546 * Closure for #ifc_proc.
548 struct IfcProcContext
552 * Head of DLL of local addresses.
554 struct LocalAddressList *lal_head;
557 * Tail of DLL of local addresses.
559 struct LocalAddressList *lal_tail;
565 * Callback function invoked for each interface found. Adds them
566 * to our new address list.
568 * @param cls a `struct IfcProcContext *`
569 * @param name name of the interface (can be NULL for unknown)
570 * @param isDefault is this presumably the default interface
571 * @param addr address of this interface (can be NULL for unknown or unassigned)
572 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
573 * @param netmask the network mask (can be NULL for unknown or unassigned)
574 * @param addrlen length of the address
575 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
581 const struct sockaddr *addr,
582 const struct sockaddr *broadcast_addr,
583 const struct sockaddr *netmask,
586 struct IfcProcContext *ifc_ctx = cls;
587 struct LocalAddressList *lal;
589 const struct in_addr *ip4;
590 const struct in6_addr *ip6;
591 enum GNUNET_NAT_AddressClass ac;
593 switch (addr->sa_family)
596 alen = sizeof (struct sockaddr_in);
597 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
598 if (match_ipv4 ("127.0.0.0", ip4, 8))
599 ac = GNUNET_NAT_AC_LOOPBACK;
600 else if (is_nat_v4 (ip4))
601 ac = GNUNET_NAT_AC_LAN;
603 ac = GNUNET_NAT_AC_GLOBAL;
606 alen = sizeof (struct sockaddr_in6);
607 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
608 if (match_ipv6 ("::1", ip6, 128))
609 ac = GNUNET_NAT_AC_LOOPBACK;
610 else if (is_nat_v6 (ip6))
611 ac = GNUNET_NAT_AC_LAN;
613 ac = GNUNET_NAT_AC_GLOBAL;
614 if ( (ip6->s6_addr[11] == 0xFF) &&
615 (ip6->s6_addr[12] == 0xFE) )
617 /* contains a MAC, be extra careful! */
618 ac |= GNUNET_NAT_AC_PRIVATE;
630 lal = GNUNET_malloc (sizeof (*lal));
631 lal->af = addr->sa_family;
633 GNUNET_memcpy (&lal->addr,
636 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
644 * Notify client about a change in the list of addresses this peer
647 * @param ac address class of the entry in the list that changed
648 * @param ch client to contact
649 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
650 * @param addr the address that changed
651 * @param addr_len number of bytes in @a addr
654 notify_client (enum GNUNET_NAT_AddressClass ac,
655 struct ClientHandle *ch,
660 struct GNUNET_MQ_Envelope *env;
661 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
664 "Notifying client about %s of IP %s\n",
665 add ? "addition" : "removal",
668 env = GNUNET_MQ_msg_extra (msg,
670 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
671 msg->add_remove = htonl (add);
672 msg->addr_class = htonl (ac);
673 GNUNET_memcpy (&msg[1],
676 GNUNET_MQ_send (ch->mq,
682 * Check if we should bother to notify this client about this
683 * address change, and if so, do it.
685 * @param delta the entry in the list that changed
686 * @param ch client to check
687 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
690 check_notify_client (struct LocalAddressList *delta,
691 struct ClientHandle *ch,
695 struct sockaddr_in v4;
696 struct sockaddr_in6 v6;
698 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701 "Not notifying client as it does not care about addresses\n");
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 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
726 continue; /* bound to non-loopback, but this is loopback */
727 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
728 (0 != c4->sin_addr.s_addr) &&
729 (! is_nat_v4 (&v4.sin_addr)) )
730 continue; /* based on external-IP, but this IP is not
731 from private address range. */
732 if ( (0 != memcmp (&v4.sin_addr,
734 sizeof (struct in_addr))) &&
735 (0 != c4->sin_addr.s_addr) &&
736 (! is_nat_v4 (&c4->sin_addr)) )
737 continue; /* this IP is not from private address range,
738 and IP does not match. */
740 /* OK, IP seems relevant, notify client */
741 if (0 == htons (v4.sin_port))
742 v4.sin_port = c4->sin_port;
743 notify_client (delta->ac,
751 alen = sizeof (struct sockaddr_in6);
755 for (unsigned int i=0;i<ch->num_caddrs;i++)
757 const struct sockaddr_in6 *c6;
759 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
760 continue; /* IPv4 not relevant */
761 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
762 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
763 (0 != memcmp (&c6->sin6_addr,
765 sizeof (struct in6_addr))) &&
766 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
767 continue; /* bound to loopback, but this is not loopback */
768 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
769 match_ipv6 ("::1", &v6.sin6_addr, 128) )
770 continue; /* bound to non-loopback, but this is loopback */
771 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
772 (0 != memcmp (&c6->sin6_addr,
774 sizeof (struct in6_addr))) &&
775 (! is_nat_v6 (&v6.sin6_addr)) )
776 continue; /* based on external-IP, but this IP is not
777 from private address range. */
778 if ( (0 != memcmp (&v6.sin6_addr,
780 sizeof (struct in6_addr))) &&
781 (0 != memcmp (&c6->sin6_addr,
783 sizeof (struct in6_addr))) &&
784 (! is_nat_v6 (&c6->sin6_addr)) )
785 continue; /* this IP is not from private address range,
786 and IP does not match. */
787 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
788 (0 != memcmp (&c6->sin6_addr,
790 sizeof (struct in6_addr))) &&
791 (0 != memcmp (&v6.sin6_addr,
793 sizeof (struct in6_addr))) &&
794 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
795 continue; /* client bound to link-local, and the other address
796 does not match and is not an external IP */
798 /* OK, IP seems relevant, notify client */
799 if (0 == htons (v6.sin6_port))
800 v6.sin6_port = c6->sin6_port;
801 notify_client (delta->ac,
816 * Notify all clients about a change in the list
817 * of addresses this peer has.
819 * @param delta the entry in the list that changed
820 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
823 notify_clients (struct LocalAddressList *delta,
826 for (struct ClientHandle *ch = ch_head;
829 check_notify_client (delta,
836 * Tell relevant client about a change in our external
839 * @param cls client to check if it cares and possibly notify
840 * @param v4 the external address that changed
841 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
844 notify_client_external_ipv4_change (void *cls,
845 const struct in_addr *v4,
848 struct ClientHandle *ch = cls;
849 struct sockaddr_in sa;
852 /* (0) check if this impacts 'hole_external' */
853 if ( (NULL != ch->hole_external) &&
854 (0 == strcasecmp (ch->hole_external,
857 struct LocalAddressList lal;
858 struct sockaddr_in *s4;
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
862 (unsigned int) ch->ext_dns_port,
864 memset (&lal, 0, sizeof (lal));
865 s4 = (struct sockaddr_in *) &lal.addr;
866 s4->sin_family = AF_INET;
867 s4->sin_port = htons (ch->ext_dns_port);
870 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
871 check_notify_client (&lal,
876 /* (1) check if client cares. */
877 if (! ch->natted_address)
880 for (unsigned int i=0;i<ch->num_caddrs;i++)
882 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
884 if (AF_INET != ss->ss_family)
886 have_v4 = GNUNET_YES;
889 if (GNUNET_NO == have_v4)
890 return; /* IPv6-only */
892 /* (2) build address info */
896 sa.sin_family = AF_INET;
898 sa.sin_port = htons (0);
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
901 "Detected eternal IP %s, notifying client of external IP (without port)\n",
902 GNUNET_a2s ((const struct sockaddr *) &sa,
904 /* (3) notify client of change */
905 notify_client (is_nat_v4 (v4)
906 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
907 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
916 * We got a connection reversal request from another peer.
917 * Notify applicable clients.
919 * @param cls closure with the `struct LocalAddressList`
920 * @param ra IP address of the peer who wants us to connect to it
923 reversal_callback (void *cls,
924 const struct sockaddr_in *ra)
926 struct LocalAddressList *lal = cls;
927 const struct sockaddr_in *l4;
929 GNUNET_assert (AF_INET == lal->af);
930 l4 = (const struct sockaddr_in *) &lal->addr;
931 for (struct ClientHandle *ch = ch_head;
935 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
936 struct GNUNET_MQ_Envelope *env;
939 /* Check if client is in applicable range for ICMP NAT traversal
940 for this local address */
941 if (! ch->natted_address)
944 for (unsigned int i=0;i<ch->num_caddrs;i++)
946 struct ClientAddress *ca = &ch->caddrs[i];
947 const struct sockaddr_in *c4;
949 if (AF_INET != ca->ss.ss_family)
951 c4 = (const struct sockaddr_in *) &ca->ss;
952 if ( (0 != c4->sin_addr.s_addr) &&
953 (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
961 /* Notify applicable client about connection reversal request */
962 env = GNUNET_MQ_msg_extra (crrm,
963 sizeof (struct sockaddr_in),
964 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
965 GNUNET_memcpy (&crrm[1],
967 sizeof (struct sockaddr_in));
968 GNUNET_MQ_send (ch->mq,
975 * Task we run periodically to scan for network interfaces.
982 struct IfcProcContext ifc_ctx;
985 struct LocalAddressList *lnext;
987 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
993 GNUNET_OS_network_interfaces_list (&ifc_proc,
995 /* remove addresses that disappeared */
996 for (struct LocalAddressList *lal = lal_head;
1002 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1006 if ( (pos->af == lal->af) &&
1007 (0 == memcmp (&lal->addr,
1009 (AF_INET == lal->af)
1010 ? sizeof (struct sockaddr_in)
1011 : sizeof (struct sockaddr_in6))) )
1016 if (GNUNET_NO == found)
1018 notify_clients (lal,
1024 /* add addresses that appeared */
1025 have_nat = GNUNET_NO;
1026 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1028 pos = ifc_ctx.lal_head)
1031 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1032 have_nat = GNUNET_YES;
1033 for (struct LocalAddressList *lal = 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 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1048 if (GNUNET_YES == found)
1054 notify_clients (pos,
1056 GNUNET_CONTAINER_DLL_insert (lal_head,
1059 if ( (AF_INET == pos->af) &&
1060 (NULL == pos->hc) &&
1061 (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1063 const struct sockaddr_in *s4
1064 = (const struct sockaddr_in *) &pos->addr;
1066 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067 "Found NATed local address %s, starting NAT server\n",
1068 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1070 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1076 GN_nat_status_changed (have_nat);
1081 * Function called whenever our set of external addresses
1082 * as created by `upnpc` changes.
1084 * @param cls closure with our `struct ClientHandle *`
1085 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1086 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1087 * @param addr either the previous or the new public IP address
1088 * @param addrlen actual length of the @a addr
1089 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1092 upnp_addr_change_cb (void *cls,
1094 const struct sockaddr *addr,
1096 enum GNUNET_NAT_StatusCode result)
1098 struct ClientHandle *ch = cls;
1099 enum GNUNET_NAT_AddressClass ac;
1103 case GNUNET_NAT_ERROR_SUCCESS:
1104 GNUNET_assert (NULL != addr);
1106 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1107 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1108 case GNUNET_NAT_ERROR_IPC_FAILURE:
1109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1110 "Running upnpc failed: %d\n",
1113 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1114 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1115 "external-ip binary not found\n");
1117 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1118 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1119 "upnpc binary not found\n");
1121 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1122 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1123 "external-ip binary could not be run\n");
1125 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1126 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1127 "upnpc failed to create port mapping\n");
1129 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1131 "Invalid output from upnpc\n");
1133 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1135 "Invalid address returned by upnpc\n");
1138 GNUNET_break (0); /* should not be possible */
1141 switch (addr->sa_family)
1144 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1146 : GNUNET_NAT_AC_EXTERN;
1149 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1151 : GNUNET_NAT_AC_EXTERN;
1157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158 "upnp external address %s: %s\n",
1159 add_remove ? "added" : "removed",
1171 * Resolve the `hole_external` name to figure out our
1172 * external address from a manually punched hole. The
1173 * port number has already been parsed, this task is
1174 * responsible for periodically doing a DNS lookup.
1176 * @param ch client handle to act upon
1179 dyndns_lookup (void *cls);
1183 * Our (external) hostname was resolved. Update lists of
1184 * current external IPs (note that DNS may return multiple
1185 * addresses!) and notify client accordingly.
1187 * @param cls the `struct ClientHandle`
1188 * @param addr NULL on error, otherwise result of DNS lookup
1189 * @param addrlen number of bytes in @a addr
1192 process_external_ip (void *cls,
1193 const struct sockaddr *addr,
1196 struct ClientHandle *ch = cls;
1197 struct LocalAddressList *lal;
1198 struct sockaddr_storage ss;
1199 struct sockaddr_in *v4;
1200 struct sockaddr_in6 *v6;
1204 struct LocalAddressList *laln;
1208 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1211 /* Current iteration is over, remove 'old' IPs now */
1212 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1215 if (GNUNET_YES == lal->old)
1217 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1220 check_notify_client (lal,
1228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1229 "Got IP `%s' for external address `%s'\n",
1234 /* build sockaddr storage with port number */
1241 switch (addr->sa_family)
1244 v4 = (struct sockaddr_in *) &ss;
1245 v4->sin_port = htons (ch->ext_dns_port);
1248 v6 = (struct sockaddr_in6 *) &ss;
1249 v6->sin6_port = htons (ch->ext_dns_port);
1255 /* See if 'ss' matches any of our known addresses */
1256 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1258 if (GNUNET_NO == lal->old)
1259 continue; /* already processed, skip */
1260 if ( (addr->sa_family == lal->addr.ss_family) &&
1265 /* Address unchanged, remember so we do not remove */
1266 lal->old = GNUNET_NO;
1267 return; /* done here */
1270 /* notify client, and remember IP for later removal! */
1271 lal = GNUNET_new (struct LocalAddressList);
1273 lal->af = ss.ss_family;
1274 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1275 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1278 check_notify_client (lal,
1285 * Resolve the `hole_external` name to figure out our
1286 * external address from a manually punched hole. The
1287 * port number has already been parsed, this task is
1288 * responsible for periodically doing a DNS lookup.
1290 * @param ch client handle to act upon
1293 dyndns_lookup (void *cls)
1295 struct ClientHandle *ch = cls;
1296 struct LocalAddressList *lal;
1298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1299 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1302 (unsigned int) ch->ext_dns_port);
1303 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1304 lal->old = GNUNET_YES;
1305 ch->ext_dns_task = NULL;
1306 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1308 GNUNET_TIME_UNIT_MINUTES,
1309 &process_external_ip,
1315 * Resolve the `hole_external` name to figure out our
1316 * external address from a manually punched hole. The
1317 * given name may be "AUTO" in which case we should use
1318 * the IP address(es) we have from upnpc or other methods.
1319 * The name can also be an IP address, in which case we
1320 * do not need to do DNS resolution. Finally, we also
1321 * need to parse the port number.
1323 * @param ch client handle to act upon
1326 lookup_hole_external (struct ClientHandle *ch)
1330 struct sockaddr_in *s4;
1331 struct LocalAddressList *lal;
1333 port = strrchr (ch->hole_external, ':');
1336 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1337 _("Malformed punched hole specification `%s' (lacks port)\n"),
1341 if ( (1 != sscanf (port + 1,
1346 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1347 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1351 ch->ext_dns_port = (uint16_t) pnum;
1354 lal = GNUNET_new (struct LocalAddressList);
1355 if ('[' == *ch->hole_external)
1357 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1359 s6->sin6_family = AF_INET6;
1360 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1362 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1363 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1368 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1369 if (1 != inet_pton (AF_INET6,
1370 ch->hole_external + 1,
1373 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1374 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1375 ch->hole_external + 1);
1379 s6->sin6_port = htons (ch->ext_dns_port);
1381 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1382 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1385 check_notify_client (lal,
1391 s4 = (struct sockaddr_in *) &lal->addr;
1392 s4->sin_family = AF_INET;
1393 if (1 == inet_pton (AF_INET,
1397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1398 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1401 (unsigned int) ch->ext_dns_port);
1402 s4->sin_port = htons (ch->ext_dns_port);
1404 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1405 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1408 check_notify_client (lal,
1413 if (0 == strcasecmp (ch->hole_external,
1416 /* handled in #notify_client_external_ipv4_change() */
1420 /* got a DNS name, trigger lookup! */
1423 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1429 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1430 * We remember the client for updates upon future NAT events.
1432 * @param cls client who sent the message
1433 * @param message the message received
1436 handle_register (void *cls,
1437 const struct GNUNET_NAT_RegisterMessage *message)
1439 struct ClientHandle *ch = cls;
1443 if ( (0 != ch->proto) ||
1444 (NULL != ch->caddrs) )
1446 /* double registration not allowed */
1448 GNUNET_SERVICE_client_drop (ch->client);
1451 ch->flags = message->flags;
1452 ch->proto = message->proto;
1453 ch->num_caddrs = ntohs (message->num_addrs);
1454 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1455 struct ClientAddress);
1456 left = ntohs (message->header.size) - sizeof (*message);
1457 off = (const char *) &message[1];
1458 for (unsigned int i=0;i<ch->num_caddrs;i++)
1460 const struct sockaddr *sa = (const struct sockaddr *) off;
1465 if (sizeof (sa_family_t) > left)
1468 GNUNET_SERVICE_client_drop (ch->client);
1472 switch (sa->sa_family)
1476 struct sockaddr_in s4;
1480 sizeof (struct sockaddr_in));
1481 alen = sizeof (struct sockaddr_in);
1482 if (is_nat_v4 (&s4.sin_addr))
1483 is_nat = GNUNET_YES;
1484 port = ntohs (s4.sin_port);
1489 struct sockaddr_in6 s6;
1493 sizeof (struct sockaddr_in6));
1494 alen = sizeof (struct sockaddr_in6);
1495 if (is_nat_v6 (&s6.sin6_addr))
1496 is_nat = GNUNET_YES;
1497 port = ntohs (s6.sin6_port);
1502 alen = sizeof (struct sockaddr_un);
1508 GNUNET_SERVICE_client_drop (ch->client);
1512 GNUNET_assert (alen <= left);
1513 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1514 GNUNET_memcpy (&ch->caddrs[i].ss,
1518 /* If applicable, try UPNPC NAT punching */
1521 ( (IPPROTO_TCP == ch->proto) ||
1522 (IPPROTO_UDP == ch->proto) ) )
1524 ch->natted_address = GNUNET_YES;
1526 = GNUNET_NAT_mini_map_start (port,
1527 IPPROTO_TCP == ch->proto,
1528 &upnp_addr_change_cb,
1536 = GNUNET_strndup (off,
1537 ntohs (message->str_len));
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539 "Received REGISTER message from client for subsystem `%s'\n",
1542 GNUNET_CONFIGURATION_get_value_string (cfg,
1545 &ch->hole_external))
1546 lookup_hole_external (ch);
1548 /* Actually send IP address list to client */
1549 for (struct LocalAddressList *lal = lal_head;
1553 check_notify_client (lal,
1557 /* Also consider IPv4 determined by `external-ip` */
1558 ch->external_monitor
1559 = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change,
1561 GNUNET_SERVICE_client_continue (ch->client);
1566 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1569 * @param cls client who sent the message
1570 * @param message the message received
1571 * @return #GNUNET_OK if message is well-formed
1574 check_stun (void *cls,
1575 const struct GNUNET_NAT_HandleStunMessage *message)
1577 size_t sa_len = ntohs (message->sender_addr_size);
1578 size_t expect = sa_len + ntohs (message->payload_size);
1580 if (ntohs (message->header.size) - sizeof (*message) != expect)
1583 return GNUNET_SYSERR;
1585 if (sa_len < sizeof (sa_family_t))
1588 return GNUNET_SYSERR;
1595 * Notify all clients about our external IP address
1596 * as reported by the STUN server.
1598 * @param ip the external IP
1599 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1602 notify_clients_stun_change (const struct sockaddr_in *ip,
1605 for (struct ClientHandle *ch = ch_head;
1609 struct sockaddr_in v4;
1610 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1611 struct GNUNET_MQ_Envelope *env;
1613 if (! ch->natted_address)
1616 v4.sin_port = htons (0);
1617 env = GNUNET_MQ_msg_extra (msg,
1619 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1620 msg->add_remove = htonl ((int32_t) add);
1621 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1622 GNUNET_NAT_AC_GLOBAL);
1623 GNUNET_memcpy (&msg[1],
1626 GNUNET_MQ_send (ch->mq,
1633 * Function to be called when we decide that an
1634 * external IP address as told to us by a STUN
1635 * server has gone stale.
1637 * @param cls the `struct StunExternalIP` to drop
1640 stun_ip_timeout (void *cls)
1642 struct StunExternalIP *se = cls;
1644 se->timeout_task = NULL;
1645 notify_clients_stun_change (&se->external_addr,
1647 GNUNET_CONTAINER_DLL_remove (se_head,
1655 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1658 * @param cls client who sent the message
1659 * @param message the message received
1662 handle_stun (void *cls,
1663 const struct GNUNET_NAT_HandleStunMessage *message)
1665 struct ClientHandle *ch = cls;
1666 const char *buf = (const char *) &message[1];
1667 const struct sockaddr *sa;
1668 const void *payload;
1670 size_t payload_size;
1671 struct sockaddr_in external_addr;
1673 sa_len = ntohs (message->sender_addr_size);
1674 payload_size = ntohs (message->payload_size);
1675 sa = (const struct sockaddr *) &buf[0];
1676 payload = (const struct sockaddr *) &buf[sa_len];
1677 switch (sa->sa_family)
1680 if (sa_len != sizeof (struct sockaddr_in))
1683 GNUNET_SERVICE_client_drop (ch->client);
1688 if (sa_len != sizeof (struct sockaddr_in6))
1691 GNUNET_SERVICE_client_drop (ch->client);
1696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1697 "Received HANDLE_STUN message from client\n");
1699 GNUNET_NAT_stun_handle_packet_ (payload,
1703 /* We now know that a server at "sa" claims that
1704 we are visible at IP "external_addr".
1706 We should (for some fixed period of time) tell
1707 all of our clients that listen to a NAT'ed address
1708 that they might want to consider the given 'external_ip'
1709 as their public IP address (this includes TCP and UDP
1710 clients, even if only UDP sends STUN requests).
1712 If we do not get a renewal, the "external_addr" should be
1713 removed again. The timeout frequency should be configurable
1714 (with a sane default), so that the UDP plugin can tell how
1715 often to re-request STUN.
1717 struct StunExternalIP *se;
1719 /* Check if we had a prior response from this STUN server */
1720 for (se = se_head; NULL != se; se = se->next)
1722 if ( (se->stun_server_addr_len != sa_len) ||
1724 &se->stun_server_addr,
1726 continue; /* different STUN server */
1727 if (0 != memcmp (&external_addr,
1729 sizeof (struct sockaddr_in)))
1731 /* external IP changed, update! */
1732 notify_clients_stun_change (&se->external_addr,
1734 se->external_addr = external_addr;
1735 notify_clients_stun_change (&se->external_addr,
1738 /* update timeout */
1739 GNUNET_SCHEDULER_cancel (se->timeout_task);
1741 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1746 /* STUN server is completely new, create fresh entry */
1747 se = GNUNET_new (struct StunExternalIP);
1748 se->external_addr = external_addr;
1749 GNUNET_memcpy (&se->stun_server_addr,
1752 se->stun_server_addr_len = sa_len;
1753 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1756 GNUNET_CONTAINER_DLL_insert (se_head,
1759 notify_clients_stun_change (&se->external_addr,
1762 GNUNET_SERVICE_client_continue (ch->client);
1768 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1771 * @param cls client who sent the message
1772 * @param message the message received
1773 * @return #GNUNET_OK if message is well-formed
1776 check_request_connection_reversal (void *cls,
1777 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1781 expect = ntohs (message->local_addr_size)
1782 + ntohs (message->remote_addr_size);
1783 if (ntohs (message->header.size) - sizeof (*message) != expect)
1786 return GNUNET_SYSERR;
1793 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1794 * message from client.
1796 * @param cls client who sent the message
1797 * @param message the message received
1800 handle_request_connection_reversal (void *cls,
1801 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1803 struct ClientHandle *ch = cls;
1804 const char *buf = (const char *) &message[1];
1805 size_t local_sa_len = ntohs (message->local_addr_size);
1806 size_t remote_sa_len = ntohs (message->remote_addr_size);
1807 struct sockaddr_in l4;
1808 struct sockaddr_in r4;
1811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1812 "Received REQUEST CONNECTION REVERSAL message from client\n");
1813 if (local_sa_len != sizeof (struct sockaddr_in))
1815 GNUNET_break_op (0);
1816 GNUNET_SERVICE_client_drop (ch->client);
1819 if (remote_sa_len != sizeof (struct sockaddr_in))
1821 GNUNET_break_op (0);
1822 GNUNET_SERVICE_client_drop (ch->client);
1827 sizeof (struct sockaddr_in));
1828 GNUNET_break_op (AF_INET == l4.sin_family);
1829 buf += sizeof (struct sockaddr_in);
1832 sizeof (struct sockaddr_in));
1833 GNUNET_break_op (AF_INET == r4.sin_family);
1834 ret = GN_request_connection_reversal (&l4.sin_addr,
1835 ntohs (l4.sin_port),
1837 if (GNUNET_OK != ret)
1838 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1839 _("Connection reversal request failed\n"));
1840 GNUNET_SERVICE_client_continue (ch->client);
1845 * Task run during shutdown.
1850 shutdown_task (void *cls)
1852 struct StunExternalIP *se;
1854 while (NULL != (se = se_head))
1856 GNUNET_CONTAINER_DLL_remove (se_head,
1859 GNUNET_SCHEDULER_cancel (se->timeout_task);
1862 GN_nat_status_changed (GNUNET_NO);
1863 if (NULL != scan_task)
1865 GNUNET_SCHEDULER_cancel (scan_task);
1870 GNUNET_STATISTICS_destroy (stats,
1879 * Setup NAT service.
1881 * @param cls closure
1882 * @param c configuration to use
1883 * @param service the initialized service
1887 const struct GNUNET_CONFIGURATION_Handle *c,
1888 struct GNUNET_SERVICE_Handle *service)
1892 GNUNET_CONFIGURATION_get_value_time (cfg,
1895 &stun_stale_timeout))
1896 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1898 /* Check for UPnP */
1900 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1903 if (GNUNET_YES == enable_upnp)
1905 /* check if it works */
1906 if (GNUNET_SYSERR ==
1907 GNUNET_OS_check_helper_binary ("upnpc",
1911 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1912 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1913 enable_upnp = GNUNET_SYSERR;
1917 GNUNET_CONFIGURATION_get_value_time (cfg,
1921 dyndns_frequency = DYNDNS_FREQUENCY;
1923 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1925 stats = GNUNET_STATISTICS_create ("nat",
1927 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1933 * Callback called when a client connects to the service.
1935 * @param cls closure for the service
1936 * @param c the new client that connected to the service
1937 * @param mq the message queue used to send messages to the client
1938 * @return a `struct ClientHandle`
1941 client_connect_cb (void *cls,
1942 struct GNUNET_SERVICE_Client *c,
1943 struct GNUNET_MQ_Handle *mq)
1945 struct ClientHandle *ch;
1947 ch = GNUNET_new (struct ClientHandle);
1950 GNUNET_CONTAINER_DLL_insert (ch_head,
1958 * Callback called when a client disconnected from the service
1960 * @param cls closure for the service
1961 * @param c the client that disconnected
1962 * @param internal_cls a `struct ClientHandle *`
1965 client_disconnect_cb (void *cls,
1966 struct GNUNET_SERVICE_Client *c,
1969 struct ClientHandle *ch = internal_cls;
1970 struct LocalAddressList *lal;
1972 GNUNET_CONTAINER_DLL_remove (ch_head,
1975 for (unsigned int i=0;i<ch->num_caddrs;i++)
1977 if (NULL != ch->caddrs[i].mh)
1979 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
1980 ch->caddrs[i].mh = NULL;
1983 GNUNET_free_non_null (ch->caddrs);
1984 while (NULL != (lal = ch->ext_addr_head))
1986 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1991 if (NULL != ch->ext_dns_task)
1993 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
1994 ch->ext_dns_task = NULL;
1996 if (NULL != ch->external_monitor)
1998 GN_external_ipv4_monitor_stop (ch->external_monitor);
1999 ch->external_monitor = NULL;
2001 if (NULL != ch->ext_dns)
2003 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2006 GNUNET_free_non_null (ch->hole_external);
2007 GNUNET_free_non_null (ch->section_name);
2013 * Define "main" method using service macro.
2017 GNUNET_SERVICE_OPTION_NONE,
2020 &client_disconnect_cb,
2022 GNUNET_MQ_hd_var_size (register,
2023 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2024 struct GNUNET_NAT_RegisterMessage,
2026 GNUNET_MQ_hd_var_size (stun,
2027 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2028 struct GNUNET_NAT_HandleStunMessage,
2030 GNUNET_MQ_hd_var_size (request_connection_reversal,
2031 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2032 struct GNUNET_NAT_RequestConnectionReversalMessage,
2034 GNUNET_MQ_handler_end ());
2037 #if defined(LINUX) && defined(__GLIBC__)
2041 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2043 void __attribute__ ((constructor))
2044 GNUNET_ARM_memory_init ()
2046 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2047 mallopt (M_TOP_PAD, 1 * 1024);
2052 /* end of gnunet-service-nat.c */