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.
32 #include "gnunet_util_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_signatures.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_nat_service.h"
37 #include "gnunet-service-nat_stun.h"
38 #include "gnunet-service-nat_helper.h"
44 * How often should we ask the OS about a list of active
47 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
51 * Internal data structure we track for each of our clients.
59 struct ClientHandle *next;
64 struct ClientHandle *prev;
67 * Underlying handle for this client with the service.
69 struct GNUNET_SERVICE_Client *client;
72 * Message queue for communicating with the client.
74 struct GNUNET_MQ_Handle *mq;
77 * Array of addresses used by the service.
79 struct sockaddr **addrs;
82 * What does this client care about?
84 enum GNUNET_NAT_RegisterFlags flags;
87 * Port we would like as we are configured to use this one for
88 * advertising (in addition to the one we are binding to).
93 * Number of addresses that this service is bound to.
98 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
106 * List of local addresses this system has.
108 struct LocalAddressList
111 * This is a linked list.
113 struct LocalAddressList *next;
118 struct LocalAddressList *prev;
121 * The address itself (i.e. `struct sockaddr_in` or `struct
122 * sockaddr_in6`, in the respective byte order).
124 struct sockaddr_storage addr;
132 * What type of address is this?
134 enum GNUNET_NAT_AddressClass ac;
140 * Handle to our current configuration.
142 static const struct GNUNET_CONFIGURATION_Handle *cfg;
145 * Handle to the statistics service.
147 static struct GNUNET_STATISTICS_Handle *stats;
150 * Task scheduled to periodically scan our network interfaces.
152 static struct GNUNET_SCHEDULER_Task *scan_task;
155 * Head of client DLL.
157 static struct ClientHandle *ch_head;
160 * Tail of client DLL.
162 static struct ClientHandle *ch_tail;
165 * Head of DLL of local addresses.
167 static struct LocalAddressList *lal_head;
170 * Tail of DLL of local addresses.
172 static struct LocalAddressList *lal_tail;
176 * Free the DLL starting at #lal_head.
181 struct LocalAddressList *lal;
183 while (NULL != (lal = lal_head))
185 GNUNET_CONTAINER_DLL_remove (lal_head,
194 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
197 * @param cls client who sent the message
198 * @param message the message received
199 * @return #GNUNET_OK if message is well-formed
202 check_register (void *cls,
203 const struct GNUNET_NAT_RegisterMessage *message)
205 uint16_t num_addrs = ntohs (message->num_addrs);
206 const char *off = (const char *) &message[1];
207 size_t left = ntohs (message->header.size) - sizeof (*message);
209 for (unsigned int i=0;i<num_addrs;i++)
212 const struct sockaddr *sa = (const struct sockaddr *) off;
214 if (sizeof (sa_family_t) > left)
217 return GNUNET_SYSERR;
219 switch (sa->sa_family)
222 alen = sizeof (struct sockaddr_in);
225 alen = sizeof (struct sockaddr_in6);
229 alen = sizeof (struct sockaddr_un);
234 return GNUNET_SYSERR;
239 return GNUNET_SYSERR;
247 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
248 * We remember the client for updates upon future NAT events.
250 * @param cls client who sent the message
251 * @param message the message received
254 handle_register (void *cls,
255 const struct GNUNET_NAT_RegisterMessage *message)
257 struct ClientHandle *ch = cls;
261 if ( (0 != ch->proto) ||
262 (NULL != ch->addrs) )
264 /* double registration not allowed */
266 GNUNET_SERVICE_client_drop (ch->client);
269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
270 "Received REGISTER message from client\n");
271 ch->flags = message->flags;
272 ch->proto = message->proto;
273 ch->adv_port = ntohs (message->adv_port);
274 ch->num_addrs = ntohs (message->adv_port);
275 ch->addrs = GNUNET_new_array (ch->num_addrs,
277 left = ntohs (message->header.size) - sizeof (*message);
278 off = (const char *) &message[1];
279 for (unsigned int i=0;i<ch->num_addrs;i++)
282 const struct sockaddr *sa = (const struct sockaddr *) off;
284 if (sizeof (sa_family_t) > left)
287 GNUNET_SERVICE_client_drop (ch->client);
290 switch (sa->sa_family)
293 alen = sizeof (struct sockaddr_in);
296 alen = sizeof (struct sockaddr_in6);
300 alen = sizeof (struct sockaddr_un);
305 GNUNET_SERVICE_client_drop (ch->client);
308 GNUNET_assert (alen <= left);
309 ch->addrs[i] = GNUNET_malloc (alen);
310 GNUNET_memcpy (ch->addrs[i],
315 GNUNET_SERVICE_client_continue (ch->client);
320 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
323 * @param cls client who sent the message
324 * @param message the message received
325 * @return #GNUNET_OK if message is well-formed
328 check_stun (void *cls,
329 const struct GNUNET_NAT_HandleStunMessage *message)
331 size_t sa_len = ntohs (message->sender_addr_size);
332 size_t expect = sa_len + ntohs (message->payload_size);
334 if (ntohs (message->header.size) - sizeof (*message) != expect)
337 return GNUNET_SYSERR;
339 if (sa_len < sizeof (sa_family_t))
342 return GNUNET_SYSERR;
349 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
352 * @param cls client who sent the message
353 * @param message the message received
356 handle_stun (void *cls,
357 const struct GNUNET_NAT_HandleStunMessage *message)
359 struct ClientHandle *ch = cls;
360 const char *buf = (const char *) &message[1];
361 const struct sockaddr *sa;
365 struct sockaddr_in external_addr;
367 sa_len = ntohs (message->sender_addr_size);
368 payload_size = ntohs (message->payload_size);
369 sa = (const struct sockaddr *) &buf[0];
370 payload = (const struct sockaddr *) &buf[sa_len];
371 switch (sa->sa_family)
374 if (sa_len != sizeof (struct sockaddr_in))
377 GNUNET_SERVICE_client_drop (ch->client);
382 if (sa_len != sizeof (struct sockaddr_in6))
385 GNUNET_SERVICE_client_drop (ch->client);
390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391 "Received HANDLE_STUN message from client\n");
393 GNUNET_NAT_stun_handle_packet_ (payload,
397 /* FIXME: do something with "external_addr"! We
398 now know that a server at "sa" claims that
399 we are visible at IP "external_addr".
401 We should (for some fixed period of time) tell
402 all of our clients that listen to a NAT'ed address
403 that they might want to consider the given 'external_ip'
404 as their public IP address (this includes TCP and UDP
405 clients, even if only UDP sends STUN requests).
407 If we do not get a renewal, the "external_addr" should be
408 removed again. The timeout frequency should be configurable
409 (with a sane default), so that the UDP plugin can tell how
410 often to re-request STUN.
414 GNUNET_SERVICE_client_continue (ch->client);
420 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
423 * @param cls client who sent the message
424 * @param message the message received
425 * @return #GNUNET_OK if message is well-formed
428 check_request_connection_reversal (void *cls,
429 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
433 expect = ntohs (message->local_addr_size)
434 + ntohs (message->remote_addr_size);
435 if (ntohs (message->header.size) - sizeof (*message) != expect)
438 return GNUNET_SYSERR;
445 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
446 * message from client.
448 * @param cls client who sent the message
449 * @param message the message received
452 handle_request_connection_reversal (void *cls,
453 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
455 struct ClientHandle *ch = cls;
456 const char *buf = (const char *) &message[1];
457 size_t local_sa_len = ntohs (message->local_addr_size);
458 size_t remote_sa_len = ntohs (message->remote_addr_size);
459 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
460 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
463 "Received REQUEST CONNECTION REVERSAL message from client\n");
464 switch (local_sa->sa_family)
467 if (local_sa_len != sizeof (struct sockaddr_in))
470 GNUNET_SERVICE_client_drop (ch->client);
475 if (local_sa_len != sizeof (struct sockaddr_in6))
478 GNUNET_SERVICE_client_drop (ch->client);
484 GNUNET_SERVICE_client_drop (ch->client);
487 switch (remote_sa->sa_family)
490 if (remote_sa_len != sizeof (struct sockaddr_in))
493 GNUNET_SERVICE_client_drop (ch->client);
498 if (remote_sa_len != sizeof (struct sockaddr_in6))
501 GNUNET_SERVICE_client_drop (ch->client);
507 GNUNET_SERVICE_client_drop (ch->client);
510 /* FIXME: actually run the logic! */
512 GNUNET_SERVICE_client_continue (ch->client);
517 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
520 * @param cls client who sent the message
521 * @param message the message received
524 handle_test (void *cls,
525 const struct GNUNET_NAT_RequestTestMessage *message)
527 struct ClientHandle *ch = cls;
529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
530 "Received REQUEST_TEST message from client\n");
531 /* FIXME: actually process test request */
532 GNUNET_SERVICE_client_continue (ch->client);
537 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
540 * @param cls client who sent the message
541 * @param message the message received
542 * @return #GNUNET_OK if message is well-formed
545 check_autoconfig_request (void *cls,
546 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
548 return GNUNET_OK; /* checked later */
553 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
556 * @param cls client who sent the message
557 * @param message the message received
560 handle_autoconfig_request (void *cls,
561 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
563 struct ClientHandle *ch = cls;
564 size_t left = ntohs (message->header.size);
565 struct GNUNET_CONFIGURATION_Handle *c;
567 c = GNUNET_CONFIGURATION_create ();
569 GNUNET_CONFIGURATION_deserialize (c,
570 (const char *) &message[1],
575 GNUNET_SERVICE_client_drop (ch->client);
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579 "Received REQUEST_AUTO_CONFIG message from client\n");
580 // FIXME: actually handle request...
581 GNUNET_CONFIGURATION_destroy (c);
582 GNUNET_SERVICE_client_continue (ch->client);
587 * Task run during shutdown.
592 shutdown_task (void *cls)
594 if (NULL != scan_task)
596 GNUNET_SCHEDULER_cancel (scan_task);
601 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
609 * Closure for #ifc_proc.
611 struct IfcProcContext
615 * Head of DLL of local addresses.
617 struct LocalAddressList *lal_head;
620 * Tail of DLL of local addresses.
622 struct LocalAddressList *lal_tail;
628 * Check if @a ip is in @a network with @a bits netmask.
630 * @param network to test
631 * @param ip IP address to test
632 * @param bits bitmask for the network
633 * @return #GNUNET_YES if @a ip is in @a network
636 match_ipv4 (const char *network,
637 const struct in_addr *ip,
644 GNUNET_assert (1 == inet_pton (AF_INET,
647 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
652 * Check if @a ip is in @a network with @a bits netmask.
654 * @param network to test
655 * @param ip IP address to test
656 * @param bits bitmask for the network
657 * @return #GNUNET_YES if @a ip is in @a network
660 match_ipv6 (const char *network,
661 const struct in6_addr *ip,
665 struct in6_addr mask;
670 GNUNET_assert (1 == inet_pton (AF_INET,
673 memset (&mask, 0, sizeof (mask));
677 mask.s6_addr[off++] = 0xFF;
682 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
685 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
686 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
687 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
694 * Test if the given IPv4 address is in a known range
695 * for private networks.
697 * @param ip address to test
698 * @return #GNUNET_YES if @a ip is in a NAT range
701 is_nat_v4 (const struct in_addr *ip)
704 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
705 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
706 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
707 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
708 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
713 * Test if the given IPv6 address is in a known range
714 * for private networks.
716 * @param ip address to test
717 * @return #GNUNET_YES if @a ip is in a NAT range
720 is_nat_v6 (const struct in6_addr *ip)
723 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
724 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
725 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
730 * Callback function invoked for each interface found. Adds them
731 * to our new address list.
733 * @param cls a `struct IfcProcContext *`
734 * @param name name of the interface (can be NULL for unknown)
735 * @param isDefault is this presumably the default interface
736 * @param addr address of this interface (can be NULL for unknown or unassigned)
737 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
738 * @param netmask the network mask (can be NULL for unknown or unassigned)
739 * @param addrlen length of the address
740 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
746 const struct sockaddr *addr,
747 const struct sockaddr *broadcast_addr,
748 const struct sockaddr *netmask,
751 struct IfcProcContext *ifc_ctx = cls;
752 struct LocalAddressList *lal;
754 const struct in_addr *ip4;
755 const struct in6_addr *ip6;
756 enum GNUNET_NAT_AddressClass ac;
758 switch (addr->sa_family)
761 alen = sizeof (struct sockaddr_in);
762 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
763 if (match_ipv4 ("127.0.0.0", ip4, 8))
764 ac = GNUNET_NAT_AC_LOOPBACK;
765 else if (is_nat_v4 (ip4))
766 ac = GNUNET_NAT_AC_LAN;
768 ac = GNUNET_NAT_AC_GLOBAL;
771 alen = sizeof (struct sockaddr_in6);
772 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
773 if (match_ipv6 ("::1", ip6, 128))
774 ac = GNUNET_NAT_AC_LOOPBACK;
775 else if (is_nat_v6 (ip6))
776 ac = GNUNET_NAT_AC_LAN;
778 ac = GNUNET_NAT_AC_GLOBAL;
779 if ( (ip6->s6_addr[11] == 0xFF) &&
780 (ip6->s6_addr[12] == 0xFE) )
782 /* contains a MAC, be extra careful! */
783 ac |= GNUNET_NAT_AC_PRIVATE;
795 lal = GNUNET_malloc (sizeof (*lal));
796 lal->af = addr->sa_family;
798 GNUNET_memcpy (&lal->addr,
801 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
809 * Notify client about a change in the list
810 * of addresses this peer has.
812 * @param delta the entry in the list that changed
813 * @param ch client to contact
814 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
815 * @param addr the address that changed
816 * @param addr_len number of bytes in @a addr
819 notify_client (struct LocalAddressList *delta,
820 struct ClientHandle *ch,
825 struct GNUNET_MQ_Envelope *env;
826 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
828 env = GNUNET_MQ_msg_extra (msg,
830 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
831 msg->add_remove = htonl (add);
832 msg->addr_class = htonl (delta->ac);
833 GNUNET_memcpy (&msg[1],
836 GNUNET_MQ_send (ch->mq,
842 * Notify all clients about a change in the list
843 * of addresses this peer has.
845 * @param delta the entry in the list that changed
846 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
849 notify_clients (struct LocalAddressList *delta,
852 for (struct ClientHandle *ch = ch_head;
857 struct sockaddr_in v4;
858 struct sockaddr_in6 v6;
860 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
865 alen = sizeof (struct sockaddr_in);
869 for (unsigned int i=0;i<ch->num_addrs;i++)
871 const struct sockaddr_in *c4;
873 if (AF_INET != ch->addrs[i]->sa_family)
874 continue; /* IPv4 not relevant */
875 c4 = (const struct sockaddr_in *) ch->addrs[i];
876 v4.sin_port = c4->sin_port;
877 notify_client (delta,
885 alen = sizeof (struct sockaddr_in6);
889 for (unsigned int i=0;i<ch->num_addrs;i++)
891 const struct sockaddr_in6 *c6;
893 if (AF_INET6 != ch->addrs[i]->sa_family)
894 continue; /* IPv4 not relevant */
895 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
896 v6.sin6_port = c6->sin6_port;
897 notify_client (delta,
913 * Task we run periodically to scan for network interfaces.
920 struct IfcProcContext ifc_ctx;
923 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
929 GNUNET_OS_network_interfaces_list (&ifc_proc,
931 for (struct LocalAddressList *lal = lal_head;
936 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
940 if ( (pos->af == lal->af) &&
941 (0 == memcmp (&lal->addr,
944 ? sizeof (struct sockaddr_in)
945 : sizeof (struct sockaddr_in6))) )
948 if (GNUNET_NO == found)
953 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
958 for (struct LocalAddressList *lal = lal_head;
962 if ( (pos->af == lal->af) &&
963 (0 == memcmp (&lal->addr,
966 ? sizeof (struct sockaddr_in)
967 : sizeof (struct sockaddr_in6))) )
970 if (GNUNET_NO == found)
976 lal_head = ifc_ctx.lal_head;
977 lal_tail = ifc_ctx.lal_tail;
982 * Handle network size estimate clients.
985 * @param c configuration to use
986 * @param service the initialized service
990 const struct GNUNET_CONFIGURATION_Handle *c,
991 struct GNUNET_SERVICE_Handle *service)
994 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
996 stats = GNUNET_STATISTICS_create ("nat",
998 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1004 * Callback called when a client connects to the service.
1006 * @param cls closure for the service
1007 * @param c the new client that connected to the service
1008 * @param mq the message queue used to send messages to the client
1009 * @return a `struct ClientHandle`
1012 client_connect_cb (void *cls,
1013 struct GNUNET_SERVICE_Client *c,
1014 struct GNUNET_MQ_Handle *mq)
1016 struct ClientHandle *ch;
1018 ch = GNUNET_new (struct ClientHandle);
1021 GNUNET_CONTAINER_DLL_insert (ch_head,
1029 * Callback called when a client disconnected from the service
1031 * @param cls closure for the service
1032 * @param c the client that disconnected
1033 * @param internal_cls a `struct ClientHandle *`
1036 client_disconnect_cb (void *cls,
1037 struct GNUNET_SERVICE_Client *c,
1040 struct ClientHandle *ch = internal_cls;
1042 GNUNET_CONTAINER_DLL_remove (ch_head,
1045 for (unsigned int i=0;i<ch->num_addrs;i++)
1046 GNUNET_free_non_null (ch->addrs[i]);
1047 GNUNET_free_non_null (ch->addrs);
1053 * Define "main" method using service macro.
1057 GNUNET_SERVICE_OPTION_NONE,
1060 &client_disconnect_cb,
1062 GNUNET_MQ_hd_var_size (register,
1063 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1064 struct GNUNET_NAT_RegisterMessage,
1066 GNUNET_MQ_hd_var_size (stun,
1067 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1068 struct GNUNET_NAT_HandleStunMessage,
1070 GNUNET_MQ_hd_var_size (request_connection_reversal,
1071 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1072 struct GNUNET_NAT_RequestConnectionReversalMessage,
1074 GNUNET_MQ_hd_fixed_size (test,
1075 GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
1076 struct GNUNET_NAT_RequestTestMessage,
1078 GNUNET_MQ_hd_var_size (autoconfig_request,
1079 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1080 struct GNUNET_NAT_AutoconfigRequestMessage,
1082 GNUNET_MQ_handler_end ());
1085 #if defined(LINUX) && defined(__GLIBC__)
1089 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1091 void __attribute__ ((constructor))
1092 GNUNET_ARM_memory_init ()
1094 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1095 mallopt (M_TOP_PAD, 1 * 1024);
1100 /* end of gnunet-service-nat.c */