2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 * @file nat/gnunet-service-nat.c
23 * @brief network address translation traversal service
24 * @author Christian Grothoff
26 * The purpose of this service is to enable transports to
27 * traverse NAT routers, by providing traversal options and
28 * knowledge about the local network topology.
31 * - implement UPnPC/PMP-based NAT traversal
32 * - implement autoconfig
33 * - implement NEW logic for external IP detection
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_nat_service.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)
62 * Internal data structure we track for each of our clients.
70 struct ClientHandle *next;
75 struct ClientHandle *prev;
78 * Underlying handle for this client with the service.
80 struct GNUNET_SERVICE_Client *client;
83 * Message queue for communicating with the client.
85 struct GNUNET_MQ_Handle *mq;
88 * Array of addresses used by the service.
90 struct sockaddr **addrs;
93 * What does this client care about?
95 enum GNUNET_NAT_RegisterFlags flags;
98 * Is any of the @e addrs in a reserved subnet for NAT?
103 * Port we would like as we are configured to use this one for
104 * advertising (in addition to the one we are binding to).
109 * Number of addresses that this service is bound to.
114 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
122 * List of local addresses this system has.
124 struct LocalAddressList
127 * This is a linked list.
129 struct LocalAddressList *next;
134 struct LocalAddressList *prev;
137 * The address itself (i.e. `struct sockaddr_in` or `struct
138 * sockaddr_in6`, in the respective byte order).
140 struct sockaddr_storage addr;
148 * What type of address is this?
150 enum GNUNET_NAT_AddressClass ac;
156 * External IP address as given to us via some STUN server.
158 struct StunExternalIP
163 struct StunExternalIP *next;
168 struct StunExternalIP *prev;
171 * Task we run to remove this entry when it is stale.
173 struct GNUNET_SCHEDULER_Task *timeout_task;
176 * Our external IP address as reported by the
179 struct sockaddr_in external_addr;
182 * Address of the reporting STUN server. Used to
183 * detect when a STUN server changes its opinion
184 * to more quickly remove stale results.
186 struct sockaddr_storage stun_server_addr;
189 * Number of bytes used in @e stun_server_addr.
191 size_t stun_server_addr_len;
196 * Context for autoconfiguration operations.
198 struct AutoconfigContext
203 struct AutoconfigContext *prev;
208 struct AutoconfigContext *next;
211 * Which client asked the question.
213 struct ClientHandle *ch;
216 * Configuration we are creating.
218 struct GNUNET_CONFIGURATION_Handle *c;
221 * Timeout task to force termination.
223 struct GNUNET_SCHEDULER_Task *timeout_task;
226 * What type of system are we on?
231 * Handle to activity to probe for our external IP.
233 struct GNUNET_NAT_ExternalHandle *probe_external;
236 * #GNUNET_YES if upnpc should be used,
237 * #GNUNET_NO if upnpc should not be used,
238 * #GNUNET_SYSERR if we should simply not change the option.
243 * Status code to return to the client.
245 enum GNUNET_NAT_StatusCode status_code;
248 * NAT type to return to the client.
250 enum GNUNET_NAT_Type type;
255 * DLL of our autoconfiguration operations.
257 static struct AutoconfigContext *ac_head;
260 * DLL of our autoconfiguration operations.
262 static struct AutoconfigContext *ac_tail;
265 * Timeout to use when STUN data is considered stale.
267 static struct GNUNET_TIME_Relative stun_stale_timeout;
270 * Handle to our current configuration.
272 static const struct GNUNET_CONFIGURATION_Handle *cfg;
275 * Handle to the statistics service.
277 static struct GNUNET_STATISTICS_Handle *stats;
280 * Task scheduled to periodically scan our network interfaces.
282 static struct GNUNET_SCHEDULER_Task *scan_task;
285 * Head of client DLL.
287 static struct ClientHandle *ch_head;
290 * Tail of client DLL.
292 static struct ClientHandle *ch_tail;
295 * Head of DLL of local addresses.
297 static struct LocalAddressList *lal_head;
300 * Tail of DLL of local addresses.
302 static struct LocalAddressList *lal_tail;
307 static struct StunExternalIP *se_head;
312 static struct StunExternalIP *se_tail;
315 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
316 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
318 static int enable_upnp;
322 * Free the DLL starting at #lal_head.
327 struct LocalAddressList *lal;
329 while (NULL != (lal = lal_head))
331 GNUNET_CONTAINER_DLL_remove (lal_head,
340 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
343 * @param cls client who sent the message
344 * @param message the message received
345 * @return #GNUNET_OK if message is well-formed
348 check_register (void *cls,
349 const struct GNUNET_NAT_RegisterMessage *message)
351 uint16_t num_addrs = ntohs (message->num_addrs);
352 const char *off = (const char *) &message[1];
353 size_t left = ntohs (message->header.size) - sizeof (*message);
355 for (unsigned int i=0;i<num_addrs;i++)
358 const struct sockaddr *sa = (const struct sockaddr *) off;
360 if (sizeof (sa_family_t) > left)
363 return GNUNET_SYSERR;
365 switch (sa->sa_family)
368 alen = sizeof (struct sockaddr_in);
371 alen = sizeof (struct sockaddr_in6);
375 alen = sizeof (struct sockaddr_un);
380 return GNUNET_SYSERR;
385 return GNUNET_SYSERR;
393 * Check if @a ip is in @a network with @a bits netmask.
395 * @param network to test
396 * @param ip IP address to test
397 * @param bits bitmask for the network
398 * @return #GNUNET_YES if @a ip is in @a network
401 match_ipv4 (const char *network,
402 const struct in_addr *ip,
411 GNUNET_assert (1 == inet_pton (AF_INET,
414 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
419 * Check if @a ip is in @a network with @a bits netmask.
421 * @param network to test
422 * @param ip IP address to test
423 * @param bits bitmask for the network
424 * @return #GNUNET_YES if @a ip is in @a network
427 match_ipv6 (const char *network,
428 const struct in6_addr *ip,
432 struct in6_addr mask;
437 GNUNET_assert (1 == inet_pton (AF_INET6,
440 memset (&mask, 0, sizeof (mask));
441 if (0 == memcmp (&mask,
448 mask.s6_addr[off++] = 0xFF;
453 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
456 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
457 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
458 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
465 * Test if the given IPv4 address is in a known range
466 * for private networks.
468 * @param ip address to test
469 * @return #GNUNET_YES if @a ip is in a NAT range
472 is_nat_v4 (const struct in_addr *ip)
475 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
476 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
477 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
478 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
479 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
484 * Test if the given IPv6 address is in a known range
485 * for private networks.
487 * @param ip address to test
488 * @return #GNUNET_YES if @a ip is in a NAT range
491 is_nat_v6 (const struct in6_addr *ip)
494 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
495 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
496 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
501 * Closure for #ifc_proc.
503 struct IfcProcContext
507 * Head of DLL of local addresses.
509 struct LocalAddressList *lal_head;
512 * Tail of DLL of local addresses.
514 struct LocalAddressList *lal_tail;
520 * Callback function invoked for each interface found. Adds them
521 * to our new address list.
523 * @param cls a `struct IfcProcContext *`
524 * @param name name of the interface (can be NULL for unknown)
525 * @param isDefault is this presumably the default interface
526 * @param addr address of this interface (can be NULL for unknown or unassigned)
527 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
528 * @param netmask the network mask (can be NULL for unknown or unassigned)
529 * @param addrlen length of the address
530 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
536 const struct sockaddr *addr,
537 const struct sockaddr *broadcast_addr,
538 const struct sockaddr *netmask,
541 struct IfcProcContext *ifc_ctx = cls;
542 struct LocalAddressList *lal;
544 const struct in_addr *ip4;
545 const struct in6_addr *ip6;
546 enum GNUNET_NAT_AddressClass ac;
548 switch (addr->sa_family)
551 alen = sizeof (struct sockaddr_in);
552 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
553 if (match_ipv4 ("127.0.0.0", ip4, 8))
554 ac = GNUNET_NAT_AC_LOOPBACK;
555 else if (is_nat_v4 (ip4))
556 ac = GNUNET_NAT_AC_LAN;
558 ac = GNUNET_NAT_AC_GLOBAL;
561 alen = sizeof (struct sockaddr_in6);
562 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
563 if (match_ipv6 ("::1", ip6, 128))
564 ac = GNUNET_NAT_AC_LOOPBACK;
565 else if (is_nat_v6 (ip6))
566 ac = GNUNET_NAT_AC_LAN;
568 ac = GNUNET_NAT_AC_GLOBAL;
569 if ( (ip6->s6_addr[11] == 0xFF) &&
570 (ip6->s6_addr[12] == 0xFE) )
572 /* contains a MAC, be extra careful! */
573 ac |= GNUNET_NAT_AC_PRIVATE;
585 lal = GNUNET_malloc (sizeof (*lal));
586 lal->af = addr->sa_family;
588 GNUNET_memcpy (&lal->addr,
591 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
599 * Notify client about a change in the list of addresses this peer
602 * @param delta the entry in the list that changed
603 * @param ch client to contact
604 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
605 * @param addr the address that changed
606 * @param addr_len number of bytes in @a addr
609 notify_client (struct LocalAddressList *delta,
610 struct ClientHandle *ch,
615 struct GNUNET_MQ_Envelope *env;
616 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
618 env = GNUNET_MQ_msg_extra (msg,
620 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
621 msg->add_remove = htonl (add);
622 msg->addr_class = htonl (delta->ac);
623 GNUNET_memcpy (&msg[1],
626 GNUNET_MQ_send (ch->mq,
632 * Check if we should bother to notify this client about this
633 * address change, and if so, do it.
635 * @param delta the entry in the list that changed
636 * @param ch client to check
637 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
640 check_notify_client (struct LocalAddressList *delta,
641 struct ClientHandle *ch,
645 struct sockaddr_in v4;
646 struct sockaddr_in6 v6;
648 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
653 alen = sizeof (struct sockaddr_in);
657 for (unsigned int i=0;i<ch->num_addrs;i++)
659 const struct sockaddr_in *c4;
661 if (AF_INET != ch->addrs[i]->sa_family)
662 return; /* IPv4 not relevant */
663 c4 = (const struct sockaddr_in *) ch->addrs[i];
664 v4.sin_port = c4->sin_port;
665 notify_client (delta,
673 alen = sizeof (struct sockaddr_in6);
677 for (unsigned int i=0;i<ch->num_addrs;i++)
679 const struct sockaddr_in6 *c6;
681 if (AF_INET6 != ch->addrs[i]->sa_family)
682 return; /* IPv4 not relevant */
683 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
684 v6.sin6_port = c6->sin6_port;
685 notify_client (delta,
700 * Notify all clients about a change in the list
701 * of addresses this peer has.
703 * @param delta the entry in the list that changed
704 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
707 notify_clients (struct LocalAddressList *delta,
710 for (struct ClientHandle *ch = ch_head;
713 check_notify_client (delta,
720 * Task we run periodically to scan for network interfaces.
727 struct IfcProcContext ifc_ctx;
730 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
736 GNUNET_OS_network_interfaces_list (&ifc_proc,
738 /* remove addresses that disappeared */
739 for (struct LocalAddressList *lal = lal_head;
744 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
748 if ( (pos->af == lal->af) &&
749 (0 == memcmp (&lal->addr,
752 ? sizeof (struct sockaddr_in)
753 : sizeof (struct sockaddr_in6))) )
756 if (GNUNET_NO == found)
761 /* add addresses that appeared */
762 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
767 for (struct LocalAddressList *lal = lal_head;
771 if ( (pos->af == lal->af) &&
772 (0 == memcmp (&lal->addr,
775 ? sizeof (struct sockaddr_in)
776 : sizeof (struct sockaddr_in6))) )
779 if (GNUNET_NO == found)
785 lal_head = ifc_ctx.lal_head;
786 lal_tail = ifc_ctx.lal_tail;
791 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
792 * We remember the client for updates upon future NAT events.
794 * @param cls client who sent the message
795 * @param message the message received
798 handle_register (void *cls,
799 const struct GNUNET_NAT_RegisterMessage *message)
801 struct ClientHandle *ch = cls;
805 if ( (0 != ch->proto) ||
806 (NULL != ch->addrs) )
808 /* double registration not allowed */
810 GNUNET_SERVICE_client_drop (ch->client);
813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
814 "Received REGISTER message from client\n");
815 ch->flags = message->flags;
816 ch->proto = message->proto;
817 ch->adv_port = ntohs (message->adv_port);
818 ch->num_addrs = ntohs (message->num_addrs);
819 ch->addrs = GNUNET_new_array (ch->num_addrs,
821 left = ntohs (message->header.size) - sizeof (*message);
822 off = (const char *) &message[1];
823 for (unsigned int i=0;i<ch->num_addrs;i++)
826 const struct sockaddr *sa = (const struct sockaddr *) off;
828 if (sizeof (sa_family_t) > left)
831 GNUNET_SERVICE_client_drop (ch->client);
834 switch (sa->sa_family)
838 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
840 alen = sizeof (struct sockaddr_in);
841 if (is_nat_v4 (&s4->sin_addr))
842 ch->natted_address = GNUNET_YES;
847 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
849 alen = sizeof (struct sockaddr_in6);
850 if (is_nat_v6 (&s6->sin6_addr))
851 ch->natted_address = GNUNET_YES;
856 alen = sizeof (struct sockaddr_un);
861 GNUNET_SERVICE_client_drop (ch->client);
864 GNUNET_assert (alen <= left);
865 ch->addrs[i] = GNUNET_malloc (alen);
866 GNUNET_memcpy (ch->addrs[i],
871 /* Actually send IP address list to client */
872 for (struct LocalAddressList *lal = lal_head;
876 check_notify_client (lal,
880 GNUNET_SERVICE_client_continue (ch->client);
885 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
888 * @param cls client who sent the message
889 * @param message the message received
890 * @return #GNUNET_OK if message is well-formed
893 check_stun (void *cls,
894 const struct GNUNET_NAT_HandleStunMessage *message)
896 size_t sa_len = ntohs (message->sender_addr_size);
897 size_t expect = sa_len + ntohs (message->payload_size);
899 if (ntohs (message->header.size) - sizeof (*message) != expect)
902 return GNUNET_SYSERR;
904 if (sa_len < sizeof (sa_family_t))
907 return GNUNET_SYSERR;
914 * Notify all clients about our external IP address
915 * as reported by the STUN server.
917 * @param ip the external IP
918 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
921 notify_clients_stun_change (const struct sockaddr_in *ip,
924 for (struct ClientHandle *ch = ch_head;
928 struct sockaddr_in v4;
929 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
930 struct GNUNET_MQ_Envelope *env;
932 if (! ch->natted_address)
935 v4.sin_port = htons (ch->adv_port);
936 env = GNUNET_MQ_msg_extra (msg,
938 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
939 msg->add_remove = htonl ((int32_t) add);
940 msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN |
941 GNUNET_NAT_AC_GLOBAL);
942 GNUNET_memcpy (&msg[1],
945 GNUNET_MQ_send (ch->mq,
952 * Function to be called when we decide that an
953 * external IP address as told to us by a STUN
954 * server has gone stale.
956 * @param cls the `struct StunExternalIP` to drop
959 stun_ip_timeout (void *cls)
961 struct StunExternalIP *se = cls;
963 se->timeout_task = NULL;
964 notify_clients_stun_change (&se->external_addr,
966 GNUNET_CONTAINER_DLL_remove (se_head,
974 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
977 * @param cls client who sent the message
978 * @param message the message received
981 handle_stun (void *cls,
982 const struct GNUNET_NAT_HandleStunMessage *message)
984 struct ClientHandle *ch = cls;
985 const char *buf = (const char *) &message[1];
986 const struct sockaddr *sa;
990 struct sockaddr_in external_addr;
992 sa_len = ntohs (message->sender_addr_size);
993 payload_size = ntohs (message->payload_size);
994 sa = (const struct sockaddr *) &buf[0];
995 payload = (const struct sockaddr *) &buf[sa_len];
996 switch (sa->sa_family)
999 if (sa_len != sizeof (struct sockaddr_in))
1002 GNUNET_SERVICE_client_drop (ch->client);
1007 if (sa_len != sizeof (struct sockaddr_in6))
1010 GNUNET_SERVICE_client_drop (ch->client);
1015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1016 "Received HANDLE_STUN message from client\n");
1018 GNUNET_NAT_stun_handle_packet_ (payload,
1022 /* We now know that a server at "sa" claims that
1023 we are visible at IP "external_addr".
1025 We should (for some fixed period of time) tell
1026 all of our clients that listen to a NAT'ed address
1027 that they might want to consider the given 'external_ip'
1028 as their public IP address (this includes TCP and UDP
1029 clients, even if only UDP sends STUN requests).
1031 If we do not get a renewal, the "external_addr" should be
1032 removed again. The timeout frequency should be configurable
1033 (with a sane default), so that the UDP plugin can tell how
1034 often to re-request STUN.
1036 struct StunExternalIP *se;
1038 /* Check if we had a prior response from this STUN server */
1039 for (se = se_head; NULL != se; se = se->next)
1041 if ( (se->stun_server_addr_len != sa_len) ||
1043 &se->stun_server_addr,
1045 continue; /* different STUN server */
1046 if (0 != memcmp (&external_addr,
1048 sizeof (struct sockaddr_in)))
1050 /* external IP changed, update! */
1051 notify_clients_stun_change (&se->external_addr,
1053 se->external_addr = external_addr;
1054 notify_clients_stun_change (&se->external_addr,
1057 /* update timeout */
1058 GNUNET_SCHEDULER_cancel (se->timeout_task);
1060 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1065 /* STUN server is completely new, create fresh entry */
1066 se = GNUNET_new (struct StunExternalIP);
1067 se->external_addr = external_addr;
1068 GNUNET_memcpy (&se->stun_server_addr,
1071 se->stun_server_addr_len = sa_len;
1072 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1075 GNUNET_CONTAINER_DLL_insert (se_head,
1078 notify_clients_stun_change (&se->external_addr,
1081 GNUNET_SERVICE_client_continue (ch->client);
1087 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1090 * @param cls client who sent the message
1091 * @param message the message received
1092 * @return #GNUNET_OK if message is well-formed
1095 check_request_connection_reversal (void *cls,
1096 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1100 expect = ntohs (message->local_addr_size)
1101 + ntohs (message->remote_addr_size);
1102 if (ntohs (message->header.size) - sizeof (*message) != expect)
1105 return GNUNET_SYSERR;
1112 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1113 * message from client.
1115 * @param cls client who sent the message
1116 * @param message the message received
1119 handle_request_connection_reversal (void *cls,
1120 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1122 struct ClientHandle *ch = cls;
1123 const char *buf = (const char *) &message[1];
1124 size_t local_sa_len = ntohs (message->local_addr_size);
1125 size_t remote_sa_len = ntohs (message->remote_addr_size);
1126 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1127 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1128 const struct sockaddr_in *l4 = NULL;
1129 const struct sockaddr_in *r4;
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "Received REQUEST CONNECTION REVERSAL message from client\n");
1134 switch (local_sa->sa_family)
1137 if (local_sa_len != sizeof (struct sockaddr_in))
1140 GNUNET_SERVICE_client_drop (ch->client);
1143 l4 = (const struct sockaddr_in *) local_sa;
1146 if (local_sa_len != sizeof (struct sockaddr_in6))
1149 GNUNET_SERVICE_client_drop (ch->client);
1152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1153 _("Connection reversal for IPv6 not supported yet\n"));
1154 ret = GNUNET_SYSERR;
1158 GNUNET_SERVICE_client_drop (ch->client);
1161 switch (remote_sa->sa_family)
1164 if (remote_sa_len != sizeof (struct sockaddr_in))
1167 GNUNET_SERVICE_client_drop (ch->client);
1170 r4 = (const struct sockaddr_in *) remote_sa;
1171 ret = GN_request_connection_reversal (&l4->sin_addr,
1172 ntohs (l4->sin_port),
1176 if (remote_sa_len != sizeof (struct sockaddr_in6))
1179 GNUNET_SERVICE_client_drop (ch->client);
1182 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1183 _("Connection reversal for IPv6 not supported yet\n"));
1184 ret = GNUNET_SYSERR;
1188 GNUNET_SERVICE_client_drop (ch->client);
1191 if (GNUNET_OK != ret)
1192 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1193 _("Connection reversal request failed\n"));
1194 GNUNET_SERVICE_client_continue (ch->client);
1199 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1202 * @param cls client who sent the message
1203 * @param message the message received
1204 * @return #GNUNET_OK if message is well-formed
1207 check_autoconfig_request (void *cls,
1208 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1210 return GNUNET_OK; /* checked later */
1215 * Stop all pending activities with respect to the @a ac
1217 * @param ac autoconfiguration to terminate activities for
1220 terminate_ac_activities (struct AutoconfigContext *ac)
1222 if (NULL != ac->probe_external)
1224 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1225 ac->probe_external = NULL;
1227 if (NULL != ac->timeout_task)
1229 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1230 ac->timeout_task = NULL;
1236 * Finish handling the autoconfiguration request and send
1237 * the response to the client.
1239 * @param cls the `struct AutoconfigContext` to conclude
1242 conclude_autoconfig_request (void *cls)
1244 struct AutoconfigContext *ac = cls;
1245 struct ClientHandle *ch = ac->ch;
1246 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1247 struct GNUNET_MQ_Envelope *env;
1251 ac->timeout_task = NULL;
1252 terminate_ac_activities (ac);
1254 /* Send back response */
1255 buf = GNUNET_CONFIGURATION_serialize (ac->c,
1257 env = GNUNET_MQ_msg_extra (arm,
1259 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1260 arm->status_code = htonl ((uint32_t) ac->status_code);
1261 arm->type = htonl ((uint32_t) ac->type);
1262 GNUNET_memcpy (&arm[1],
1266 GNUNET_MQ_send (ch->mq,
1270 GNUNET_free (ac->system_type);
1271 GNUNET_CONFIGURATION_destroy (ac->c);
1272 GNUNET_CONTAINER_DLL_remove (ac_head,
1276 GNUNET_SERVICE_client_continue (ch->client);
1281 * Check if all autoconfiguration operations have concluded,
1282 * and if they have, send the result back to the client.
1284 * @param ac autoconfiguation context to check
1287 check_autoconfig_finished (struct AutoconfigContext *ac)
1289 if (NULL != ac->probe_external)
1291 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1293 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1299 * Update ENABLE_UPNPC configuration option.
1301 * @param ac autoconfiguration to update
1304 update_enable_upnpc_option (struct AutoconfigContext *ac)
1306 switch (ac->enable_upnpc)
1309 GNUNET_CONFIGURATION_set_value_string (ac->c,
1315 GNUNET_CONFIGURATION_set_value_string (ac->c,
1321 /* We are unsure, do not change option */
1328 * Handle result from external IP address probe during
1329 * autoconfiguration.
1331 * @param cls our `struct AutoconfigContext`
1332 * @param addr the address, NULL on errors
1333 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1336 auto_external_result_cb (void *cls,
1337 const struct in_addr *addr,
1338 enum GNUNET_NAT_StatusCode result)
1340 struct AutoconfigContext *ac = cls;
1342 ac->probe_external = NULL;
1345 case GNUNET_NAT_ERROR_SUCCESS:
1346 ac->enable_upnpc = GNUNET_YES;
1348 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1349 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1350 case GNUNET_NAT_ERROR_IPC_FAILURE:
1351 ac->enable_upnpc = GNUNET_NO; /* did not work */
1354 GNUNET_break (0); /* unexpected */
1355 ac->enable_upnpc = GNUNET_SYSERR;
1358 update_enable_upnpc_option (ac);
1359 check_autoconfig_finished (ac);
1364 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1367 * @param cls client who sent the message
1368 * @param message the message received
1371 handle_autoconfig_request (void *cls,
1372 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1374 struct ClientHandle *ch = cls;
1375 size_t left = ntohs (message->header.size) - sizeof (*message);
1376 struct LocalAddressList *lal;
1377 struct AutoconfigContext *ac;
1379 ac = GNUNET_new (struct AutoconfigContext);
1381 ac->c = GNUNET_CONFIGURATION_create ();
1383 GNUNET_CONFIGURATION_deserialize (ac->c,
1384 (const char *) &message[1],
1389 GNUNET_SERVICE_client_drop (ch->client);
1390 GNUNET_CONFIGURATION_destroy (ac->c);
1394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1395 "Received REQUEST_AUTO_CONFIG message from client\n");
1398 GNUNET_CONFIGURATION_get_value_string (ac->c,
1402 ac->system_type = GNUNET_strdup ("UNKNOWN");
1404 GNUNET_CONTAINER_DLL_insert (ac_head,
1408 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1409 &conclude_autoconfig_request,
1411 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1413 /* Probe for upnpc */
1414 if (GNUNET_SYSERR ==
1415 GNUNET_OS_check_helper_binary ("upnpc",
1419 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1420 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1421 ac->enable_upnpc = GNUNET_NO;
1425 for (lal = lal_head; NULL != lal; lal = lal->next)
1426 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1427 /* we are behind NAT, useful to try upnpc */
1428 ac->enable_upnpc = GNUNET_YES;
1430 if (GNUNET_YES == ac->enable_upnpc)
1432 /* If we are a mobile device, always leave it on as the network
1433 may change to one that supports UPnP anytime. If we are
1434 stationary, check if our network actually supports UPnP, and if
1436 if ( (0 == strcasecmp (ac->system_type,
1437 "INFRASTRUCTURE")) ||
1438 (0 == strcasecmp (ac->system_type,
1441 /* Check if upnpc gives us an external IP */
1443 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1447 if (NULL == ac->probe_external)
1448 update_enable_upnpc_option (ac);
1450 /* Finally, check if we are already done */
1451 check_autoconfig_finished (ac);
1456 * Task run during shutdown.
1461 shutdown_task (void *cls)
1463 struct StunExternalIP *se;
1464 struct AutoconfigContext *ac;
1466 while (NULL != (ac = ac_head))
1468 GNUNET_CONTAINER_DLL_remove (ac_head,
1471 terminate_ac_activities (ac);
1474 while (NULL != (se = se_head))
1476 GNUNET_CONTAINER_DLL_remove (se_head,
1479 GNUNET_SCHEDULER_cancel (se->timeout_task);
1482 if (NULL != scan_task)
1484 GNUNET_SCHEDULER_cancel (scan_task);
1489 GNUNET_STATISTICS_destroy (stats,
1498 * Setup NAT service.
1500 * @param cls closure
1501 * @param c configuration to use
1502 * @param service the initialized service
1506 const struct GNUNET_CONFIGURATION_Handle *c,
1507 struct GNUNET_SERVICE_Handle *service)
1511 GNUNET_CONFIGURATION_get_value_time (cfg,
1514 &stun_stale_timeout))
1515 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1517 /* Check for UPnP */
1519 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1522 if (GNUNET_YES == enable_upnp)
1524 /* check if it works */
1525 if (GNUNET_SYSERR ==
1526 GNUNET_OS_check_helper_binary ("upnpc",
1530 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1531 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1532 enable_upnp = GNUNET_SYSERR;
1536 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1538 stats = GNUNET_STATISTICS_create ("nat",
1540 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1546 * Callback called when a client connects to the service.
1548 * @param cls closure for the service
1549 * @param c the new client that connected to the service
1550 * @param mq the message queue used to send messages to the client
1551 * @return a `struct ClientHandle`
1554 client_connect_cb (void *cls,
1555 struct GNUNET_SERVICE_Client *c,
1556 struct GNUNET_MQ_Handle *mq)
1558 struct ClientHandle *ch;
1560 ch = GNUNET_new (struct ClientHandle);
1563 GNUNET_CONTAINER_DLL_insert (ch_head,
1571 * Callback called when a client disconnected from the service
1573 * @param cls closure for the service
1574 * @param c the client that disconnected
1575 * @param internal_cls a `struct ClientHandle *`
1578 client_disconnect_cb (void *cls,
1579 struct GNUNET_SERVICE_Client *c,
1582 struct ClientHandle *ch = internal_cls;
1584 GNUNET_CONTAINER_DLL_remove (ch_head,
1587 for (unsigned int i=0;i<ch->num_addrs;i++)
1588 GNUNET_free_non_null (ch->addrs[i]);
1589 GNUNET_free_non_null (ch->addrs);
1595 * Define "main" method using service macro.
1599 GNUNET_SERVICE_OPTION_NONE,
1602 &client_disconnect_cb,
1604 GNUNET_MQ_hd_var_size (register,
1605 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1606 struct GNUNET_NAT_RegisterMessage,
1608 GNUNET_MQ_hd_var_size (stun,
1609 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1610 struct GNUNET_NAT_HandleStunMessage,
1612 GNUNET_MQ_hd_var_size (request_connection_reversal,
1613 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1614 struct GNUNET_NAT_RequestConnectionReversalMessage,
1616 GNUNET_MQ_hd_var_size (autoconfig_request,
1617 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1618 struct GNUNET_NAT_AutoconfigRequestMessage,
1620 GNUNET_MQ_handler_end ());
1623 #if defined(LINUX) && defined(__GLIBC__)
1627 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1629 void __attribute__ ((constructor))
1630 GNUNET_ARM_memory_init ()
1632 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1633 mallopt (M_TOP_PAD, 1 * 1024);
1638 /* end of gnunet-service-nat.c */