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 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.
17 * @file nat/gnunet-service-nat.c
18 * @brief network address translation traversal service
19 * @author Christian Grothoff
21 * The purpose of this service is to enable transports to
22 * traverse NAT routers, by providing traversal options and
23 * knowledge about the local network topology.
26 * - migrate test cases to new NAT service
27 * - add new traceroute-based logic for external IP detection
29 * - implement & test STUN processing to classify NAT;
30 * basically, open port & try different methods.
34 #include "gnunet_util_lib.h"
35 #include "gnunet_protocols.h"
36 #include "gnunet_signatures.h"
37 #include "gnunet_statistics_service.h"
38 #include "gnunet_resolver_service.h"
39 #include "gnunet_nat_service.h"
40 #include "gnunet-service-nat.h"
41 #include "gnunet-service-nat_externalip.h"
42 #include "gnunet-service-nat_stun.h"
43 #include "gnunet-service-nat_mini.h"
44 #include "gnunet-service-nat_helper.h"
50 * How often should we ask the OS about a list of active
53 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
56 * How long do we wait until we forcefully terminate autoconfiguration?
58 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
61 * How often do we scan for changes in how our external (dyndns) hostname resolves?
63 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
67 * Information we track per client address.
72 * Network address used by the client.
74 struct sockaddr_storage ss;
77 * Handle to active UPnP request where we asked upnpc to open
78 * a port at the NAT. NULL if we do not have such a request
81 struct GNUNET_NAT_MiniHandle *mh;
87 * List of local addresses this system has.
89 struct LocalAddressList
92 * This is a linked list.
94 struct LocalAddressList *next;
99 struct LocalAddressList *prev;
102 * Context for a gnunet-helper-nat-server used to listen
103 * for ICMP messages to this client for connection reversal.
105 struct HelperContext *hc;
108 * The address itself (i.e. `struct sockaddr_in` or `struct
109 * sockaddr_in6`, in the respective byte order).
111 struct sockaddr_storage addr;
114 * Address family. (FIXME: redundant, addr.ss_family! Remove!?)
119 * #GNUNET_YES if we saw this one in the previous iteration,
120 * but not in the current iteration and thus might need to
121 * remove it at the end.
126 * What type of address is this?
128 enum GNUNET_NAT_AddressClass ac;
134 * Internal data structure we track for each of our clients.
142 struct ClientHandle *next;
147 struct ClientHandle *prev;
150 * Underlying handle for this client with the service.
152 struct GNUNET_SERVICE_Client *client;
155 * Message queue for communicating with the client.
157 struct GNUNET_MQ_Handle *mq;
160 * Array of addresses used by the service.
162 struct ClientAddress *caddrs;
165 * External DNS name and port given by user due to manual
166 * hole punching. Special DNS name 'AUTO' is used to indicate
167 * desire for automatic determination of the external IP
168 * (instead of DNS or manual configuration, i.e. to be used
169 * if the IP keeps changing and we have no DynDNS, but we do
170 * have a hole punched).
175 * Name of the configuration section this client cares about.
180 * Task for periodically re-running the @e ext_dns DNS lookup.
182 struct GNUNET_SCHEDULER_Task *ext_dns_task;
185 * Handle for (DYN)DNS lookup of our external IP as given in
188 struct GNUNET_RESOLVER_RequestHandle *ext_dns;
191 * Handle for monitoring external IP changes.
193 struct GN_ExternalIPMonitor *external_monitor;
196 * DLL of external IP addresses as given in @e hole_external.
198 struct LocalAddressList *ext_addr_head;
201 * DLL of external IP addresses as given in @e hole_external.
203 struct LocalAddressList *ext_addr_tail;
206 * Port number we found in @e hole_external.
208 uint16_t ext_dns_port;
211 * What does this client care about?
213 enum GNUNET_NAT_RegisterFlags flags;
216 * Is any of the @e caddrs in a reserved subnet for NAT?
221 * Number of addresses that this service is bound to.
222 * Length of the @e caddrs array.
227 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
235 * External IP address as given to us via some STUN server.
237 struct StunExternalIP
242 struct StunExternalIP *next;
247 struct StunExternalIP *prev;
250 * Task we run to remove this entry when it is stale.
252 struct GNUNET_SCHEDULER_Task *timeout_task;
255 * Our external IP address as reported by the
258 struct sockaddr_in external_addr;
261 * Address of the reporting STUN server. Used to
262 * detect when a STUN server changes its opinion
263 * to more quickly remove stale results.
265 struct sockaddr_storage stun_server_addr;
268 * Number of bytes used in @e stun_server_addr.
270 size_t stun_server_addr_len;
275 * Timeout to use when STUN data is considered stale.
277 static struct GNUNET_TIME_Relative stun_stale_timeout;
280 * How often do we scan for changes in how our external (dyndns) hostname resolves?
282 static struct GNUNET_TIME_Relative dyndns_frequency;
285 * Handle to our current configuration.
287 static const struct GNUNET_CONFIGURATION_Handle *cfg;
290 * Handle to the statistics service.
292 static struct GNUNET_STATISTICS_Handle *stats;
295 * Task scheduled to periodically scan our network interfaces.
297 static struct GNUNET_SCHEDULER_Task *scan_task;
300 * Head of client DLL.
302 static struct ClientHandle *ch_head;
305 * Tail of client DLL.
307 static struct ClientHandle *ch_tail;
310 * Head of DLL of local addresses.
312 static struct LocalAddressList *lal_head;
315 * Tail of DLL of local addresses.
317 static struct LocalAddressList *lal_tail;
322 static struct StunExternalIP *se_head;
327 static struct StunExternalIP *se_tail;
330 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
331 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
337 * Remove and free an entry from the #lal_head DLL.
339 * @param lal entry to free
342 free_lal (struct LocalAddressList *lal)
344 GNUNET_CONTAINER_DLL_remove (lal_head,
349 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
350 "Lost NATed local address %s, stopping NAT server\n",
351 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
352 sizeof (struct sockaddr_in)));
354 GN_stop_gnunet_nat_server_ (lal->hc);
362 * Free the DLL starting at #lal_head.
367 struct LocalAddressList *lal;
369 while (NULL != (lal = lal_head))
375 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
378 * @param cls client who sent the message
379 * @param message the message received
380 * @return #GNUNET_OK if message is well-formed
383 check_register (void *cls,
384 const struct GNUNET_NAT_RegisterMessage *message)
386 uint16_t num_addrs = ntohs (message->num_addrs);
387 const char *off = (const char *) &message[1];
388 size_t left = ntohs (message->header.size) - sizeof (*message);
390 for (unsigned int i=0;i<num_addrs;i++)
393 const struct sockaddr *sa = (const struct sockaddr *) off;
395 if (sizeof (sa_family_t) > left)
398 return GNUNET_SYSERR;
400 switch (sa->sa_family)
403 alen = sizeof (struct sockaddr_in);
406 alen = sizeof (struct sockaddr_in6);
410 alen = sizeof (struct sockaddr_un);
415 return GNUNET_SYSERR;
420 return GNUNET_SYSERR;
425 if (left != ntohs (message->str_len))
428 return GNUNET_SYSERR;
435 * Check if @a ip is in @a network with @a bits netmask.
437 * @param network to test
438 * @param ip IP address to test
439 * @param bits bitmask for the network
440 * @return #GNUNET_YES if @a ip is in @a network
443 match_ipv4 (const char *network,
444 const struct in_addr *ip,
453 GNUNET_assert (1 == inet_pton (AF_INET,
456 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
461 * Check if @a ip is in @a network with @a bits netmask.
463 * @param network to test
464 * @param ip IP address to test
465 * @param bits bitmask for the network
466 * @return #GNUNET_YES if @a ip is in @a network
469 match_ipv6 (const char *network,
470 const struct in6_addr *ip,
474 struct in6_addr mask;
479 GNUNET_assert (1 == inet_pton (AF_INET6,
482 memset (&mask, 0, sizeof (mask));
483 if (0 == memcmp (&mask,
490 mask.s6_addr[off++] = 0xFF;
495 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
498 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
499 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
500 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
507 * Test if the given IPv4 address is in a known range
508 * for private networks.
510 * @param ip address to test
511 * @return #GNUNET_YES if @a ip is in a NAT range
514 is_nat_v4 (const struct in_addr *ip)
517 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
518 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
519 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
520 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
521 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
526 * Test if the given IPv6 address is in a known range
527 * for private networks.
529 * @param ip address to test
530 * @return #GNUNET_YES if @a ip is in a NAT range
533 is_nat_v6 (const struct in6_addr *ip)
536 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
537 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
538 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
543 * Closure for #ifc_proc.
545 struct IfcProcContext
549 * Head of DLL of local addresses.
551 struct LocalAddressList *lal_head;
554 * Tail of DLL of local addresses.
556 struct LocalAddressList *lal_tail;
562 * Callback function invoked for each interface found. Adds them
563 * to our new address list.
565 * @param cls a `struct IfcProcContext *`
566 * @param name name of the interface (can be NULL for unknown)
567 * @param isDefault is this presumably the default interface
568 * @param addr address of this interface (can be NULL for unknown or unassigned)
569 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
570 * @param netmask the network mask (can be NULL for unknown or unassigned)
571 * @param addrlen length of the address
572 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
578 const struct sockaddr *addr,
579 const struct sockaddr *broadcast_addr,
580 const struct sockaddr *netmask,
583 struct IfcProcContext *ifc_ctx = cls;
584 struct LocalAddressList *lal;
586 const struct in_addr *ip4;
587 const struct in6_addr *ip6;
588 enum GNUNET_NAT_AddressClass ac;
590 switch (addr->sa_family)
593 alen = sizeof (struct sockaddr_in);
594 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
595 if (match_ipv4 ("127.0.0.0", ip4, 8))
596 ac = GNUNET_NAT_AC_LOOPBACK;
597 else if (is_nat_v4 (ip4))
598 ac = GNUNET_NAT_AC_LAN;
600 ac = GNUNET_NAT_AC_GLOBAL;
603 alen = sizeof (struct sockaddr_in6);
604 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
605 if (match_ipv6 ("::1", ip6, 128))
606 ac = GNUNET_NAT_AC_LOOPBACK;
607 else if (is_nat_v6 (ip6))
608 ac = GNUNET_NAT_AC_LAN;
610 ac = GNUNET_NAT_AC_GLOBAL;
611 if ( (ip6->s6_addr[11] == 0xFF) &&
612 (ip6->s6_addr[12] == 0xFE) )
614 /* contains a MAC, be extra careful! */
615 ac |= GNUNET_NAT_AC_PRIVATE;
627 lal = GNUNET_malloc (sizeof (*lal));
628 lal->af = addr->sa_family;
630 GNUNET_memcpy (&lal->addr,
633 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
641 * Notify client about a change in the list of addresses this peer
644 * @param ac address class of the entry in the list that changed
645 * @param ch client to contact
646 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
647 * @param addr the address that changed
648 * @param addr_len number of bytes in @a addr
651 notify_client (enum GNUNET_NAT_AddressClass ac,
652 struct ClientHandle *ch,
657 struct GNUNET_MQ_Envelope *env;
658 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
661 "Notifying client about %s of IP %s\n",
662 add ? "addition" : "removal",
665 env = GNUNET_MQ_msg_extra (msg,
667 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
668 msg->add_remove = htonl (add);
669 msg->addr_class = htonl (ac);
670 GNUNET_memcpy (&msg[1],
673 GNUNET_MQ_send (ch->mq,
679 * Check if we should bother to notify this client about this
680 * address change, and if so, do it.
682 * @param delta the entry in the list that changed
683 * @param ch client to check
684 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
687 check_notify_client (struct LocalAddressList *delta,
688 struct ClientHandle *ch,
692 struct sockaddr_in v4;
693 struct sockaddr_in6 v6;
695 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
698 "Not notifying client as it does not care about addresses\n");
704 alen = sizeof (struct sockaddr_in);
709 /* Check for client notifications */
710 for (unsigned int i=0;i<ch->num_caddrs;i++)
712 const struct sockaddr_in *c4;
714 if (AF_INET != ch->caddrs[i].ss.ss_family)
715 continue; /* IPv4 not relevant */
716 c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
717 if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
718 (0 != c4->sin_addr.s_addr) &&
719 (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
720 continue; /* bound to loopback, but this is not loopback */
721 if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
722 match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
723 continue; /* bound to non-loopback, but this is loopback */
724 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
725 (0 != c4->sin_addr.s_addr) &&
726 (! is_nat_v4 (&v4.sin_addr)) )
727 continue; /* based on external-IP, but this IP is not
728 from private address range. */
729 if ( (0 != memcmp (&v4.sin_addr,
731 sizeof (struct in_addr))) &&
732 (0 != c4->sin_addr.s_addr) &&
733 (! is_nat_v4 (&c4->sin_addr)) )
734 continue; /* this IP is not from private address range,
735 and IP does not match. */
737 /* OK, IP seems relevant, notify client */
738 if (0 == htons (v4.sin_port))
739 v4.sin_port = c4->sin_port;
740 notify_client (delta->ac,
748 alen = sizeof (struct sockaddr_in6);
752 for (unsigned int i=0;i<ch->num_caddrs;i++)
754 const struct sockaddr_in6 *c6;
756 if (AF_INET6 != ch->caddrs[i].ss.ss_family)
757 continue; /* IPv4 not relevant */
758 c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
759 if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
760 (0 != memcmp (&c6->sin6_addr,
762 sizeof (struct in6_addr))) &&
763 (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
764 continue; /* bound to loopback, but this is not loopback */
765 if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
766 match_ipv6 ("::1", &v6.sin6_addr, 128) )
767 continue; /* bound to non-loopback, but this is loopback */
768 if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
769 (0 != memcmp (&c6->sin6_addr,
771 sizeof (struct in6_addr))) &&
772 (! is_nat_v6 (&v6.sin6_addr)) )
773 continue; /* based on external-IP, but this IP is not
774 from private address range. */
775 if ( (0 != memcmp (&v6.sin6_addr,
777 sizeof (struct in6_addr))) &&
778 (0 != memcmp (&c6->sin6_addr,
780 sizeof (struct in6_addr))) &&
781 (! is_nat_v6 (&c6->sin6_addr)) )
782 continue; /* this IP is not from private address range,
783 and IP does not match. */
784 if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
785 (0 != memcmp (&c6->sin6_addr,
787 sizeof (struct in6_addr))) &&
788 (0 != memcmp (&v6.sin6_addr,
790 sizeof (struct in6_addr))) &&
791 (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
792 continue; /* client bound to link-local, and the other address
793 does not match and is not an external IP */
795 /* OK, IP seems relevant, notify client */
796 if (0 == htons (v6.sin6_port))
797 v6.sin6_port = c6->sin6_port;
798 notify_client (delta->ac,
813 * Notify all clients about a change in the list
814 * of addresses this peer has.
816 * @param delta the entry in the list that changed
817 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
820 notify_clients (struct LocalAddressList *delta,
823 for (struct ClientHandle *ch = ch_head;
826 check_notify_client (delta,
833 * Tell relevant client about a change in our external
836 * @param cls client to check if it cares and possibly notify
837 * @param v4 the external address that changed
838 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
841 notify_client_external_ipv4_change (void *cls,
842 const struct in_addr *v4,
845 struct ClientHandle *ch = cls;
846 struct sockaddr_in sa;
849 /* (0) check if this impacts 'hole_external' */
850 if ( (NULL != ch->hole_external) &&
851 (0 == strcasecmp (ch->hole_external,
854 struct LocalAddressList lal;
855 struct sockaddr_in *s4;
857 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
858 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
859 (unsigned int) ch->ext_dns_port,
861 memset (&lal, 0, sizeof (lal));
862 s4 = (struct sockaddr_in *) &lal.addr;
863 s4->sin_family = AF_INET;
864 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)
877 for (unsigned int i=0;i<ch->num_caddrs;i++)
879 const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
881 if (AF_INET != ss->ss_family)
883 have_v4 = GNUNET_YES;
886 if (GNUNET_NO == have_v4)
887 return; /* IPv6-only */
889 /* (2) build address info */
893 sa.sin_family = AF_INET;
895 sa.sin_port = htons (0);
897 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
898 "Detected eternal IP %s, notifying client of external IP (without port)\n",
899 GNUNET_a2s ((const struct sockaddr *) &sa,
901 /* (3) notify client of change */
902 notify_client (is_nat_v4 (v4)
903 ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
904 : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
913 * We got a connection reversal request from another peer.
914 * Notify applicable clients.
916 * @param cls closure with the `struct LocalAddressList`
917 * @param ra IP address of the peer who wants us to connect to it
920 reversal_callback (void *cls,
921 const struct sockaddr_in *ra)
923 struct LocalAddressList *lal = cls;
924 const struct sockaddr_in *l4;
926 GNUNET_assert (AF_INET == lal->af);
927 l4 = (const struct sockaddr_in *) &lal->addr;
928 for (struct ClientHandle *ch = ch_head;
932 struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
933 struct GNUNET_MQ_Envelope *env;
936 /* Check if client is in applicable range for ICMP NAT traversal
937 for this local address */
938 if (! ch->natted_address)
941 for (unsigned int i=0;i<ch->num_caddrs;i++)
943 struct ClientAddress *ca = &ch->caddrs[i];
944 const struct sockaddr_in *c4;
946 if (AF_INET != ca->ss.ss_family)
948 c4 = (const struct sockaddr_in *) &ca->ss;
949 if ( (0 != c4->sin_addr.s_addr) &&
950 (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
958 /* Notify applicable client about connection reversal request */
959 env = GNUNET_MQ_msg_extra (crrm,
960 sizeof (struct sockaddr_in),
961 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
962 GNUNET_memcpy (&crrm[1],
964 sizeof (struct sockaddr_in));
965 GNUNET_MQ_send (ch->mq,
972 * Task we run periodically to scan for network interfaces.
979 struct IfcProcContext ifc_ctx;
982 struct LocalAddressList *lnext;
984 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
990 GNUNET_OS_network_interfaces_list (&ifc_proc,
992 /* remove addresses that disappeared */
993 for (struct LocalAddressList *lal = lal_head;
999 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1003 if ( (pos->af == lal->af) &&
1004 (0 == memcmp (&lal->addr,
1006 (AF_INET == lal->af)
1007 ? sizeof (struct sockaddr_in)
1008 : sizeof (struct sockaddr_in6))) )
1013 if (GNUNET_NO == found)
1015 notify_clients (lal,
1021 /* add addresses that appeared */
1022 have_nat = GNUNET_NO;
1023 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1025 pos = ifc_ctx.lal_head)
1028 if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1029 have_nat = GNUNET_YES;
1030 for (struct LocalAddressList *lal = lal_head;
1034 if ( (pos->af == lal->af) &&
1035 (0 == memcmp (&lal->addr,
1037 (AF_INET == lal->af)
1038 ? sizeof (struct sockaddr_in)
1039 : sizeof (struct sockaddr_in6))) )
1042 GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1045 if (GNUNET_YES == found)
1051 notify_clients (pos,
1053 GNUNET_CONTAINER_DLL_insert (lal_head,
1056 if ( (AF_INET == pos->af) &&
1057 (NULL == pos->hc) &&
1058 (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1060 const struct sockaddr_in *s4
1061 = (const struct sockaddr_in *) &pos->addr;
1063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1064 "Found NATed local address %s, starting NAT server\n",
1065 GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1067 pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1073 GN_nat_status_changed (have_nat);
1078 * Function called whenever our set of external addresses
1079 * as created by `upnpc` changes.
1081 * @param cls closure with our `struct ClientHandle *`
1082 * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1083 * the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1084 * @param addr either the previous or the new public IP address
1085 * @param addrlen actual length of the @a addr
1086 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1089 upnp_addr_change_cb (void *cls,
1091 const struct sockaddr *addr,
1093 enum GNUNET_NAT_StatusCode result)
1095 struct ClientHandle *ch = cls;
1096 enum GNUNET_NAT_AddressClass ac;
1100 case GNUNET_NAT_ERROR_SUCCESS:
1101 GNUNET_assert (NULL != addr);
1103 case GNUNET_NAT_ERROR_UPNPC_FAILED:
1104 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1105 case GNUNET_NAT_ERROR_IPC_FAILURE:
1106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1107 "Running upnpc failed: %d\n",
1110 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1111 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1112 "external-ip binary not found\n");
1114 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1115 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1116 "upnpc binary not found\n");
1118 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1120 "external-ip binary could not be run\n");
1122 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1123 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1124 "upnpc failed to create port mapping\n");
1126 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1128 "Invalid output from upnpc\n");
1130 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132 "Invalid address returned by upnpc\n");
1135 GNUNET_break (0); /* should not be possible */
1138 switch (addr->sa_family)
1141 ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1143 : GNUNET_NAT_AC_EXTERN;
1146 ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1148 : GNUNET_NAT_AC_EXTERN;
1154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1155 "upnp external address %s: %s\n",
1156 add_remove ? "added" : "removed",
1168 * Resolve the `hole_external` name to figure out our
1169 * external address from a manually punched hole. The
1170 * port number has already been parsed, this task is
1171 * responsible for periodically doing a DNS lookup.
1173 * @param ch client handle to act upon
1176 dyndns_lookup (void *cls);
1180 * Our (external) hostname was resolved. Update lists of
1181 * current external IPs (note that DNS may return multiple
1182 * addresses!) and notify client accordingly.
1184 * @param cls the `struct ClientHandle`
1185 * @param addr NULL on error, otherwise result of DNS lookup
1186 * @param addrlen number of bytes in @a addr
1189 process_external_ip (void *cls,
1190 const struct sockaddr *addr,
1193 struct ClientHandle *ch = cls;
1194 struct LocalAddressList *lal;
1195 struct sockaddr_storage ss;
1196 struct sockaddr_in *v4;
1197 struct sockaddr_in6 *v6;
1201 struct LocalAddressList *laln;
1205 = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1208 /* Current iteration is over, remove 'old' IPs now */
1209 for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1212 if (GNUNET_YES == lal->old)
1214 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1217 check_notify_client (lal,
1225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1226 "Got IP `%s' for external address `%s'\n",
1231 /* build sockaddr storage with port number */
1238 switch (addr->sa_family)
1241 v4 = (struct sockaddr_in *) &ss;
1242 v4->sin_port = htons (ch->ext_dns_port);
1245 v6 = (struct sockaddr_in6 *) &ss;
1246 v6->sin6_port = htons (ch->ext_dns_port);
1252 /* See if 'ss' matches any of our known addresses */
1253 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1255 if (GNUNET_NO == lal->old)
1256 continue; /* already processed, skip */
1257 if ( (addr->sa_family == lal->addr.ss_family) &&
1262 /* Address unchanged, remember so we do not remove */
1263 lal->old = GNUNET_NO;
1264 return; /* done here */
1267 /* notify client, and remember IP for later removal! */
1268 lal = GNUNET_new (struct LocalAddressList);
1270 lal->af = ss.ss_family;
1271 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1272 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1275 check_notify_client (lal,
1282 * Resolve the `hole_external` name to figure out our
1283 * external address from a manually punched hole. The
1284 * port number has already been parsed, this task is
1285 * responsible for periodically doing a DNS lookup.
1287 * @param ch client handle to act upon
1290 dyndns_lookup (void *cls)
1292 struct ClientHandle *ch = cls;
1293 struct LocalAddressList *lal;
1295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1296 "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1299 (unsigned int) ch->ext_dns_port);
1300 for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1301 lal->old = GNUNET_YES;
1302 ch->ext_dns_task = NULL;
1303 ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1305 GNUNET_TIME_UNIT_MINUTES,
1306 &process_external_ip,
1312 * Resolve the `hole_external` name to figure out our
1313 * external address from a manually punched hole. The
1314 * given name may be "AUTO" in which case we should use
1315 * the IP address(es) we have from upnpc or other methods.
1316 * The name can also be an IP address, in which case we
1317 * do not need to do DNS resolution. Finally, we also
1318 * need to parse the port number.
1320 * @param ch client handle to act upon
1323 lookup_hole_external (struct ClientHandle *ch)
1327 struct sockaddr_in *s4;
1328 struct LocalAddressList *lal;
1330 port = strrchr (ch->hole_external, ':');
1333 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1334 _("Malformed punched hole specification `%s' (lacks port)\n"),
1338 if ( (1 != sscanf (port + 1,
1343 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1344 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1348 ch->ext_dns_port = (uint16_t) pnum;
1351 lal = GNUNET_new (struct LocalAddressList);
1352 if ('[' == *ch->hole_external)
1354 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1356 s6->sin6_family = AF_INET6;
1357 if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1359 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1360 _("Malformed punched hole specification `%s' (lacks `]')\n"),
1365 ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1366 if (1 != inet_pton (AF_INET6,
1367 ch->hole_external + 1,
1370 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1371 _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1372 ch->hole_external + 1);
1376 s6->sin6_port = htons (ch->ext_dns_port);
1378 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1379 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1382 check_notify_client (lal,
1388 s4 = (struct sockaddr_in *) &lal->addr;
1389 s4->sin_family = AF_INET;
1390 if (1 == inet_pton (AF_INET,
1394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1395 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1398 (unsigned int) ch->ext_dns_port);
1399 s4->sin_port = htons (ch->ext_dns_port);
1401 lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1402 GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1405 check_notify_client (lal,
1410 if (0 == strcasecmp (ch->hole_external,
1413 /* handled in #notify_client_external_ipv4_change() */
1417 /* got a DNS name, trigger lookup! */
1420 = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1426 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1427 * We remember the client for updates upon future NAT events.
1429 * @param cls client who sent the message
1430 * @param message the message received
1433 handle_register (void *cls,
1434 const struct GNUNET_NAT_RegisterMessage *message)
1436 struct ClientHandle *ch = cls;
1440 if ( (0 != ch->proto) ||
1441 (NULL != ch->caddrs) )
1443 /* double registration not allowed */
1445 GNUNET_SERVICE_client_drop (ch->client);
1448 ch->flags = message->flags;
1449 ch->proto = message->proto;
1450 ch->num_caddrs = ntohs (message->num_addrs);
1451 ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1452 struct ClientAddress);
1453 left = ntohs (message->header.size) - sizeof (*message);
1454 off = (const char *) &message[1];
1455 for (unsigned int i=0;i<ch->num_caddrs;i++)
1457 const struct sockaddr *sa = (const struct sockaddr *) off;
1462 if (sizeof (sa_family_t) > left)
1465 GNUNET_SERVICE_client_drop (ch->client);
1469 switch (sa->sa_family)
1473 struct sockaddr_in s4;
1477 sizeof (struct sockaddr_in));
1478 alen = sizeof (struct sockaddr_in);
1479 if (is_nat_v4 (&s4.sin_addr))
1480 is_nat = GNUNET_YES;
1481 port = ntohs (s4.sin_port);
1486 struct sockaddr_in6 s6;
1490 sizeof (struct sockaddr_in6));
1491 alen = sizeof (struct sockaddr_in6);
1492 if (is_nat_v6 (&s6.sin6_addr))
1493 is_nat = GNUNET_YES;
1494 port = ntohs (s6.sin6_port);
1499 alen = sizeof (struct sockaddr_un);
1505 GNUNET_SERVICE_client_drop (ch->client);
1509 GNUNET_assert (alen <= left);
1510 GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1511 GNUNET_memcpy (&ch->caddrs[i].ss,
1515 /* If applicable, try UPNPC NAT punching */
1518 ( (IPPROTO_TCP == ch->proto) ||
1519 (IPPROTO_UDP == ch->proto) ) )
1521 ch->natted_address = GNUNET_YES;
1523 = GNUNET_NAT_mini_map_start (port,
1524 IPPROTO_TCP == ch->proto,
1525 &upnp_addr_change_cb,
1533 = GNUNET_strndup (off,
1534 ntohs (message->str_len));
1535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1536 "Received REGISTER message from client for subsystem `%s'\n",
1539 GNUNET_CONFIGURATION_get_value_string (cfg,
1542 &ch->hole_external))
1543 lookup_hole_external (ch);
1545 /* Actually send IP address list to client */
1546 for (struct LocalAddressList *lal = lal_head;
1550 check_notify_client (lal,
1554 /* Also consider IPv4 determined by `external-ip` */
1555 ch->external_monitor
1556 = GN_external_ipv4_monitor_start (¬ify_client_external_ipv4_change,
1558 GNUNET_SERVICE_client_continue (ch->client);
1563 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1566 * @param cls client who sent the message
1567 * @param message the message received
1568 * @return #GNUNET_OK if message is well-formed
1571 check_stun (void *cls,
1572 const struct GNUNET_NAT_HandleStunMessage *message)
1574 size_t sa_len = ntohs (message->sender_addr_size);
1575 size_t expect = sa_len + ntohs (message->payload_size);
1577 if (ntohs (message->header.size) - sizeof (*message) != expect)
1580 return GNUNET_SYSERR;
1582 if (sa_len < sizeof (sa_family_t))
1585 return GNUNET_SYSERR;
1592 * Notify all clients about our external IP address
1593 * as reported by the STUN server.
1595 * @param ip the external IP
1596 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1599 notify_clients_stun_change (const struct sockaddr_in *ip,
1602 for (struct ClientHandle *ch = ch_head;
1606 struct sockaddr_in v4;
1607 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1608 struct GNUNET_MQ_Envelope *env;
1610 if (! ch->natted_address)
1613 v4.sin_port = htons (0);
1614 env = GNUNET_MQ_msg_extra (msg,
1616 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1617 msg->add_remove = htonl ((int32_t) add);
1618 msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1619 GNUNET_NAT_AC_GLOBAL);
1620 GNUNET_memcpy (&msg[1],
1623 GNUNET_MQ_send (ch->mq,
1630 * Function to be called when we decide that an
1631 * external IP address as told to us by a STUN
1632 * server has gone stale.
1634 * @param cls the `struct StunExternalIP` to drop
1637 stun_ip_timeout (void *cls)
1639 struct StunExternalIP *se = cls;
1641 se->timeout_task = NULL;
1642 notify_clients_stun_change (&se->external_addr,
1644 GNUNET_CONTAINER_DLL_remove (se_head,
1652 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1655 * @param cls client who sent the message
1656 * @param message the message received
1659 handle_stun (void *cls,
1660 const struct GNUNET_NAT_HandleStunMessage *message)
1662 struct ClientHandle *ch = cls;
1663 const char *buf = (const char *) &message[1];
1664 const struct sockaddr *sa;
1665 const void *payload;
1667 size_t payload_size;
1668 struct sockaddr_in external_addr;
1670 sa_len = ntohs (message->sender_addr_size);
1671 payload_size = ntohs (message->payload_size);
1672 sa = (const struct sockaddr *) &buf[0];
1673 payload = (const struct sockaddr *) &buf[sa_len];
1674 switch (sa->sa_family)
1677 if (sa_len != sizeof (struct sockaddr_in))
1680 GNUNET_SERVICE_client_drop (ch->client);
1685 if (sa_len != sizeof (struct sockaddr_in6))
1688 GNUNET_SERVICE_client_drop (ch->client);
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1694 "Received HANDLE_STUN message from client\n");
1696 GNUNET_NAT_stun_handle_packet_ (payload,
1700 /* We now know that a server at "sa" claims that
1701 we are visible at IP "external_addr".
1703 We should (for some fixed period of time) tell
1704 all of our clients that listen to a NAT'ed address
1705 that they might want to consider the given 'external_ip'
1706 as their public IP address (this includes TCP and UDP
1707 clients, even if only UDP sends STUN requests).
1709 If we do not get a renewal, the "external_addr" should be
1710 removed again. The timeout frequency should be configurable
1711 (with a sane default), so that the UDP plugin can tell how
1712 often to re-request STUN.
1714 struct StunExternalIP *se;
1716 /* Check if we had a prior response from this STUN server */
1717 for (se = se_head; NULL != se; se = se->next)
1719 if ( (se->stun_server_addr_len != sa_len) ||
1721 &se->stun_server_addr,
1723 continue; /* different STUN server */
1724 if (0 != memcmp (&external_addr,
1726 sizeof (struct sockaddr_in)))
1728 /* external IP changed, update! */
1729 notify_clients_stun_change (&se->external_addr,
1731 se->external_addr = external_addr;
1732 notify_clients_stun_change (&se->external_addr,
1735 /* update timeout */
1736 GNUNET_SCHEDULER_cancel (se->timeout_task);
1738 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1743 /* STUN server is completely new, create fresh entry */
1744 se = GNUNET_new (struct StunExternalIP);
1745 se->external_addr = external_addr;
1746 GNUNET_memcpy (&se->stun_server_addr,
1749 se->stun_server_addr_len = sa_len;
1750 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1753 GNUNET_CONTAINER_DLL_insert (se_head,
1756 notify_clients_stun_change (&se->external_addr,
1759 GNUNET_SERVICE_client_continue (ch->client);
1765 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1768 * @param cls client who sent the message
1769 * @param message the message received
1770 * @return #GNUNET_OK if message is well-formed
1773 check_request_connection_reversal (void *cls,
1774 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1778 expect = ntohs (message->local_addr_size)
1779 + ntohs (message->remote_addr_size);
1780 if (ntohs (message->header.size) - sizeof (*message) != expect)
1783 return GNUNET_SYSERR;
1790 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1791 * message from client.
1793 * @param cls client who sent the message
1794 * @param message the message received
1797 handle_request_connection_reversal (void *cls,
1798 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1800 struct ClientHandle *ch = cls;
1801 const char *buf = (const char *) &message[1];
1802 size_t local_sa_len = ntohs (message->local_addr_size);
1803 size_t remote_sa_len = ntohs (message->remote_addr_size);
1804 struct sockaddr_in l4;
1805 struct sockaddr_in r4;
1808 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1809 "Received REQUEST CONNECTION REVERSAL message from client\n");
1810 if (local_sa_len != sizeof (struct sockaddr_in))
1812 GNUNET_break_op (0);
1813 GNUNET_SERVICE_client_drop (ch->client);
1816 if (remote_sa_len != sizeof (struct sockaddr_in))
1818 GNUNET_break_op (0);
1819 GNUNET_SERVICE_client_drop (ch->client);
1824 sizeof (struct sockaddr_in));
1825 GNUNET_break_op (AF_INET == l4.sin_family);
1826 buf += sizeof (struct sockaddr_in);
1829 sizeof (struct sockaddr_in));
1830 GNUNET_break_op (AF_INET == r4.sin_family);
1831 ret = GN_request_connection_reversal (&l4.sin_addr,
1832 ntohs (l4.sin_port),
1834 if (GNUNET_OK != ret)
1835 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1836 _("Connection reversal request failed\n"));
1837 GNUNET_SERVICE_client_continue (ch->client);
1842 * Task run during shutdown.
1847 shutdown_task (void *cls)
1849 struct StunExternalIP *se;
1851 while (NULL != (se = se_head))
1853 GNUNET_CONTAINER_DLL_remove (se_head,
1856 GNUNET_SCHEDULER_cancel (se->timeout_task);
1859 GN_nat_status_changed (GNUNET_NO);
1860 if (NULL != scan_task)
1862 GNUNET_SCHEDULER_cancel (scan_task);
1867 GNUNET_STATISTICS_destroy (stats,
1876 * Setup NAT service.
1878 * @param cls closure
1879 * @param c configuration to use
1880 * @param service the initialized service
1884 const struct GNUNET_CONFIGURATION_Handle *c,
1885 struct GNUNET_SERVICE_Handle *service)
1889 GNUNET_CONFIGURATION_get_value_time (cfg,
1892 &stun_stale_timeout))
1893 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1895 /* Check for UPnP */
1897 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1900 if (GNUNET_YES == enable_upnp)
1902 /* check if it works */
1903 if (GNUNET_SYSERR ==
1904 GNUNET_OS_check_helper_binary ("upnpc",
1908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1909 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1910 enable_upnp = GNUNET_SYSERR;
1914 GNUNET_CONFIGURATION_get_value_time (cfg,
1918 dyndns_frequency = DYNDNS_FREQUENCY;
1920 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1922 stats = GNUNET_STATISTICS_create ("nat",
1924 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1930 * Callback called when a client connects to the service.
1932 * @param cls closure for the service
1933 * @param c the new client that connected to the service
1934 * @param mq the message queue used to send messages to the client
1935 * @return a `struct ClientHandle`
1938 client_connect_cb (void *cls,
1939 struct GNUNET_SERVICE_Client *c,
1940 struct GNUNET_MQ_Handle *mq)
1942 struct ClientHandle *ch;
1944 ch = GNUNET_new (struct ClientHandle);
1947 GNUNET_CONTAINER_DLL_insert (ch_head,
1955 * Callback called when a client disconnected from the service
1957 * @param cls closure for the service
1958 * @param c the client that disconnected
1959 * @param internal_cls a `struct ClientHandle *`
1962 client_disconnect_cb (void *cls,
1963 struct GNUNET_SERVICE_Client *c,
1966 struct ClientHandle *ch = internal_cls;
1967 struct LocalAddressList *lal;
1969 GNUNET_CONTAINER_DLL_remove (ch_head,
1972 for (unsigned int i=0;i<ch->num_caddrs;i++)
1974 if (NULL != ch->caddrs[i].mh)
1976 GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
1977 ch->caddrs[i].mh = NULL;
1980 GNUNET_free_non_null (ch->caddrs);
1981 while (NULL != (lal = ch->ext_addr_head))
1983 GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1988 if (NULL != ch->ext_dns_task)
1990 GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
1991 ch->ext_dns_task = NULL;
1993 if (NULL != ch->external_monitor)
1995 GN_external_ipv4_monitor_stop (ch->external_monitor);
1996 ch->external_monitor = NULL;
1998 if (NULL != ch->ext_dns)
2000 GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2003 GNUNET_free_non_null (ch->hole_external);
2004 GNUNET_free_non_null (ch->section_name);
2010 * Define "main" method using service macro.
2014 GNUNET_SERVICE_OPTION_NONE,
2017 &client_disconnect_cb,
2019 GNUNET_MQ_hd_var_size (register,
2020 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2021 struct GNUNET_NAT_RegisterMessage,
2023 GNUNET_MQ_hd_var_size (stun,
2024 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2025 struct GNUNET_NAT_HandleStunMessage,
2027 GNUNET_MQ_hd_var_size (request_connection_reversal,
2028 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2029 struct GNUNET_NAT_RequestConnectionReversalMessage,
2031 GNUNET_MQ_handler_end ());
2034 #if defined(LINUX) && defined(__GLIBC__)
2038 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2040 void __attribute__ ((constructor))
2041 GNUNET_ARM_memory_init ()
2043 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2044 mallopt (M_TOP_PAD, 1 * 1024);
2049 /* end of gnunet-service-nat.c */