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
136 * Handle to our current configuration.
138 static const struct GNUNET_CONFIGURATION_Handle *cfg;
141 * Handle to the statistics service.
143 static struct GNUNET_STATISTICS_Handle *stats;
146 * Task scheduled to periodically scan our network interfaces.
148 static struct GNUNET_SCHEDULER_Task *scan_task;
151 * Head of client DLL.
153 static struct ClientHandle *ch_head;
156 * Tail of client DLL.
158 static struct ClientHandle *ch_tail;
161 * Head of DLL of local addresses.
163 static struct LocalAddressList *lal_head;
166 * Tail of DLL of local addresses.
168 static struct LocalAddressList *lal_tail;
172 * Free the DLL starting at #lal_head.
177 struct LocalAddressList *lal;
179 while (NULL != (lal = lal_head))
181 GNUNET_CONTAINER_DLL_remove (lal_head,
190 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
193 * @param cls client who sent the message
194 * @param message the message received
195 * @return #GNUNET_OK if message is well-formed
198 check_register (void *cls,
199 const struct GNUNET_NAT_RegisterMessage *message)
201 uint16_t num_addrs = ntohs (message->num_addrs);
202 const char *off = (const char *) &message[1];
203 size_t left = ntohs (message->header.size) - sizeof (*message);
205 for (unsigned int i=0;i<num_addrs;i++)
208 const struct sockaddr *sa = (const struct sockaddr *) off;
210 if (sizeof (sa_family_t) > left)
213 return GNUNET_SYSERR;
215 switch (sa->sa_family)
218 alen = sizeof (struct sockaddr_in);
221 alen = sizeof (struct sockaddr_in6);
225 alen = sizeof (struct sockaddr_un);
230 return GNUNET_SYSERR;
235 return GNUNET_SYSERR;
243 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
244 * We remember the client for updates upon future NAT events.
246 * @param cls client who sent the message
247 * @param message the message received
250 handle_register (void *cls,
251 const struct GNUNET_NAT_RegisterMessage *message)
253 struct ClientHandle *ch = cls;
257 if ( (0 != ch->proto) ||
258 (NULL != ch->addrs) )
260 /* double registration not allowed */
262 GNUNET_SERVICE_client_drop (ch->client);
265 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
266 "Received REGISTER message from client\n");
267 ch->flags = message->flags;
268 ch->proto = message->proto;
269 ch->adv_port = ntohs (message->adv_port);
270 ch->num_addrs = ntohs (message->adv_port);
271 ch->addrs = GNUNET_new_array (ch->num_addrs,
273 left = ntohs (message->header.size) - sizeof (*message);
274 off = (const char *) &message[1];
275 for (unsigned int i=0;i<ch->num_addrs;i++)
278 const struct sockaddr *sa = (const struct sockaddr *) off;
280 if (sizeof (sa_family_t) > left)
283 GNUNET_SERVICE_client_drop (ch->client);
286 switch (sa->sa_family)
289 alen = sizeof (struct sockaddr_in);
292 alen = sizeof (struct sockaddr_in6);
296 alen = sizeof (struct sockaddr_un);
301 GNUNET_SERVICE_client_drop (ch->client);
304 GNUNET_assert (alen <= left);
305 ch->addrs[i] = GNUNET_malloc (alen);
306 GNUNET_memcpy (ch->addrs[i],
311 GNUNET_SERVICE_client_continue (ch->client);
316 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
319 * @param cls client who sent the message
320 * @param message the message received
321 * @return #GNUNET_OK if message is well-formed
324 check_stun (void *cls,
325 const struct GNUNET_NAT_HandleStunMessage *message)
327 size_t sa_len = ntohs (message->sender_addr_size);
328 size_t expect = sa_len + ntohs (message->payload_size);
330 if (ntohs (message->header.size) - sizeof (*message) != expect)
333 return GNUNET_SYSERR;
335 if (sa_len < sizeof (sa_family_t))
338 return GNUNET_SYSERR;
345 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
348 * @param cls client who sent the message
349 * @param message the message received
352 handle_stun (void *cls,
353 const struct GNUNET_NAT_HandleStunMessage *message)
355 struct ClientHandle *ch = cls;
356 const char *buf = (const char *) &message[1];
357 const struct sockaddr *sa;
362 sa_len = ntohs (message->sender_addr_size);
363 payload_size = ntohs (message->payload_size);
364 sa = (const struct sockaddr *) &buf[0];
365 payload = (const struct sockaddr *) &buf[sa_len];
366 switch (sa->sa_family)
369 if (sa_len != sizeof (struct sockaddr_in))
372 GNUNET_SERVICE_client_drop (ch->client);
377 if (sa_len != sizeof (struct sockaddr_in6))
380 GNUNET_SERVICE_client_drop (ch->client);
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Received HANDLE_STUN message from client\n");
387 // FIXME: actually handle STUN request!
388 GNUNET_SERVICE_client_continue (ch->client);
394 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
397 * @param cls client who sent the message
398 * @param message the message received
399 * @return #GNUNET_OK if message is well-formed
402 check_request_connection_reversal (void *cls,
403 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
407 expect = ntohs (message->local_addr_size)
408 + ntohs (message->remote_addr_size);
409 if (ntohs (message->header.size) - sizeof (*message) != expect)
412 return GNUNET_SYSERR;
419 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
420 * message from client.
422 * @param cls client who sent the message
423 * @param message the message received
426 handle_request_connection_reversal (void *cls,
427 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
429 struct ClientHandle *ch = cls;
430 const char *buf = (const char *) &message[1];
431 size_t local_sa_len = ntohs (message->local_addr_size);
432 size_t remote_sa_len = ntohs (message->remote_addr_size);
433 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
434 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437 "Received REQUEST CONNECTION REVERSAL message from client\n");
438 switch (local_sa->sa_family)
441 if (local_sa_len != sizeof (struct sockaddr_in))
444 GNUNET_SERVICE_client_drop (ch->client);
449 if (local_sa_len != sizeof (struct sockaddr_in6))
452 GNUNET_SERVICE_client_drop (ch->client);
458 GNUNET_SERVICE_client_drop (ch->client);
461 switch (remote_sa->sa_family)
464 if (remote_sa_len != sizeof (struct sockaddr_in))
467 GNUNET_SERVICE_client_drop (ch->client);
472 if (remote_sa_len != sizeof (struct sockaddr_in6))
475 GNUNET_SERVICE_client_drop (ch->client);
481 GNUNET_SERVICE_client_drop (ch->client);
484 /* FIXME: actually run the logic! */
486 GNUNET_SERVICE_client_continue (ch->client);
491 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
494 * @param cls client who sent the message
495 * @param message the message received
498 handle_test (void *cls,
499 const struct GNUNET_NAT_RequestTestMessage *message)
501 struct ClientHandle *ch = cls;
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Received REQUEST_TEST message from client\n");
505 GNUNET_SERVICE_client_continue (ch->client);
510 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
513 * @param cls client who sent the message
514 * @param message the message received
515 * @return #GNUNET_OK if message is well-formed
518 check_autoconfig_request (void *cls,
519 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
521 return GNUNET_OK; /* checked later */
526 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
529 * @param cls client who sent the message
530 * @param message the message received
533 handle_autoconfig_request (void *cls,
534 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
536 struct ClientHandle *ch = cls;
537 size_t left = ntohs (message->header.size);
538 struct GNUNET_CONFIGURATION_Handle *c;
540 c = GNUNET_CONFIGURATION_create ();
542 GNUNET_CONFIGURATION_deserialize (c,
543 (const char *) &message[1],
548 GNUNET_SERVICE_client_drop (ch->client);
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
552 "Received REQUEST_AUTO_CONFIG message from client\n");
553 // FIXME: actually handle request...
554 GNUNET_CONFIGURATION_destroy (c);
555 GNUNET_SERVICE_client_continue (ch->client);
560 * Task run during shutdown.
565 shutdown_task (void *cls)
567 if (NULL != scan_task)
569 GNUNET_SCHEDULER_cancel (scan_task);
574 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
582 * Closure for #ifc_proc.
584 struct IfcProcContext
588 * Head of DLL of local addresses.
590 struct LocalAddressList *lal_head;
593 * Tail of DLL of local addresses.
595 struct LocalAddressList *lal_tail;
601 * Callback function invoked for each interface found. Adds them
602 * to our new address list.
604 * @param cls a `struct IfcProcContext *`
605 * @param name name of the interface (can be NULL for unknown)
606 * @param isDefault is this presumably the default interface
607 * @param addr address of this interface (can be NULL for unknown or unassigned)
608 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
609 * @param netmask the network mask (can be NULL for unknown or unassigned)
610 * @param addrlen length of the address
611 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
617 const struct sockaddr *addr,
618 const struct sockaddr *broadcast_addr,
619 const struct sockaddr *netmask,
622 struct IfcProcContext *ifc_ctx = cls;
623 struct LocalAddressList *lal;
627 switch (addr->sa_family)
630 alen = sizeof (struct in_addr);
631 ip = &((const struct sockaddr_in *) addr)->sin_addr;
634 alen = sizeof (struct in6_addr);
635 ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
646 lal = GNUNET_malloc (sizeof (*lal) + alen);
647 lal->af = addr->sa_family;
649 GNUNET_memcpy (&lal[1],
652 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
660 * Task we run periodically to scan for network interfaces.
667 struct IfcProcContext ifc_ctx;
669 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
675 GNUNET_OS_network_interfaces_list (&ifc_proc,
677 /* FIXME: notify clients of changes in lal-DLL */
679 lal_head = ifc_ctx.lal_head;
680 lal_tail = ifc_ctx.lal_tail;
685 * Handle network size estimate clients.
688 * @param c configuration to use
689 * @param service the initialized service
693 const struct GNUNET_CONFIGURATION_Handle *c,
694 struct GNUNET_SERVICE_Handle *service)
697 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
699 stats = GNUNET_STATISTICS_create ("nat",
701 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
707 * Callback called when a client connects to the service.
709 * @param cls closure for the service
710 * @param c the new client that connected to the service
711 * @param mq the message queue used to send messages to the client
712 * @return a `struct ClientHandle`
715 client_connect_cb (void *cls,
716 struct GNUNET_SERVICE_Client *c,
717 struct GNUNET_MQ_Handle *mq)
719 struct ClientHandle *ch;
721 ch = GNUNET_new (struct ClientHandle);
724 GNUNET_CONTAINER_DLL_insert (ch_head,
732 * Callback called when a client disconnected from the service
734 * @param cls closure for the service
735 * @param c the client that disconnected
736 * @param internal_cls a `struct ClientHandle *`
739 client_disconnect_cb (void *cls,
740 struct GNUNET_SERVICE_Client *c,
743 struct ClientHandle *ch = internal_cls;
745 GNUNET_CONTAINER_DLL_remove (ch_head,
748 for (unsigned int i=0;i<ch->num_addrs;i++)
749 GNUNET_free_non_null (ch->addrs[i]);
750 GNUNET_free_non_null (ch->addrs);
756 * Define "main" method using service macro.
760 GNUNET_SERVICE_OPTION_NONE,
763 &client_disconnect_cb,
765 GNUNET_MQ_hd_var_size (register,
766 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
767 struct GNUNET_NAT_RegisterMessage,
769 GNUNET_MQ_hd_var_size (stun,
770 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
771 struct GNUNET_NAT_HandleStunMessage,
773 GNUNET_MQ_hd_var_size (request_connection_reversal,
774 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
775 struct GNUNET_NAT_RequestConnectionReversalMessage,
777 GNUNET_MQ_hd_fixed_size (test,
778 GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
779 struct GNUNET_NAT_RequestTestMessage,
781 GNUNET_MQ_hd_var_size (autoconfig_request,
782 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
783 struct GNUNET_NAT_AutoconfigRequestMessage,
785 GNUNET_MQ_handler_end ());
788 #if defined(LINUX) && defined(__GLIBC__)
792 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
794 void __attribute__ ((constructor))
795 GNUNET_ARM_memory_init ()
797 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
798 mallopt (M_TOP_PAD, 1 * 1024);
803 /* end of gnunet-service-nat.c */