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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
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 * - migrate test cases to new NAT service
32 * - add new traceroute-based logic for external IP detection
34 * - implement & test STUN processing to classify NAT;
35 * basically, open port & try different methods.
39 #include "gnunet_util_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
42 #include "gnunet_statistics_service.h"
43 #include "gnunet_resolver_service.h"
44 #include "gnunet_nat_service.h"
45 #include "gnunet-service-nat.h"
46 #include "gnunet-service-nat_externalip.h"
47 #include "gnunet-service-nat_stun.h"
48 #include "gnunet-service-nat_mini.h"
49 #include "gnunet-service-nat_helper.h"
55 * How often should we ask the OS about a list of active
58 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
61 * How long do we wait until we forcefully terminate autoconfiguration?
63 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply ( \
64 GNUNET_TIME_UNIT_SECONDS, 5)
67 * How often do we scan for changes in how our external (dyndns) hostname resolves?
69 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply ( \
70 GNUNET_TIME_UNIT_MINUTES, 7)
74 * Information we track per client address.
79 * Network address used by the client.
81 struct sockaddr_storage ss;
84 * Handle to active UPnP request where we asked upnpc to open
85 * a port at the NAT. NULL if we do not have such a request
88 struct GNUNET_NAT_MiniHandle *mh;
93 * List of local addresses this system has.
95 struct LocalAddressList
98 * This is a linked list.
100 struct LocalAddressList *next;
105 struct LocalAddressList *prev;
108 * Context for a gnunet-helper-nat-server used to listen
109 * for ICMP messages to this client for connection reversal.
111 struct HelperContext *hc;
114 * The address itself (i.e. `struct sockaddr_in` or `struct
115 * sockaddr_in6`, in the respective byte order).
117 struct sockaddr_storage addr;
120 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
125 * #GNUNET_YES if we saw this one in the previous iteration,
126 * but not in the current iteration and thus might need to
127 * remove it at the end.
132 * What type of address is this?
134 enum GNUNET_NAT_AddressClass ac;
139 * Internal data structure we track for each of our clients.
146 struct ClientHandle *next;
151 struct ClientHandle *prev;
154 * Underlying handle for this client with the service.
156 struct GNUNET_SERVICE_Client *client;
159 * Message queue for communicating with the client.
161 struct GNUNET_MQ_Handle *mq;
164 * Array of addresses used by the service.
166 struct ClientAddress *caddrs;
169 * External DNS name and port given by user due to manual
170 * hole punching. Special DNS name 'AUTO' is used to indicate
171 * desire for automatic determination of the external IP
172 * (instead of DNS or manual configuration, i.e. to be used
173 * if the IP keeps changing and we have no DynDNS, but we do
174 * have a hole punched).
179 * Name of the configuration section this client cares about.
184 * Task for periodically re-running the @e ext_dns DNS lookup.
186 struct GNUNET_SCHEDULER_Task *ext_dns_task;
189 * Handle for (DYN)DNS lookup of our external IP as given in
192 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
195 * Handle for monitoring external IP changes.
197 struct GN_ExternalIPMonitor *external_monitor;
200 * DLL of external IP addresses as given in @e hole_external.
202 struct LocalAddressList *ext_addr_head;
205 * DLL of external IP addresses as given in @e hole_external.
207 struct LocalAddressList *ext_addr_tail;
210 * Port number we found in @e hole_external.
212 uint16_t ext_dns_port;
215 * What does this client care about?
217 enum GNUNET_NAT_RegisterFlags flags;
220 * Is any of the @e caddrs in a reserved subnet for NAT?
225 * Number of addresses that this service is bound to.
226 * Length of the @e caddrs array.
231 * 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.
339 * Is IP Scanning enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
340 * without, only explicitly specified IPs will be handled (HOLE_EXTERNAL)
345 * Remove and free an entry from the #lal_head DLL.
347 * @param lal entry to free
350 free_lal (struct LocalAddressList *lal)
352 GNUNET_CONTAINER_DLL_remove (lal_head,
357 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
358 "Lost NATed local address %s, stopping NAT server\n",
359 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
360 sizeof(struct sockaddr_in)));
362 GN_stop_gnunet_nat_server_ (lal->hc);
370 * Free the DLL starting at #lal_head.
375 struct LocalAddressList *lal;
377 while (NULL != (lal = lal_head))
383 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
386 * @param cls client who sent the message
387 * @param message the message received
388 * @return #GNUNET_OK if message is well-formed
391 check_register (void *cls,
392 const struct GNUNET_NAT_RegisterMessage *message)
394 uint16_t num_addrs = ntohs (message->num_addrs);
395 const char *off = (const char *) &message[1];
396 size_t left = ntohs (message->header.size) - sizeof(*message);
398 for (unsigned int i = 0; i < num_addrs; i++)
401 const struct sockaddr *sa = (const struct sockaddr *) off;
403 if (sizeof(sa_family_t) > left)
406 return GNUNET_SYSERR;
408 switch (sa->sa_family)
411 alen = sizeof(struct sockaddr_in);
415 alen = sizeof(struct sockaddr_in6);
420 alen = sizeof(struct sockaddr_un);
425 return GNUNET_SYSERR;
430 return GNUNET_SYSERR;
435 if (left != ntohs (message->str_len))
438 return GNUNET_SYSERR;
445 * Check if @a ip is in @a network with @a bits netmask.
447 * @param network to test
448 * @param ip IP address to test
449 * @param bits bitmask for the network
450 * @return #GNUNET_YES if @a ip is in @a network
453 match_ipv4 (const char *network,
454 const struct in_addr *ip,
463 GNUNET_assert (1 == inet_pton (AF_INET,
466 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
471 * Check if @a ip is in @a network with @a bits netmask.
473 * @param network to test
474 * @param ip IP address to test
475 * @param bits bitmask for the network
476 * @return #GNUNET_YES if @a ip is in @a network
479 match_ipv6 (const char *network,
480 const struct in6_addr *ip,
484 struct in6_addr mask;
489 GNUNET_assert (1 == inet_pton (AF_INET6,
492 memset (&mask, 0, sizeof(mask));
493 if (0 == GNUNET_memcmp (&mask,
499 mask.s6_addr[off++] = 0xFF;
504 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
507 for (unsigned j = 0; j < sizeof(struct in6_addr) / sizeof(uint32_t); j++)
508 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
509 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
516 * Test if the given IPv4 address is in a known range
517 * for private networks.
519 * @param ip address to test
520 * @return #GNUNET_YES if @a ip is in a NAT range
523 is_nat_v4 (const struct in_addr *ip)
526 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
527 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
528 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
529 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
530 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
535 * Test if the given IPv6 address is in a known range
536 * for private networks.
538 * @param ip address to test
539 * @return #GNUNET_YES if @a ip is in a NAT range
542 is_nat_v6 (const struct in6_addr *ip)
545 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
546 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
547 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
552 * Closure for #ifc_proc.
554 struct IfcProcContext
557 * Head of DLL of local addresses.
559 struct LocalAddressList *lal_head;
562 * Tail of DLL of local addresses.
564 struct LocalAddressList *lal_tail;
569 * Callback function invoked for each interface found. Adds them
570 * to our new address list.
572 * @param cls a `struct IfcProcContext *`
573 * @param name name of the interface (can be NULL for unknown)
574 * @param isDefault is this presumably the default interface
575 * @param addr address of this interface (can be NULL for unknown or unassigned)
576 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
577 * @param netmask the network mask (can be NULL for unknown or unassigned)
578 * @param addrlen length of the address
579 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
585 const struct sockaddr *addr,
586 const struct sockaddr *broadcast_addr,
587 const struct sockaddr *netmask,
590 struct IfcProcContext *ifc_ctx = cls;
591 struct LocalAddressList *lal;
593 const struct in_addr *ip4;
594 const struct in6_addr *ip6;
595 enum GNUNET_NAT_AddressClass ac;
597 switch (addr->sa_family)
600 alen = sizeof(struct sockaddr_in);
601 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
602 if (match_ipv4 ("127.0.0.0", ip4, 8))
603 ac = GNUNET_NAT_AC_LOOPBACK;
604 else if (is_nat_v4 (ip4))
605 ac = GNUNET_NAT_AC_LAN;
607 ac = GNUNET_NAT_AC_GLOBAL;
611 alen = sizeof(struct sockaddr_in6);
612 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
613 if (match_ipv6 ("::1", ip6, 128))
614 ac = GNUNET_NAT_AC_LOOPBACK;
615 else if (is_nat_v6 (ip6))
616 ac = GNUNET_NAT_AC_LAN;
618 ac = GNUNET_NAT_AC_GLOBAL;
619 if ((ip6->s6_addr[11] == 0xFF) &&
620 (ip6->s6_addr[12] == 0xFE))
622 /* contains a MAC, be extra careful! */
623 ac |= GNUNET_NAT_AC_PRIVATE;
636 lal = GNUNET_malloc (sizeof(*lal));
637 lal->af = addr->sa_family;
639 GNUNET_memcpy (&lal->addr,
642 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
650 * Notify client about a change in the list of addresses this peer
653 * @param ac address class of the entry in the list that changed
654 * @param ch client to contact
655 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
656 * @param addr the address that changed
657 * @param addr_len number of bytes in @a addr
660 notify_client (enum GNUNET_NAT_AddressClass ac,
661 struct ClientHandle *ch,
666 struct GNUNET_MQ_Envelope *env;
667 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
670 "Notifying client about %s of IP %s\n",
671 add ? "addition" : "removal",
674 env = GNUNET_MQ_msg_extra (msg,
676 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
677 msg->add_remove = htonl (add);
678 msg->addr_class = htonl (ac);
679 GNUNET_memcpy (&msg[1],
682 GNUNET_MQ_send (ch->mq,
688 * Check if we should bother to notify this client about this
689 * address change, and if so, do it.
691 * @param delta the entry in the list that changed
692 * @param ch client to check
693 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
696 check_notify_client (struct LocalAddressList *delta,
697 struct ClientHandle *ch,
701 struct sockaddr_in v4;
702 struct sockaddr_in6 v6;
704 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "Not notifying client as it does not care about addresses\n");
713 alen = sizeof(struct sockaddr_in);
718 /* Check for client notifications */
719 for (unsigned int i = 0; i < ch->num_caddrs; i++)
721 const struct sockaddr_in *c4;
723 if (AF_INET != ch->caddrs[i].ss.ss_family)
724 continue; /* IPv4 not relevant */
725 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
726 if (match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
727 (0 != c4->sin_addr.s_addr) &&
728 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)))
729 continue; /* bound to loopback, but this is not loopback */
730 if ((! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8)) &&
731 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8))
732 continue; /* bound to non-loopback, but this is loopback */
733 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
734 (0 != c4->sin_addr.s_addr) &&
735 (! is_nat_v4 (&v4.sin_addr)))
736 continue; /* based on external-IP, but this IP is not
737 from private address range. */
738 if ((0 != GNUNET_memcmp (&v4.sin_addr,
740 (0 != c4->sin_addr.s_addr) &&
741 (! is_nat_v4 (&c4->sin_addr)))
742 continue; /* this IP is not from private address range,
743 and IP does not match. */
745 /* OK, IP seems relevant, notify client */
746 if (0 == htons (v4.sin_port))
747 v4.sin_port = c4->sin_port;
748 notify_client (delta->ac,
757 alen = sizeof(struct sockaddr_in6);
761 for (unsigned int i = 0; i < ch->num_caddrs; i++)
763 const struct sockaddr_in6 *c6;
765 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
766 continue; /* IPv4 not relevant */
767 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
768 if (match_ipv6 ("::1", &c6->sin6_addr, 128) &&
769 (0 != GNUNET_memcmp (&c6->sin6_addr,
771 (! match_ipv6 ("::1", &v6.sin6_addr, 128)))
772 continue; /* bound to loopback, but this is not loopback */
773 if ((! match_ipv6 ("::1", &c6->sin6_addr, 128)) &&
774 match_ipv6 ("::1", &v6.sin6_addr, 128))
775 continue; /* bound to non-loopback, but this is loopback */
776 if ((0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
777 (0 != GNUNET_memcmp (&c6->sin6_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 != GNUNET_memcmp (&v6.sin6_addr,
784 (0 != GNUNET_memcmp (&c6->sin6_addr,
786 (! is_nat_v6 (&c6->sin6_addr)))
787 continue; /* this IP is not from private address range,
788 and IP does not match. */
789 if ((match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
790 (0 != GNUNET_memcmp (&c6->sin6_addr,
792 (0 != GNUNET_memcmp (&v6.sin6_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,
817 * Notify all clients about a change in the list
818 * of addresses this peer has.
820 * @param delta the entry in the list that changed
821 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
824 notify_clients (struct LocalAddressList *delta,
827 for (struct ClientHandle *ch = ch_head;
830 check_notify_client (delta,
837 * Tell relevant client about a change in our external
840 * @param cls client to check if it cares and possibly notify
841 * @param v4 the external address that changed
842 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
845 notify_client_external_ipv4_change (void *cls,
846 const struct in_addr *v4,
849 struct ClientHandle *ch = cls;
850 struct sockaddr_in sa;
853 /* (0) check if this impacts 'hole_external' */
854 if ((NULL != ch->hole_external) &&
855 (0 == strcasecmp (ch->hole_external,
858 struct LocalAddressList lal;
859 struct sockaddr_in *s4;
861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
862 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
863 (unsigned int) ch->ext_dns_port,
865 memset (&lal, 0, sizeof(lal));
866 s4 = (struct sockaddr_in *) &lal.addr;
867 s4->sin_family = AF_INET;
868 s4->sin_port = htons (ch->ext_dns_port);
871 lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
872 check_notify_client (&lal,
877 /* (1) check if client cares. */
878 if (! ch->natted_address)
881 for (unsigned int i = 0; i < ch->num_caddrs; i++)
883 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
885 if (AF_INET != ss->ss_family)
887 have_v4 = GNUNET_YES;
890 if (GNUNET_NO == have_v4)
891 return; /* IPv6-only */
893 /* (2) build address info */
897 sa.sin_family = AF_INET;
899 sa.sin_port = htons (0);
901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
902 "Detected eternal IP %s, notifying client of external IP (without port)\n",
903 GNUNET_a2s ((const struct sockaddr *) &sa,
905 /* (3) notify client of change */
906 notify_client (is_nat_v4 (v4)
907 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
908 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
917 * We got a connection reversal request from another peer.
918 * Notify applicable clients.
920 * @param cls closure with the `struct LocalAddressList`
921 * @param ra IP address of the peer who wants us to connect to it
924 reversal_callback (void *cls,
925 const struct sockaddr_in *ra)
927 struct LocalAddressList *lal = cls;
928 const struct sockaddr_in *l4;
930 GNUNET_assert (AF_INET == lal->af);
931 l4 = (const struct sockaddr_in *) &lal->addr;
932 for (struct ClientHandle *ch = ch_head;
936 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
937 struct GNUNET_MQ_Envelope *env;
940 /* Check if client is in applicable range for ICMP NAT traversal
941 for this local address */
942 if (! ch->natted_address)
945 for (unsigned int i = 0; i < ch->num_caddrs; i++)
947 struct ClientAddress *ca = &ch->caddrs[i];
948 const struct sockaddr_in *c4;
950 if (AF_INET != ca->ss.ss_family)
952 c4 = (const struct sockaddr_in *) &ca->ss;
953 if ((0 != c4->sin_addr.s_addr) &&
954 (l4->sin_addr.s_addr != c4->sin_addr.s_addr))
962 /* Notify applicable client about connection reversal request */
963 env = GNUNET_MQ_msg_extra (crrm,
964 sizeof(struct sockaddr_in),
965 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
966 GNUNET_memcpy (&crrm[1],
968 sizeof(struct sockaddr_in));
969 GNUNET_MQ_send (ch->mq,
976 * Task we run periodically to scan for network interfaces.
983 struct IfcProcContext ifc_ctx;
986 struct LocalAddressList *lnext;
988 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
994 GNUNET_OS_network_interfaces_list (&ifc_proc,
996 /* remove addresses that disappeared */
997 for (struct LocalAddressList *lal = lal_head;
1003 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1007 if ((pos->af == lal->af) &&
1008 (0 == memcmp (&lal->addr,
1010 (AF_INET == lal->af)
1011 ? sizeof(struct sockaddr_in)
1012 : sizeof(struct sockaddr_in6))))
1017 if (GNUNET_NO == found)
1019 notify_clients (lal,
1025 /* add addresses that appeared */
1026 have_nat = GNUNET_NO;
1027 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1029 pos = ifc_ctx.lal_head)
1032 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1033 have_nat = GNUNET_YES;
1034 for (struct LocalAddressList *lal = 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 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1049 if (GNUNET_YES == found)
1055 notify_clients (pos,
1057 GNUNET_CONTAINER_DLL_insert (lal_head,
1060 if ((AF_INET == pos->af) &&
1061 (NULL == pos->hc) &&
1062 (0 != (GNUNET_NAT_AC_LAN & pos->ac)))
1064 const struct sockaddr_in *s4
1065 = (const struct sockaddr_in *) &pos->addr;
1067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1068 "Found NATed local address %s, starting NAT server\n",
1069 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1071 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1078 GN_nat_status_changed (have_nat);
1083 * Function called whenever our set of external addresses
1084 * as created by `upnpc` changes.
1086 * @param cls closure with our `struct ClientHandle *`
1087 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1088 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1089 * @param addr either the previous or the new public IP address
1090 * @param addrlen actual length of the @a addr
1091 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1094 upnp_addr_change_cb (void *cls,
1096 const struct sockaddr *addr,
1098 enum GNUNET_NAT_StatusCode result)
1100 struct ClientHandle *ch = cls;
1101 enum GNUNET_NAT_AddressClass ac;
1105 case GNUNET_NAT_ERROR_SUCCESS:
1106 GNUNET_assert (NULL != addr);
1109 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1110 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1111 case GNUNET_NAT_ERROR_IPC_FAILURE:
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1113 "Running upnpc failed: %d\n",
1117 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1118 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1119 "external-ip binary not found\n");
1122 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1123 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1124 "upnpc binary not found\n");
1127 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1128 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1129 "external-ip binary could not be run\n");
1132 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1133 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1134 "upnpc failed to create port mapping\n");
1137 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "Invalid output from upnpc\n");
1142 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1144 "Invalid address returned by upnpc\n");
1148 GNUNET_break (0); /* should not be possible */
1151 switch (addr->sa_family)
1154 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1156 : GNUNET_NAT_AC_EXTERN;
1160 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1162 : GNUNET_NAT_AC_EXTERN;
1169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1170 "upnp external address %s: %s\n",
1171 add_remove ? "added" : "removed",
1183 * Resolve the `hole_external` name to figure out our
1184 * external address from a manually punched hole. The
1185 * port number has already been parsed, this task is
1186 * responsible for periodically doing a DNS lookup.
1188 * @param ch client handle to act upon
1191 dyndns_lookup (void *cls);
1195 * Our (external) hostname was resolved. Update lists of
1196 * current external IPs (note that DNS may return multiple
1197 * addresses!) and notify client accordingly.
1199 * @param cls the `struct ClientHandle`
1200 * @param addr NULL on error, otherwise result of DNS lookup
1201 * @param addrlen number of bytes in @a addr
1204 process_external_ip (void *cls,
1205 const struct sockaddr *addr,
1208 struct ClientHandle *ch = cls;
1209 struct LocalAddressList *lal;
1210 struct sockaddr_storage ss;
1211 struct sockaddr_in *v4;
1212 struct sockaddr_in6 *v6;
1216 struct LocalAddressList *laln;
1220 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1223 /* Current iteration is over, remove 'old' IPs now */
1224 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1227 if (GNUNET_YES == lal->old)
1229 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1232 check_notify_client (lal,
1240 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1241 "Got IP `%s' for external address `%s'\n",
1246 /* build sockaddr storage with port number */
1253 switch (addr->sa_family)
1256 v4 = (struct sockaddr_in *) &ss;
1257 v4->sin_port = htons (ch->ext_dns_port);
1261 v6 = (struct sockaddr_in6 *) &ss;
1262 v6->sin6_port = htons (ch->ext_dns_port);
1269 /* See if 'ss' matches any of our known addresses */
1270 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1272 if (GNUNET_NO == lal->old)
1273 continue; /* already processed, skip */
1274 if ((addr->sa_family == lal->addr.ss_family) &&
1279 /* Address unchanged, remember so we do not remove */
1280 lal->old = GNUNET_NO;
1281 return; /* done here */
1284 /* notify client, and remember IP for later removal! */
1285 lal = GNUNET_new (struct LocalAddressList);
1287 lal->af = ss.ss_family;
1288 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1289 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1292 check_notify_client (lal,
1299 * Resolve the `hole_external` name to figure out our
1300 * external address from a manually punched hole. The
1301 * port number has already been parsed, this task is
1302 * responsible for periodically doing a DNS lookup.
1304 * @param ch client handle to act upon
1307 dyndns_lookup (void *cls)
1309 struct ClientHandle *ch = cls;
1310 struct LocalAddressList *lal;
1312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1316 (unsigned int) ch->ext_dns_port);
1317 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1318 lal->old = GNUNET_YES;
1319 ch->ext_dns_task = NULL;
1320 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1322 GNUNET_TIME_UNIT_MINUTES,
1323 &process_external_ip,
1329 * Resolve the `hole_external` name to figure out our
1330 * external address from a manually punched hole. The
1331 * given name may be "AUTO" in which case we should use
1332 * the IP address(es) we have from upnpc or other methods.
1333 * The name can also be an IP address, in which case we
1334 * do not need to do DNS resolution. Finally, we also
1335 * need to parse the port number.
1337 * @param ch client handle to act upon
1340 lookup_hole_external (struct ClientHandle *ch)
1344 struct sockaddr_in *s4;
1345 struct LocalAddressList *lal;
1347 port = strrchr (ch->hole_external, ':');
1350 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1351 _ ("Malformed punched hole specification `%s' (lacks port)\n"),
1355 if ((1 != sscanf (port + 1,
1360 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1362 "Invalid port number in punched hole specification `%s' (lacks port)\n"),
1366 ch->ext_dns_port = (uint16_t) pnum;
1369 lal = GNUNET_new (struct LocalAddressList);
1370 if ('[' == *ch->hole_external)
1372 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1374 s6->sin6_family = AF_INET6;
1375 if (']' != (ch->hole_external[strlen (ch->hole_external) - 1]))
1377 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1378 _ ("Malformed punched hole specification `%s' (lacks `]')\n"),
1383 ch->hole_external[strlen (ch->hole_external) - 1] = '\0';
1384 if (1 != inet_pton (AF_INET6,
1385 ch->hole_external + 1,
1388 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1390 "Malformed punched hole specification `%s' (IPv6 address invalid)"),
1391 ch->hole_external + 1);
1395 s6->sin6_port = htons (ch->ext_dns_port);
1397 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1398 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1401 check_notify_client (lal,
1407 s4 = (struct sockaddr_in *) &lal->addr;
1408 s4->sin_family = AF_INET;
1409 if (1 == inet_pton (AF_INET,
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1417 (unsigned int) ch->ext_dns_port);
1418 s4->sin_port = htons (ch->ext_dns_port);
1420 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1421 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1424 check_notify_client (lal,
1429 if (0 == strcasecmp (ch->hole_external,
1432 /* handled in #notify_client_external_ipv4_change() */
1436 /* got a DNS name, trigger lookup! */
1439 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1445 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1446 * We remember the client for updates upon future NAT events.
1448 * @param cls client who sent the message
1449 * @param message the message received
1452 handle_register (void *cls,
1453 const struct GNUNET_NAT_RegisterMessage *message)
1455 struct ClientHandle *ch = cls;
1459 if ((0 != ch->proto) ||
1460 (NULL != ch->caddrs))
1462 /* double registration not allowed */
1464 GNUNET_SERVICE_client_drop (ch->client);
1467 ch->flags = message->flags;
1468 ch->proto = message->proto;
1469 ch->num_caddrs = ntohs (message->num_addrs);
1470 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1471 struct ClientAddress);
1472 left = ntohs (message->header.size) - sizeof(*message);
1473 off = (const char *) &message[1];
1474 for (unsigned int i = 0; i < ch->num_caddrs; i++)
1476 const struct sockaddr *sa = (const struct sockaddr *) off;
1481 if (sizeof(sa_family_t) > left)
1484 GNUNET_SERVICE_client_drop (ch->client);
1488 switch (sa->sa_family)
1492 struct sockaddr_in s4;
1496 sizeof(struct sockaddr_in));
1497 alen = sizeof(struct sockaddr_in);
1498 if (is_nat_v4 (&s4.sin_addr))
1499 is_nat = GNUNET_YES;
1500 port = ntohs (s4.sin_port);
1506 struct sockaddr_in6 s6;
1510 sizeof(struct sockaddr_in6));
1511 alen = sizeof(struct sockaddr_in6);
1512 if (is_nat_v6 (&s6.sin6_addr))
1513 is_nat = GNUNET_YES;
1514 port = ntohs (s6.sin6_port);
1520 alen = sizeof(struct sockaddr_un);
1526 GNUNET_SERVICE_client_drop (ch->client);
1530 GNUNET_assert (alen <= left);
1531 GNUNET_assert (alen <= sizeof(struct sockaddr_storage));
1532 GNUNET_memcpy (&ch->caddrs[i].ss,
1536 /* If applicable, try UPNPC NAT punching */
1539 ((IPPROTO_TCP == ch->proto) ||
1540 (IPPROTO_UDP == ch->proto)))
1542 ch->natted_address = GNUNET_YES;
1544 = GNUNET_NAT_mini_map_start (port,
1545 IPPROTO_TCP == ch->proto,
1546 &upnp_addr_change_cb,
1554 = GNUNET_strndup (off,
1555 ntohs (message->str_len));
1556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1557 "Received REGISTER message from client for subsystem `%s'\n",
1560 GNUNET_CONFIGURATION_get_value_string (cfg,
1563 &ch->hole_external))
1564 lookup_hole_external (ch);
1566 /* Actually send IP address list to client */
1567 for (struct LocalAddressList *lal = lal_head;
1571 check_notify_client (lal,
1575 /* Also consider IPv4 determined by `external-ip` */
1576 ch->external_monitor
1577 = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change,
1579 GNUNET_SERVICE_client_continue (ch->client);
1584 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1587 * @param cls client who sent the message
1588 * @param message the message received
1589 * @return #GNUNET_OK if message is well-formed
1592 check_stun (void *cls,
1593 const struct GNUNET_NAT_HandleStunMessage *message)
1595 size_t sa_len = ntohs (message->sender_addr_size);
1596 size_t expect = sa_len + ntohs (message->payload_size);
1598 if (ntohs (message->header.size) - sizeof(*message) != expect)
1601 return GNUNET_SYSERR;
1603 if (sa_len < sizeof(sa_family_t))
1606 return GNUNET_SYSERR;
1613 * Notify all clients about our external IP address
1614 * as reported by the STUN server.
1616 * @param ip the external IP
1617 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1620 notify_clients_stun_change (const struct sockaddr_in *ip,
1623 for (struct ClientHandle *ch = ch_head;
1627 struct sockaddr_in v4;
1628 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1629 struct GNUNET_MQ_Envelope *env;
1631 if (! ch->natted_address)
1634 v4.sin_port = htons (0);
1635 env = GNUNET_MQ_msg_extra (msg,
1637 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1638 msg->add_remove = htonl ((int32_t) add);
1639 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN
1640 | GNUNET_NAT_AC_GLOBAL);
1641 GNUNET_memcpy (&msg[1],
1644 GNUNET_MQ_send (ch->mq,
1651 * Function to be called when we decide that an
1652 * external IP address as told to us by a STUN
1653 * server has gone stale.
1655 * @param cls the `struct StunExternalIP` to drop
1658 stun_ip_timeout (void *cls)
1660 struct StunExternalIP *se = cls;
1662 se->timeout_task = NULL;
1663 notify_clients_stun_change (&se->external_addr,
1665 GNUNET_CONTAINER_DLL_remove (se_head,
1673 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1676 * @param cls client who sent the message
1677 * @param message the message received
1680 handle_stun (void *cls,
1681 const struct GNUNET_NAT_HandleStunMessage *message)
1683 struct ClientHandle *ch = cls;
1684 const char *buf = (const char *) &message[1];
1685 const struct sockaddr *sa;
1686 const void *payload;
1688 size_t payload_size;
1689 struct sockaddr_in external_addr;
1691 sa_len = ntohs (message->sender_addr_size);
1692 payload_size = ntohs (message->payload_size);
1693 sa = (const struct sockaddr *) &buf[0];
1694 payload = (const struct sockaddr *) &buf[sa_len];
1695 switch (sa->sa_family)
1698 if (sa_len != sizeof(struct sockaddr_in))
1701 GNUNET_SERVICE_client_drop (ch->client);
1707 if (sa_len != sizeof(struct sockaddr_in6))
1710 GNUNET_SERVICE_client_drop (ch->client);
1715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1716 "Received HANDLE_STUN message from client\n");
1718 GNUNET_NAT_stun_handle_packet_ (payload,
1722 /* We now know that a server at "sa" claims that
1723 we are visible at IP "external_addr".
1725 We should (for some fixed period of time) tell
1726 all of our clients that listen to a NAT'ed address
1727 that they might want to consider the given 'external_ip'
1728 as their public IP address (this includes TCP and UDP
1729 clients, even if only UDP sends STUN requests).
1731 If we do not get a renewal, the "external_addr" should be
1732 removed again. The timeout frequency should be configurable
1733 (with a sane default), so that the UDP plugin can tell how
1734 often to re-request STUN.
1735 */struct StunExternalIP *se;
1737 /* Check if we had a prior response from this STUN server */
1738 for (se = se_head; NULL != se; se = se->next)
1740 if ((se->stun_server_addr_len != sa_len) ||
1742 &se->stun_server_addr,
1744 continue; /* different STUN server */
1745 if (0 != GNUNET_memcmp (&external_addr,
1746 &se->external_addr))
1748 /* external IP changed, update! */
1749 notify_clients_stun_change (&se->external_addr,
1751 se->external_addr = external_addr;
1752 notify_clients_stun_change (&se->external_addr,
1755 /* update timeout */
1756 GNUNET_SCHEDULER_cancel (se->timeout_task);
1758 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1763 /* STUN server is completely new, create fresh entry */
1764 se = GNUNET_new (struct StunExternalIP);
1765 se->external_addr = external_addr;
1766 GNUNET_memcpy (&se->stun_server_addr,
1769 se->stun_server_addr_len = sa_len;
1770 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1773 GNUNET_CONTAINER_DLL_insert (se_head,
1776 notify_clients_stun_change (&se->external_addr,
1779 GNUNET_SERVICE_client_continue (ch->client);
1785 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1788 * @param cls client who sent the message
1789 * @param message the message received
1790 * @return #GNUNET_OK if message is well-formed
1793 check_request_connection_reversal (void *cls,
1795 GNUNET_NAT_RequestConnectionReversalMessage *
1800 expect = ntohs (message->local_addr_size)
1801 + ntohs (message->remote_addr_size);
1802 if (ntohs (message->header.size) - sizeof(*message) != expect)
1805 return GNUNET_SYSERR;
1812 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1813 * message from client.
1815 * @param cls client who sent the message
1816 * @param message the message received
1819 handle_request_connection_reversal (void *cls,
1821 GNUNET_NAT_RequestConnectionReversalMessage
1824 struct ClientHandle *ch = cls;
1825 const char *buf = (const char *) &message[1];
1826 size_t local_sa_len = ntohs (message->local_addr_size);
1827 size_t remote_sa_len = ntohs (message->remote_addr_size);
1828 struct sockaddr_in l4;
1829 struct sockaddr_in r4;
1832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833 "Received REQUEST CONNECTION REVERSAL message from client\n");
1834 if (local_sa_len != sizeof(struct sockaddr_in))
1836 GNUNET_break_op (0);
1837 GNUNET_SERVICE_client_drop (ch->client);
1840 if (remote_sa_len != sizeof(struct sockaddr_in))
1842 GNUNET_break_op (0);
1843 GNUNET_SERVICE_client_drop (ch->client);
1848 sizeof(struct sockaddr_in));
1849 GNUNET_break_op (AF_INET == l4.sin_family);
1850 buf += sizeof(struct sockaddr_in);
1853 sizeof(struct sockaddr_in));
1854 GNUNET_break_op (AF_INET == r4.sin_family);
1855 ret = GN_request_connection_reversal (&l4.sin_addr,
1856 ntohs (l4.sin_port),
1859 if (GNUNET_OK != ret)
1860 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1861 _ ("Connection reversal request failed\n"));
1862 GNUNET_SERVICE_client_continue (ch->client);
1867 * Task run during shutdown.
1872 shutdown_task (void *cls)
1874 struct StunExternalIP *se;
1876 while (NULL != (se = se_head))
1878 GNUNET_CONTAINER_DLL_remove (se_head,
1881 GNUNET_SCHEDULER_cancel (se->timeout_task);
1884 GN_nat_status_changed (GNUNET_NO);
1885 if (NULL != scan_task)
1887 GNUNET_SCHEDULER_cancel (scan_task);
1892 GNUNET_STATISTICS_destroy (stats,
1901 * Setup NAT service.
1903 * @param cls closure
1904 * @param c configuration to use
1905 * @param service the initialized service
1909 const struct GNUNET_CONFIGURATION_Handle *c,
1910 struct GNUNET_SERVICE_Handle *service)
1914 GNUNET_CONFIGURATION_get_value_time (cfg,
1917 &stun_stale_timeout))
1918 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1920 /* Check for UPnP */
1922 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1925 if (GNUNET_YES == enable_upnp)
1927 /* check if it works */
1928 if (GNUNET_SYSERR ==
1929 GNUNET_OS_check_helper_binary ("upnpc",
1933 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1935 "UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1936 enable_upnp = GNUNET_SYSERR;
1940 GNUNET_CONFIGURATION_get_value_time (cfg,
1944 dyndns_frequency = DYNDNS_FREQUENCY;
1947 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1951 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1953 stats = GNUNET_STATISTICS_create ("nat",
1955 if (GNUNET_YES == enable_ipscan)
1956 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1962 * Callback called when a client connects to the service.
1964 * @param cls closure for the service
1965 * @param c the new client that connected to the service
1966 * @param mq the message queue used to send messages to the client
1967 * @return a `struct ClientHandle`
1970 client_connect_cb (void *cls,
1971 struct GNUNET_SERVICE_Client *c,
1972 struct GNUNET_MQ_Handle *mq)
1974 struct ClientHandle *ch;
1976 ch = GNUNET_new (struct ClientHandle);
1979 GNUNET_CONTAINER_DLL_insert (ch_head,
1987 * Callback called when a client disconnected from the service
1989 * @param cls closure for the service
1990 * @param c the client that disconnected
1991 * @param internal_cls a `struct ClientHandle *`
1994 client_disconnect_cb (void *cls,
1995 struct GNUNET_SERVICE_Client *c,
1998 struct ClientHandle *ch = internal_cls;
1999 struct LocalAddressList *lal;
2001 GNUNET_CONTAINER_DLL_remove (ch_head,
2004 for (unsigned int i = 0; i < ch->num_caddrs; i++)
2006 if (NULL != ch->caddrs[i].mh)
2008 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2009 ch->caddrs[i].mh = NULL;
2012 GNUNET_free_non_null (ch->caddrs);
2013 while (NULL != (lal = ch->ext_addr_head))
2015 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
2020 if (NULL != ch->ext_dns_task)
2022 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
2023 ch->ext_dns_task = NULL;
2025 if (NULL != ch->external_monitor)
2027 GN_external_ipv4_monitor_stop (ch->external_monitor);
2028 ch->external_monitor = NULL;
2030 if (NULL != ch->ext_dns)
2032 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2035 GNUNET_free_non_null (ch->hole_external);
2036 GNUNET_free_non_null (ch->section_name);
2042 * Define "main" method using service macro.
2046 GNUNET_SERVICE_OPTION_NONE,
2049 &client_disconnect_cb,
2051 GNUNET_MQ_hd_var_size (register,
2052 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2053 struct GNUNET_NAT_RegisterMessage,
2055 GNUNET_MQ_hd_var_size (stun,
2056 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2057 struct GNUNET_NAT_HandleStunMessage,
2059 GNUNET_MQ_hd_var_size (request_connection_reversal,
2060 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2061 struct GNUNET_NAT_RequestConnectionReversalMessage,
2063 GNUNET_MQ_handler_end ());
2066 #if defined(__linux__) && defined(__GLIBC__)
2070 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2072 void __attribute__ ((constructor))
2073 GNUNET_ARM_memory_init ()
2075 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2076 mallopt (M_TOP_PAD, 1 * 1024);
2083 /* end of gnunet-service-nat.c */