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"
42 * How often should we ask the OS about a list of active
45 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
49 * Internal data structure we track for each of our clients.
57 struct ClientHandle *next;
62 struct ClientHandle *prev;
65 * Underlying handle for this client with the service.
67 struct GNUNET_SERVICE_Client *client;
70 * Message queue for communicating with the client.
72 struct GNUNET_MQ_Handle *mq;
75 * Array of addresses used by the service.
77 struct sockaddr **addrs;
80 * What does this client care about?
82 enum GNUNET_NAT_RegisterFlags flags;
85 * Port we would like as we are configured to use this one for
86 * advertising (in addition to the one we are binding to).
91 * Number of addresses that this service is bound to.
96 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
104 * List of local addresses this system has.
106 struct LocalAddressList
109 * This is a linked list.
111 struct LocalAddressList *next;
116 struct LocalAddressList *prev;
119 * The address itself (i.e. `struct in_addr` or `struct in6_addr`,
120 * in the respective byte order). Allocated at the end of this
131 * What type of address is this?
133 enum GNUNET_NAT_AddressClass ac;
141 * Handle to our current configuration.
143 static const struct GNUNET_CONFIGURATION_Handle *cfg;
146 * Handle to the statistics service.
148 static struct GNUNET_STATISTICS_Handle *stats;
151 * Task scheduled to periodically scan our network interfaces.
153 static struct GNUNET_SCHEDULER_Task *scan_task;
156 * Head of client DLL.
158 static struct ClientHandle *ch_head;
161 * Tail of client DLL.
163 static struct ClientHandle *ch_tail;
166 * Head of DLL of local addresses.
168 static struct LocalAddressList *lal_head;
171 * Tail of DLL of local addresses.
173 static struct LocalAddressList *lal_tail;
177 * Free the DLL starting at #lal_head.
182 struct LocalAddressList *lal;
184 while (NULL != (lal = lal_head))
186 GNUNET_CONTAINER_DLL_remove (lal_head,
195 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
198 * @param cls client who sent the message
199 * @param message the message received
200 * @return #GNUNET_OK if message is well-formed
203 check_register (void *cls,
204 const struct GNUNET_NAT_RegisterMessage *message)
206 uint16_t num_addrs = ntohs (message->num_addrs);
207 const char *off = (const char *) &message[1];
208 size_t left = ntohs (message->header.size) - sizeof (*message);
210 for (unsigned int i=0;i<num_addrs;i++)
213 const struct sockaddr *sa = (const struct sockaddr *) off;
215 if (sizeof (sa_family_t) > left)
218 return GNUNET_SYSERR;
220 switch (sa->sa_family)
223 alen = sizeof (struct sockaddr_in);
226 alen = sizeof (struct sockaddr_in6);
230 alen = sizeof (struct sockaddr_un);
235 return GNUNET_SYSERR;
240 return GNUNET_SYSERR;
248 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
249 * We remember the client for updates upon future NAT events.
251 * @param cls client who sent the message
252 * @param message the message received
255 handle_register (void *cls,
256 const struct GNUNET_NAT_RegisterMessage *message)
258 struct ClientHandle *ch = cls;
262 if ( (0 != ch->proto) ||
263 (NULL != ch->addrs) )
265 /* double registration not allowed */
267 GNUNET_SERVICE_client_drop (ch->client);
270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271 "Received REGISTER message from client\n");
272 ch->flags = message->flags;
273 ch->proto = message->proto;
274 ch->adv_port = ntohs (message->adv_port);
275 ch->num_addrs = ntohs (message->adv_port);
276 ch->addrs = GNUNET_new_array (ch->num_addrs,
278 left = ntohs (message->header.size) - sizeof (*message);
279 off = (const char *) &message[1];
280 for (unsigned int i=0;i<ch->num_addrs;i++)
283 const struct sockaddr *sa = (const struct sockaddr *) off;
285 if (sizeof (sa_family_t) > left)
288 GNUNET_SERVICE_client_drop (ch->client);
291 switch (sa->sa_family)
294 alen = sizeof (struct sockaddr_in);
297 alen = sizeof (struct sockaddr_in6);
301 alen = sizeof (struct sockaddr_un);
306 GNUNET_SERVICE_client_drop (ch->client);
309 GNUNET_assert (alen <= left);
310 ch->addrs[i] = GNUNET_malloc (alen);
311 GNUNET_memcpy (ch->addrs[i],
316 GNUNET_SERVICE_client_continue (ch->client);
321 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
324 * @param cls client who sent the message
325 * @param message the message received
326 * @return #GNUNET_OK if message is well-formed
329 check_stun (void *cls,
330 const struct GNUNET_NAT_HandleStunMessage *message)
332 size_t sa_len = ntohs (message->sender_addr_size);
333 size_t expect = sa_len + ntohs (message->payload_size);
335 if (ntohs (message->header.size) - sizeof (*message) != expect)
338 return GNUNET_SYSERR;
340 if (sa_len < sizeof (sa_family_t))
343 return GNUNET_SYSERR;
350 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
353 * @param cls client who sent the message
354 * @param message the message received
357 handle_stun (void *cls,
358 const struct GNUNET_NAT_HandleStunMessage *message)
360 struct ClientHandle *ch = cls;
361 const char *buf = (const char *) &message[1];
362 const struct sockaddr *sa;
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");
392 // FIXME: actually handle STUN request!
393 GNUNET_SERVICE_client_continue (ch->client);
399 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
402 * @param cls client who sent the message
403 * @param message the message received
404 * @return #GNUNET_OK if message is well-formed
407 check_request_connection_reversal (void *cls,
408 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
412 expect = ntohs (message->local_addr_size)
413 + ntohs (message->remote_addr_size);
414 if (ntohs (message->header.size) - sizeof (*message) != expect)
417 return GNUNET_SYSERR;
424 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
425 * message from client.
427 * @param cls client who sent the message
428 * @param message the message received
431 handle_request_connection_reversal (void *cls,
432 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
434 struct ClientHandle *ch = cls;
435 const char *buf = (const char *) &message[1];
436 size_t local_sa_len = ntohs (message->local_addr_size);
437 size_t remote_sa_len = ntohs (message->remote_addr_size);
438 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
439 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 "Received REQUEST CONNECTION REVERSAL message from client\n");
443 switch (local_sa->sa_family)
446 if (local_sa_len != sizeof (struct sockaddr_in))
449 GNUNET_SERVICE_client_drop (ch->client);
454 if (local_sa_len != sizeof (struct sockaddr_in6))
457 GNUNET_SERVICE_client_drop (ch->client);
463 GNUNET_SERVICE_client_drop (ch->client);
466 switch (remote_sa->sa_family)
469 if (remote_sa_len != sizeof (struct sockaddr_in))
472 GNUNET_SERVICE_client_drop (ch->client);
477 if (remote_sa_len != sizeof (struct sockaddr_in6))
480 GNUNET_SERVICE_client_drop (ch->client);
486 GNUNET_SERVICE_client_drop (ch->client);
489 /* FIXME: actually run the logic! */
491 GNUNET_SERVICE_client_continue (ch->client);
496 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
499 * @param cls client who sent the message
500 * @param message the message received
503 handle_test (void *cls,
504 const struct GNUNET_NAT_RequestTestMessage *message)
506 struct ClientHandle *ch = cls;
508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509 "Received REQUEST_TEST message from client\n");
510 /* FIXME: actually process test request */
511 GNUNET_SERVICE_client_continue (ch->client);
516 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
519 * @param cls client who sent the message
520 * @param message the message received
521 * @return #GNUNET_OK if message is well-formed
524 check_autoconfig_request (void *cls,
525 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
527 return GNUNET_OK; /* checked later */
532 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
535 * @param cls client who sent the message
536 * @param message the message received
539 handle_autoconfig_request (void *cls,
540 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
542 struct ClientHandle *ch = cls;
543 size_t left = ntohs (message->header.size);
544 struct GNUNET_CONFIGURATION_Handle *c;
546 c = GNUNET_CONFIGURATION_create ();
548 GNUNET_CONFIGURATION_deserialize (c,
549 (const char *) &message[1],
554 GNUNET_SERVICE_client_drop (ch->client);
557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558 "Received REQUEST_AUTO_CONFIG message from client\n");
559 // FIXME: actually handle request...
560 GNUNET_CONFIGURATION_destroy (c);
561 GNUNET_SERVICE_client_continue (ch->client);
566 * Task run during shutdown.
571 shutdown_task (void *cls)
573 if (NULL != scan_task)
575 GNUNET_SCHEDULER_cancel (scan_task);
580 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
588 * Closure for #ifc_proc.
590 struct IfcProcContext
594 * Head of DLL of local addresses.
596 struct LocalAddressList *lal_head;
599 * Tail of DLL of local addresses.
601 struct LocalAddressList *lal_tail;
607 * Callback function invoked for each interface found. Adds them
608 * to our new address list.
610 * @param cls a `struct IfcProcContext *`
611 * @param name name of the interface (can be NULL for unknown)
612 * @param isDefault is this presumably the default interface
613 * @param addr address of this interface (can be NULL for unknown or unassigned)
614 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
615 * @param netmask the network mask (can be NULL for unknown or unassigned)
616 * @param addrlen length of the address
617 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
623 const struct sockaddr *addr,
624 const struct sockaddr *broadcast_addr,
625 const struct sockaddr *netmask,
628 struct IfcProcContext *ifc_ctx = cls;
629 struct LocalAddressList *lal;
633 switch (addr->sa_family)
636 alen = sizeof (struct in_addr);
637 ip = &((const struct sockaddr_in *) addr)->sin_addr;
640 alen = sizeof (struct in6_addr);
641 ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
652 lal = GNUNET_malloc (sizeof (*lal) + alen);
653 lal->af = addr->sa_family;
655 GNUNET_memcpy (&lal[1],
658 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
666 * Notify all clients about a change in the list
667 * of addresses this peer has.
669 * @param delta the entry in the list that changed
670 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
673 notify_clients (struct LocalAddressList *delta,
676 for (struct ClientHandle *ch = ch_head;
680 struct GNUNET_MQ_Envelope *env;
681 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
683 struct sockaddr_in v4;
684 struct sockaddr_in6 v6;
687 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
692 alen = sizeof (struct sockaddr_in);
694 memset (&v4, 0, sizeof (v4));
695 v4.sin_family = AF_INET;
696 GNUNET_memcpy (&v4.sin_addr,
698 sizeof (struct in_addr));
699 /* FIXME: set port */
702 alen = sizeof (struct sockaddr_in6);
704 memset (&v6, 0, sizeof (v6));
705 v6.sin6_family = AF_INET6;
706 GNUNET_memcpy (&v6.sin6_addr,
708 sizeof (struct in6_addr));
709 /* FIXME: set port, and link/interface! */
715 env = GNUNET_MQ_msg_extra (msg,
717 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
718 msg->add_remove = htonl (add);
719 msg->addr_class = htonl (delta->ac);
720 GNUNET_memcpy (&msg[1],
723 GNUNET_MQ_send (ch->mq,
730 * Task we run periodically to scan for network interfaces.
737 struct IfcProcContext ifc_ctx;
740 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
746 GNUNET_OS_network_interfaces_list (&ifc_proc,
748 for (struct LocalAddressList *lal = lal_head;
753 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
757 if ( (pos->af == lal->af) &&
758 (0 == memcmp (lal->addr,
761 ? sizeof (struct in_addr)
762 : sizeof (struct in6_addr))) )
765 if (GNUNET_NO == found)
770 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
775 for (struct LocalAddressList *lal = lal_head;
779 if ( (pos->af == lal->af) &&
780 (0 == memcmp (lal->addr,
783 ? sizeof (struct in_addr)
784 : sizeof (struct in6_addr))) )
787 if (GNUNET_NO == found)
793 lal_head = ifc_ctx.lal_head;
794 lal_tail = ifc_ctx.lal_tail;
799 * Handle network size estimate clients.
802 * @param c configuration to use
803 * @param service the initialized service
807 const struct GNUNET_CONFIGURATION_Handle *c,
808 struct GNUNET_SERVICE_Handle *service)
811 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
813 stats = GNUNET_STATISTICS_create ("nat",
815 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
821 * Callback called when a client connects to the service.
823 * @param cls closure for the service
824 * @param c the new client that connected to the service
825 * @param mq the message queue used to send messages to the client
826 * @return a `struct ClientHandle`
829 client_connect_cb (void *cls,
830 struct GNUNET_SERVICE_Client *c,
831 struct GNUNET_MQ_Handle *mq)
833 struct ClientHandle *ch;
835 ch = GNUNET_new (struct ClientHandle);
838 GNUNET_CONTAINER_DLL_insert (ch_head,
846 * Callback called when a client disconnected from the service
848 * @param cls closure for the service
849 * @param c the client that disconnected
850 * @param internal_cls a `struct ClientHandle *`
853 client_disconnect_cb (void *cls,
854 struct GNUNET_SERVICE_Client *c,
857 struct ClientHandle *ch = internal_cls;
859 GNUNET_CONTAINER_DLL_remove (ch_head,
862 for (unsigned int i=0;i<ch->num_addrs;i++)
863 GNUNET_free_non_null (ch->addrs[i]);
864 GNUNET_free_non_null (ch->addrs);
870 * Define "main" method using service macro.
874 GNUNET_SERVICE_OPTION_NONE,
877 &client_disconnect_cb,
879 GNUNET_MQ_hd_var_size (register,
880 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
881 struct GNUNET_NAT_RegisterMessage,
883 GNUNET_MQ_hd_var_size (stun,
884 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
885 struct GNUNET_NAT_HandleStunMessage,
887 GNUNET_MQ_hd_var_size (request_connection_reversal,
888 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
889 struct GNUNET_NAT_RequestConnectionReversalMessage,
891 GNUNET_MQ_hd_fixed_size (test,
892 GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
893 struct GNUNET_NAT_RequestTestMessage,
895 GNUNET_MQ_hd_var_size (autoconfig_request,
896 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
897 struct GNUNET_NAT_AutoconfigRequestMessage,
899 GNUNET_MQ_handler_end ());
902 #if defined(LINUX) && defined(__GLIBC__)
906 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
908 void __attribute__ ((constructor))
909 GNUNET_ARM_memory_init ()
911 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
912 mallopt (M_TOP_PAD, 1 * 1024);
917 /* end of gnunet-service-nat.c */