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 * Original configuration (for diffing).
223 struct GNUNET_CONFIGURATION_Handle *orig;
226 * Timeout task to force termination.
228 struct GNUNET_SCHEDULER_Task *timeout_task;
231 * What type of system are we on?
236 * Handle to activity to probe for our external IP.
238 struct GNUNET_NAT_ExternalHandle *probe_external;
241 * #GNUNET_YES if upnpc should be used,
242 * #GNUNET_NO if upnpc should not be used,
243 * #GNUNET_SYSERR if we should simply not change the option.
248 * Status code to return to the client.
250 enum GNUNET_NAT_StatusCode status_code;
253 * NAT type to return to the client.
255 enum GNUNET_NAT_Type type;
260 * DLL of our autoconfiguration operations.
262 static struct AutoconfigContext *ac_head;
265 * DLL of our autoconfiguration operations.
267 static struct AutoconfigContext *ac_tail;
270 * Timeout to use when STUN data is considered stale.
272 static struct GNUNET_TIME_Relative stun_stale_timeout;
275 * Handle to our current configuration.
277 static const struct GNUNET_CONFIGURATION_Handle *cfg;
280 * Handle to the statistics service.
282 static struct GNUNET_STATISTICS_Handle *stats;
285 * Task scheduled to periodically scan our network interfaces.
287 static struct GNUNET_SCHEDULER_Task *scan_task;
290 * Head of client DLL.
292 static struct ClientHandle *ch_head;
295 * Tail of client DLL.
297 static struct ClientHandle *ch_tail;
300 * Head of DLL of local addresses.
302 static struct LocalAddressList *lal_head;
305 * Tail of DLL of local addresses.
307 static struct LocalAddressList *lal_tail;
312 static struct StunExternalIP *se_head;
317 static struct StunExternalIP *se_tail;
320 * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
321 * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
323 static int enable_upnp;
327 * Free the DLL starting at #lal_head.
332 struct LocalAddressList *lal;
334 while (NULL != (lal = lal_head))
336 GNUNET_CONTAINER_DLL_remove (lal_head,
345 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
348 * @param cls client who sent the message
349 * @param message the message received
350 * @return #GNUNET_OK if message is well-formed
353 check_register (void *cls,
354 const struct GNUNET_NAT_RegisterMessage *message)
356 uint16_t num_addrs = ntohs (message->num_addrs);
357 const char *off = (const char *) &message[1];
358 size_t left = ntohs (message->header.size) - sizeof (*message);
360 for (unsigned int i=0;i<num_addrs;i++)
363 const struct sockaddr *sa = (const struct sockaddr *) off;
365 if (sizeof (sa_family_t) > left)
368 return GNUNET_SYSERR;
370 switch (sa->sa_family)
373 alen = sizeof (struct sockaddr_in);
376 alen = sizeof (struct sockaddr_in6);
380 alen = sizeof (struct sockaddr_un);
385 return GNUNET_SYSERR;
390 return GNUNET_SYSERR;
398 * Check if @a ip is in @a network with @a bits netmask.
400 * @param network to test
401 * @param ip IP address to test
402 * @param bits bitmask for the network
403 * @return #GNUNET_YES if @a ip is in @a network
406 match_ipv4 (const char *network,
407 const struct in_addr *ip,
416 GNUNET_assert (1 == inet_pton (AF_INET,
419 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
424 * Check if @a ip is in @a network with @a bits netmask.
426 * @param network to test
427 * @param ip IP address to test
428 * @param bits bitmask for the network
429 * @return #GNUNET_YES if @a ip is in @a network
432 match_ipv6 (const char *network,
433 const struct in6_addr *ip,
437 struct in6_addr mask;
442 GNUNET_assert (1 == inet_pton (AF_INET6,
445 memset (&mask, 0, sizeof (mask));
446 if (0 == memcmp (&mask,
453 mask.s6_addr[off++] = 0xFF;
458 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
461 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
462 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
463 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
470 * Test if the given IPv4 address is in a known range
471 * for private networks.
473 * @param ip address to test
474 * @return #GNUNET_YES if @a ip is in a NAT range
477 is_nat_v4 (const struct in_addr *ip)
480 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
481 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
482 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
483 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
484 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
489 * Test if the given IPv6 address is in a known range
490 * for private networks.
492 * @param ip address to test
493 * @return #GNUNET_YES if @a ip is in a NAT range
496 is_nat_v6 (const struct in6_addr *ip)
499 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
500 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
501 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
506 * Closure for #ifc_proc.
508 struct IfcProcContext
512 * Head of DLL of local addresses.
514 struct LocalAddressList *lal_head;
517 * Tail of DLL of local addresses.
519 struct LocalAddressList *lal_tail;
525 * Callback function invoked for each interface found. Adds them
526 * to our new address list.
528 * @param cls a `struct IfcProcContext *`
529 * @param name name of the interface (can be NULL for unknown)
530 * @param isDefault is this presumably the default interface
531 * @param addr address of this interface (can be NULL for unknown or unassigned)
532 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
533 * @param netmask the network mask (can be NULL for unknown or unassigned)
534 * @param addrlen length of the address
535 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
541 const struct sockaddr *addr,
542 const struct sockaddr *broadcast_addr,
543 const struct sockaddr *netmask,
546 struct IfcProcContext *ifc_ctx = cls;
547 struct LocalAddressList *lal;
549 const struct in_addr *ip4;
550 const struct in6_addr *ip6;
551 enum GNUNET_NAT_AddressClass ac;
553 switch (addr->sa_family)
556 alen = sizeof (struct sockaddr_in);
557 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
558 if (match_ipv4 ("127.0.0.0", ip4, 8))
559 ac = GNUNET_NAT_AC_LOOPBACK;
560 else if (is_nat_v4 (ip4))
561 ac = GNUNET_NAT_AC_LAN;
563 ac = GNUNET_NAT_AC_GLOBAL;
566 alen = sizeof (struct sockaddr_in6);
567 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
568 if (match_ipv6 ("::1", ip6, 128))
569 ac = GNUNET_NAT_AC_LOOPBACK;
570 else if (is_nat_v6 (ip6))
571 ac = GNUNET_NAT_AC_LAN;
573 ac = GNUNET_NAT_AC_GLOBAL;
574 if ( (ip6->s6_addr[11] == 0xFF) &&
575 (ip6->s6_addr[12] == 0xFE) )
577 /* contains a MAC, be extra careful! */
578 ac |= GNUNET_NAT_AC_PRIVATE;
590 lal = GNUNET_malloc (sizeof (*lal));
591 lal->af = addr->sa_family;
593 GNUNET_memcpy (&lal->addr,
596 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
604 * Notify client about a change in the list of addresses this peer
607 * @param delta the entry in the list that changed
608 * @param ch client to contact
609 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
610 * @param addr the address that changed
611 * @param addr_len number of bytes in @a addr
614 notify_client (struct LocalAddressList *delta,
615 struct ClientHandle *ch,
620 struct GNUNET_MQ_Envelope *env;
621 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
623 env = GNUNET_MQ_msg_extra (msg,
625 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
626 msg->add_remove = htonl (add);
627 msg->addr_class = htonl (delta->ac);
628 GNUNET_memcpy (&msg[1],
631 GNUNET_MQ_send (ch->mq,
637 * Check if we should bother to notify this client about this
638 * address change, and if so, do it.
640 * @param delta the entry in the list that changed
641 * @param ch client to check
642 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
645 check_notify_client (struct LocalAddressList *delta,
646 struct ClientHandle *ch,
650 struct sockaddr_in v4;
651 struct sockaddr_in6 v6;
653 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
658 alen = sizeof (struct sockaddr_in);
662 for (unsigned int i=0;i<ch->num_addrs;i++)
664 const struct sockaddr_in *c4;
666 if (AF_INET != ch->addrs[i]->sa_family)
667 return; /* IPv4 not relevant */
668 c4 = (const struct sockaddr_in *) ch->addrs[i];
669 v4.sin_port = c4->sin_port;
670 notify_client (delta,
678 alen = sizeof (struct sockaddr_in6);
682 for (unsigned int i=0;i<ch->num_addrs;i++)
684 const struct sockaddr_in6 *c6;
686 if (AF_INET6 != ch->addrs[i]->sa_family)
687 return; /* IPv4 not relevant */
688 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
689 v6.sin6_port = c6->sin6_port;
690 notify_client (delta,
705 * Notify all clients about a change in the list
706 * of addresses this peer has.
708 * @param delta the entry in the list that changed
709 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
712 notify_clients (struct LocalAddressList *delta,
715 for (struct ClientHandle *ch = ch_head;
718 check_notify_client (delta,
725 * Task we run periodically to scan for network interfaces.
732 struct IfcProcContext ifc_ctx;
735 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
741 GNUNET_OS_network_interfaces_list (&ifc_proc,
743 /* remove addresses that disappeared */
744 for (struct LocalAddressList *lal = lal_head;
749 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
753 if ( (pos->af == lal->af) &&
754 (0 == memcmp (&lal->addr,
757 ? sizeof (struct sockaddr_in)
758 : sizeof (struct sockaddr_in6))) )
761 if (GNUNET_NO == found)
766 /* add addresses that appeared */
767 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
772 for (struct LocalAddressList *lal = lal_head;
776 if ( (pos->af == lal->af) &&
777 (0 == memcmp (&lal->addr,
780 ? sizeof (struct sockaddr_in)
781 : sizeof (struct sockaddr_in6))) )
784 if (GNUNET_NO == found)
790 lal_head = ifc_ctx.lal_head;
791 lal_tail = ifc_ctx.lal_tail;
796 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
797 * We remember the client for updates upon future NAT events.
799 * @param cls client who sent the message
800 * @param message the message received
803 handle_register (void *cls,
804 const struct GNUNET_NAT_RegisterMessage *message)
806 struct ClientHandle *ch = cls;
810 if ( (0 != ch->proto) ||
811 (NULL != ch->addrs) )
813 /* double registration not allowed */
815 GNUNET_SERVICE_client_drop (ch->client);
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Received REGISTER message from client\n");
820 ch->flags = message->flags;
821 ch->proto = message->proto;
822 ch->adv_port = ntohs (message->adv_port);
823 ch->num_addrs = ntohs (message->num_addrs);
824 ch->addrs = GNUNET_new_array (ch->num_addrs,
826 left = ntohs (message->header.size) - sizeof (*message);
827 off = (const char *) &message[1];
828 for (unsigned int i=0;i<ch->num_addrs;i++)
831 const struct sockaddr *sa = (const struct sockaddr *) off;
833 if (sizeof (sa_family_t) > left)
836 GNUNET_SERVICE_client_drop (ch->client);
839 switch (sa->sa_family)
843 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
845 alen = sizeof (struct sockaddr_in);
846 if (is_nat_v4 (&s4->sin_addr))
847 ch->natted_address = GNUNET_YES;
852 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
854 alen = sizeof (struct sockaddr_in6);
855 if (is_nat_v6 (&s6->sin6_addr))
856 ch->natted_address = GNUNET_YES;
861 alen = sizeof (struct sockaddr_un);
866 GNUNET_SERVICE_client_drop (ch->client);
869 GNUNET_assert (alen <= left);
870 ch->addrs[i] = GNUNET_malloc (alen);
871 GNUNET_memcpy (ch->addrs[i],
876 /* Actually send IP address list to client */
877 for (struct LocalAddressList *lal = lal_head;
881 check_notify_client (lal,
885 GNUNET_SERVICE_client_continue (ch->client);
890 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
893 * @param cls client who sent the message
894 * @param message the message received
895 * @return #GNUNET_OK if message is well-formed
898 check_stun (void *cls,
899 const struct GNUNET_NAT_HandleStunMessage *message)
901 size_t sa_len = ntohs (message->sender_addr_size);
902 size_t expect = sa_len + ntohs (message->payload_size);
904 if (ntohs (message->header.size) - sizeof (*message) != expect)
907 return GNUNET_SYSERR;
909 if (sa_len < sizeof (sa_family_t))
912 return GNUNET_SYSERR;
919 * Notify all clients about our external IP address
920 * as reported by the STUN server.
922 * @param ip the external IP
923 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
926 notify_clients_stun_change (const struct sockaddr_in *ip,
929 for (struct ClientHandle *ch = ch_head;
933 struct sockaddr_in v4;
934 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
935 struct GNUNET_MQ_Envelope *env;
937 if (! ch->natted_address)
940 v4.sin_port = htons (ch->adv_port);
941 env = GNUNET_MQ_msg_extra (msg,
943 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
944 msg->add_remove = htonl ((int32_t) add);
945 msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN |
946 GNUNET_NAT_AC_GLOBAL);
947 GNUNET_memcpy (&msg[1],
950 GNUNET_MQ_send (ch->mq,
957 * Function to be called when we decide that an
958 * external IP address as told to us by a STUN
959 * server has gone stale.
961 * @param cls the `struct StunExternalIP` to drop
964 stun_ip_timeout (void *cls)
966 struct StunExternalIP *se = cls;
968 se->timeout_task = NULL;
969 notify_clients_stun_change (&se->external_addr,
971 GNUNET_CONTAINER_DLL_remove (se_head,
979 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
982 * @param cls client who sent the message
983 * @param message the message received
986 handle_stun (void *cls,
987 const struct GNUNET_NAT_HandleStunMessage *message)
989 struct ClientHandle *ch = cls;
990 const char *buf = (const char *) &message[1];
991 const struct sockaddr *sa;
995 struct sockaddr_in external_addr;
997 sa_len = ntohs (message->sender_addr_size);
998 payload_size = ntohs (message->payload_size);
999 sa = (const struct sockaddr *) &buf[0];
1000 payload = (const struct sockaddr *) &buf[sa_len];
1001 switch (sa->sa_family)
1004 if (sa_len != sizeof (struct sockaddr_in))
1007 GNUNET_SERVICE_client_drop (ch->client);
1012 if (sa_len != sizeof (struct sockaddr_in6))
1015 GNUNET_SERVICE_client_drop (ch->client);
1020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021 "Received HANDLE_STUN message from client\n");
1023 GNUNET_NAT_stun_handle_packet_ (payload,
1027 /* We now know that a server at "sa" claims that
1028 we are visible at IP "external_addr".
1030 We should (for some fixed period of time) tell
1031 all of our clients that listen to a NAT'ed address
1032 that they might want to consider the given 'external_ip'
1033 as their public IP address (this includes TCP and UDP
1034 clients, even if only UDP sends STUN requests).
1036 If we do not get a renewal, the "external_addr" should be
1037 removed again. The timeout frequency should be configurable
1038 (with a sane default), so that the UDP plugin can tell how
1039 often to re-request STUN.
1041 struct StunExternalIP *se;
1043 /* Check if we had a prior response from this STUN server */
1044 for (se = se_head; NULL != se; se = se->next)
1046 if ( (se->stun_server_addr_len != sa_len) ||
1048 &se->stun_server_addr,
1050 continue; /* different STUN server */
1051 if (0 != memcmp (&external_addr,
1053 sizeof (struct sockaddr_in)))
1055 /* external IP changed, update! */
1056 notify_clients_stun_change (&se->external_addr,
1058 se->external_addr = external_addr;
1059 notify_clients_stun_change (&se->external_addr,
1062 /* update timeout */
1063 GNUNET_SCHEDULER_cancel (se->timeout_task);
1065 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1070 /* STUN server is completely new, create fresh entry */
1071 se = GNUNET_new (struct StunExternalIP);
1072 se->external_addr = external_addr;
1073 GNUNET_memcpy (&se->stun_server_addr,
1076 se->stun_server_addr_len = sa_len;
1077 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1080 GNUNET_CONTAINER_DLL_insert (se_head,
1083 notify_clients_stun_change (&se->external_addr,
1086 GNUNET_SERVICE_client_continue (ch->client);
1092 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1095 * @param cls client who sent the message
1096 * @param message the message received
1097 * @return #GNUNET_OK if message is well-formed
1100 check_request_connection_reversal (void *cls,
1101 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1105 expect = ntohs (message->local_addr_size)
1106 + ntohs (message->remote_addr_size);
1107 if (ntohs (message->header.size) - sizeof (*message) != expect)
1110 return GNUNET_SYSERR;
1117 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1118 * message from client.
1120 * @param cls client who sent the message
1121 * @param message the message received
1124 handle_request_connection_reversal (void *cls,
1125 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1127 struct ClientHandle *ch = cls;
1128 const char *buf = (const char *) &message[1];
1129 size_t local_sa_len = ntohs (message->local_addr_size);
1130 size_t remote_sa_len = ntohs (message->remote_addr_size);
1131 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1132 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1133 const struct sockaddr_in *l4 = NULL;
1134 const struct sockaddr_in *r4;
1137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1138 "Received REQUEST CONNECTION REVERSAL message from client\n");
1139 switch (local_sa->sa_family)
1142 if (local_sa_len != sizeof (struct sockaddr_in))
1145 GNUNET_SERVICE_client_drop (ch->client);
1148 l4 = (const struct sockaddr_in *) local_sa;
1151 if (local_sa_len != sizeof (struct sockaddr_in6))
1154 GNUNET_SERVICE_client_drop (ch->client);
1157 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1158 _("Connection reversal for IPv6 not supported yet\n"));
1159 ret = GNUNET_SYSERR;
1163 GNUNET_SERVICE_client_drop (ch->client);
1166 switch (remote_sa->sa_family)
1169 if (remote_sa_len != sizeof (struct sockaddr_in))
1172 GNUNET_SERVICE_client_drop (ch->client);
1175 r4 = (const struct sockaddr_in *) remote_sa;
1176 ret = GN_request_connection_reversal (&l4->sin_addr,
1177 ntohs (l4->sin_port),
1181 if (remote_sa_len != sizeof (struct sockaddr_in6))
1184 GNUNET_SERVICE_client_drop (ch->client);
1187 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1188 _("Connection reversal for IPv6 not supported yet\n"));
1189 ret = GNUNET_SYSERR;
1193 GNUNET_SERVICE_client_drop (ch->client);
1196 if (GNUNET_OK != ret)
1197 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1198 _("Connection reversal request failed\n"));
1199 GNUNET_SERVICE_client_continue (ch->client);
1204 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1207 * @param cls client who sent the message
1208 * @param message the message received
1209 * @return #GNUNET_OK if message is well-formed
1212 check_autoconfig_request (void *cls,
1213 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1215 return GNUNET_OK; /* checked later */
1220 * Stop all pending activities with respect to the @a ac
1222 * @param ac autoconfiguration to terminate activities for
1225 terminate_ac_activities (struct AutoconfigContext *ac)
1227 if (NULL != ac->probe_external)
1229 GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1230 ac->probe_external = NULL;
1232 if (NULL != ac->timeout_task)
1234 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1235 ac->timeout_task = NULL;
1241 * Finish handling the autoconfiguration request and send
1242 * the response to the client.
1244 * @param cls the `struct AutoconfigContext` to conclude
1247 conclude_autoconfig_request (void *cls)
1249 struct AutoconfigContext *ac = cls;
1250 struct ClientHandle *ch = ac->ch;
1251 struct GNUNET_NAT_AutoconfigResultMessage *arm;
1252 struct GNUNET_MQ_Envelope *env;
1255 struct GNUNET_CONFIGURATION_Handle *diff;
1257 ac->timeout_task = NULL;
1258 terminate_ac_activities (ac);
1260 /* Send back response */
1261 diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1263 buf = GNUNET_CONFIGURATION_serialize (diff,
1265 GNUNET_CONFIGURATION_destroy (diff);
1266 env = GNUNET_MQ_msg_extra (arm,
1268 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1269 arm->status_code = htonl ((uint32_t) ac->status_code);
1270 arm->type = htonl ((uint32_t) ac->type);
1271 GNUNET_memcpy (&arm[1],
1275 GNUNET_MQ_send (ch->mq,
1279 GNUNET_free (ac->system_type);
1280 GNUNET_CONFIGURATION_destroy (ac->orig);
1281 GNUNET_CONFIGURATION_destroy (ac->c);
1282 GNUNET_CONTAINER_DLL_remove (ac_head,
1286 GNUNET_SERVICE_client_continue (ch->client);
1291 * Check if all autoconfiguration operations have concluded,
1292 * and if they have, send the result back to the client.
1294 * @param ac autoconfiguation context to check
1297 check_autoconfig_finished (struct AutoconfigContext *ac)
1299 if (NULL != ac->probe_external)
1301 GNUNET_SCHEDULER_cancel (ac->timeout_task);
1303 = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1309 * Update ENABLE_UPNPC configuration option.
1311 * @param ac autoconfiguration to update
1314 update_enable_upnpc_option (struct AutoconfigContext *ac)
1316 switch (ac->enable_upnpc)
1319 GNUNET_CONFIGURATION_set_value_string (ac->c,
1325 GNUNET_CONFIGURATION_set_value_string (ac->c,
1331 /* We are unsure, do not change option */
1338 * Handle result from external IP address probe during
1339 * autoconfiguration.
1341 * @param cls our `struct AutoconfigContext`
1342 * @param addr the address, NULL on errors
1343 * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1346 auto_external_result_cb (void *cls,
1347 const struct in_addr *addr,
1348 enum GNUNET_NAT_StatusCode result)
1350 struct AutoconfigContext *ac = cls;
1352 ac->probe_external = NULL;
1355 case GNUNET_NAT_ERROR_SUCCESS:
1356 ac->enable_upnpc = GNUNET_YES;
1358 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1359 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1360 case GNUNET_NAT_ERROR_IPC_FAILURE:
1361 ac->enable_upnpc = GNUNET_NO; /* did not work */
1364 GNUNET_break (0); /* unexpected */
1365 ac->enable_upnpc = GNUNET_SYSERR;
1368 update_enable_upnpc_option (ac);
1369 check_autoconfig_finished (ac);
1374 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1377 * @param cls client who sent the message
1378 * @param message the message received
1381 handle_autoconfig_request (void *cls,
1382 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1384 struct ClientHandle *ch = cls;
1385 size_t left = ntohs (message->header.size) - sizeof (*message);
1386 struct LocalAddressList *lal;
1387 struct AutoconfigContext *ac;
1389 ac = GNUNET_new (struct AutoconfigContext);
1391 ac->c = GNUNET_CONFIGURATION_create ();
1393 GNUNET_CONFIGURATION_deserialize (ac->c,
1394 (const char *) &message[1],
1399 GNUNET_SERVICE_client_drop (ch->client);
1400 GNUNET_CONFIGURATION_destroy (ac->c);
1404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1405 "Received REQUEST_AUTO_CONFIG message from client\n");
1408 GNUNET_CONFIGURATION_get_value_string (ac->c,
1412 ac->system_type = GNUNET_strdup ("UNKNOWN");
1414 GNUNET_CONTAINER_DLL_insert (ac_head,
1418 = GNUNET_CONFIGURATION_dup (ac->c);
1420 = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1421 &conclude_autoconfig_request,
1423 ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1425 /* Probe for upnpc */
1426 if (GNUNET_SYSERR ==
1427 GNUNET_OS_check_helper_binary ("upnpc",
1431 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1432 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1433 ac->enable_upnpc = GNUNET_NO;
1437 for (lal = lal_head; NULL != lal; lal = lal->next)
1438 if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1439 /* we are behind NAT, useful to try upnpc */
1440 ac->enable_upnpc = GNUNET_YES;
1442 if (GNUNET_YES == ac->enable_upnpc)
1444 /* If we are a mobile device, always leave it on as the network
1445 may change to one that supports UPnP anytime. If we are
1446 stationary, check if our network actually supports UPnP, and if
1448 if ( (0 == strcasecmp (ac->system_type,
1449 "INFRASTRUCTURE")) ||
1450 (0 == strcasecmp (ac->system_type,
1453 /* Check if upnpc gives us an external IP */
1455 = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1459 if (NULL == ac->probe_external)
1460 update_enable_upnpc_option (ac);
1462 /* Finally, check if we are already done */
1463 check_autoconfig_finished (ac);
1468 * Task run during shutdown.
1473 shutdown_task (void *cls)
1475 struct StunExternalIP *se;
1476 struct AutoconfigContext *ac;
1478 while (NULL != (ac = ac_head))
1480 GNUNET_CONTAINER_DLL_remove (ac_head,
1483 terminate_ac_activities (ac);
1486 while (NULL != (se = se_head))
1488 GNUNET_CONTAINER_DLL_remove (se_head,
1491 GNUNET_SCHEDULER_cancel (se->timeout_task);
1494 if (NULL != scan_task)
1496 GNUNET_SCHEDULER_cancel (scan_task);
1501 GNUNET_STATISTICS_destroy (stats,
1510 * Setup NAT service.
1512 * @param cls closure
1513 * @param c configuration to use
1514 * @param service the initialized service
1518 const struct GNUNET_CONFIGURATION_Handle *c,
1519 struct GNUNET_SERVICE_Handle *service)
1523 GNUNET_CONFIGURATION_get_value_time (cfg,
1526 &stun_stale_timeout))
1527 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1529 /* Check for UPnP */
1531 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1534 if (GNUNET_YES == enable_upnp)
1536 /* check if it works */
1537 if (GNUNET_SYSERR ==
1538 GNUNET_OS_check_helper_binary ("upnpc",
1542 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1543 _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1544 enable_upnp = GNUNET_SYSERR;
1548 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1550 stats = GNUNET_STATISTICS_create ("nat",
1552 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1558 * Callback called when a client connects to the service.
1560 * @param cls closure for the service
1561 * @param c the new client that connected to the service
1562 * @param mq the message queue used to send messages to the client
1563 * @return a `struct ClientHandle`
1566 client_connect_cb (void *cls,
1567 struct GNUNET_SERVICE_Client *c,
1568 struct GNUNET_MQ_Handle *mq)
1570 struct ClientHandle *ch;
1572 ch = GNUNET_new (struct ClientHandle);
1575 GNUNET_CONTAINER_DLL_insert (ch_head,
1583 * Callback called when a client disconnected from the service
1585 * @param cls closure for the service
1586 * @param c the client that disconnected
1587 * @param internal_cls a `struct ClientHandle *`
1590 client_disconnect_cb (void *cls,
1591 struct GNUNET_SERVICE_Client *c,
1594 struct ClientHandle *ch = internal_cls;
1596 GNUNET_CONTAINER_DLL_remove (ch_head,
1599 for (unsigned int i=0;i<ch->num_addrs;i++)
1600 GNUNET_free_non_null (ch->addrs[i]);
1601 GNUNET_free_non_null (ch->addrs);
1607 * Define "main" method using service macro.
1611 GNUNET_SERVICE_OPTION_NONE,
1614 &client_disconnect_cb,
1616 GNUNET_MQ_hd_var_size (register,
1617 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1618 struct GNUNET_NAT_RegisterMessage,
1620 GNUNET_MQ_hd_var_size (stun,
1621 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1622 struct GNUNET_NAT_HandleStunMessage,
1624 GNUNET_MQ_hd_var_size (request_connection_reversal,
1625 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1626 struct GNUNET_NAT_RequestConnectionReversalMessage,
1628 GNUNET_MQ_hd_var_size (autoconfig_request,
1629 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1630 struct GNUNET_NAT_AutoconfigRequestMessage,
1632 GNUNET_MQ_handler_end ());
1635 #if defined(LINUX) && defined(__GLIBC__)
1639 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1641 void __attribute__ ((constructor))
1642 GNUNET_ARM_memory_init ()
1644 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1645 mallopt (M_TOP_PAD, 1 * 1024);
1650 /* end of gnunet-service-nat.c */