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_helper.h"
49 * How often should we ask the OS about a list of active
52 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
56 * Internal data structure we track for each of our clients.
64 struct ClientHandle *next;
69 struct ClientHandle *prev;
72 * Underlying handle for this client with the service.
74 struct GNUNET_SERVICE_Client *client;
77 * Message queue for communicating with the client.
79 struct GNUNET_MQ_Handle *mq;
82 * Array of addresses used by the service.
84 struct sockaddr **addrs;
87 * What does this client care about?
89 enum GNUNET_NAT_RegisterFlags flags;
92 * Is any of the @e addrs in a reserved subnet for NAT?
97 * Port we would like as we are configured to use this one for
98 * advertising (in addition to the one we are binding to).
103 * Number of addresses that this service is bound to.
108 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
116 * List of local addresses this system has.
118 struct LocalAddressList
121 * This is a linked list.
123 struct LocalAddressList *next;
128 struct LocalAddressList *prev;
131 * The address itself (i.e. `struct sockaddr_in` or `struct
132 * sockaddr_in6`, in the respective byte order).
134 struct sockaddr_storage addr;
142 * What type of address is this?
144 enum GNUNET_NAT_AddressClass ac;
150 * External IP address as given to us via some STUN server.
152 struct StunExternalIP
157 struct StunExternalIP *next;
162 struct StunExternalIP *prev;
165 * Task we run to remove this entry when it is stale.
167 struct GNUNET_SCHEDULER_Task *timeout_task;
170 * Our external IP address as reported by the
173 struct sockaddr_in external_addr;
176 * Address of the reporting STUN server. Used to
177 * detect when a STUN server changes its opinion
178 * to more quickly remove stale results.
180 struct sockaddr_storage stun_server_addr;
183 * Number of bytes used in @e stun_server_addr.
185 size_t stun_server_addr_len;
190 * Timeout to use when STUN data is considered stale.
192 static struct GNUNET_TIME_Relative stun_stale_timeout;
195 * Handle to our current configuration.
197 static const struct GNUNET_CONFIGURATION_Handle *cfg;
200 * Handle to the statistics service.
202 static struct GNUNET_STATISTICS_Handle *stats;
205 * Task scheduled to periodically scan our network interfaces.
207 static struct GNUNET_SCHEDULER_Task *scan_task;
210 * Head of client DLL.
212 static struct ClientHandle *ch_head;
215 * Tail of client DLL.
217 static struct ClientHandle *ch_tail;
220 * Head of DLL of local addresses.
222 static struct LocalAddressList *lal_head;
225 * Tail of DLL of local addresses.
227 static struct LocalAddressList *lal_tail;
232 static struct StunExternalIP *se_head;
237 static struct StunExternalIP *se_tail;
241 * Free the DLL starting at #lal_head.
246 struct LocalAddressList *lal;
248 while (NULL != (lal = lal_head))
250 GNUNET_CONTAINER_DLL_remove (lal_head,
259 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
262 * @param cls client who sent the message
263 * @param message the message received
264 * @return #GNUNET_OK if message is well-formed
267 check_register (void *cls,
268 const struct GNUNET_NAT_RegisterMessage *message)
270 uint16_t num_addrs = ntohs (message->num_addrs);
271 const char *off = (const char *) &message[1];
272 size_t left = ntohs (message->header.size) - sizeof (*message);
274 for (unsigned int i=0;i<num_addrs;i++)
277 const struct sockaddr *sa = (const struct sockaddr *) off;
279 if (sizeof (sa_family_t) > left)
282 return GNUNET_SYSERR;
284 switch (sa->sa_family)
287 alen = sizeof (struct sockaddr_in);
290 alen = sizeof (struct sockaddr_in6);
294 alen = sizeof (struct sockaddr_un);
299 return GNUNET_SYSERR;
304 return GNUNET_SYSERR;
312 * Check if @a ip is in @a network with @a bits netmask.
314 * @param network to test
315 * @param ip IP address to test
316 * @param bits bitmask for the network
317 * @return #GNUNET_YES if @a ip is in @a network
320 match_ipv4 (const char *network,
321 const struct in_addr *ip,
328 GNUNET_assert (1 == inet_pton (AF_INET,
331 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
336 * Check if @a ip is in @a network with @a bits netmask.
338 * @param network to test
339 * @param ip IP address to test
340 * @param bits bitmask for the network
341 * @return #GNUNET_YES if @a ip is in @a network
344 match_ipv6 (const char *network,
345 const struct in6_addr *ip,
349 struct in6_addr mask;
354 GNUNET_assert (1 == inet_pton (AF_INET6,
357 memset (&mask, 0, sizeof (mask));
361 mask.s6_addr[off++] = 0xFF;
366 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
369 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
370 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
371 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
378 * Test if the given IPv4 address is in a known range
379 * for private networks.
381 * @param ip address to test
382 * @return #GNUNET_YES if @a ip is in a NAT range
385 is_nat_v4 (const struct in_addr *ip)
388 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
389 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
390 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
391 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
392 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
397 * Test if the given IPv6 address is in a known range
398 * for private networks.
400 * @param ip address to test
401 * @return #GNUNET_YES if @a ip is in a NAT range
404 is_nat_v6 (const struct in6_addr *ip)
407 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
408 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
409 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
414 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
415 * We remember the client for updates upon future NAT events.
417 * @param cls client who sent the message
418 * @param message the message received
421 handle_register (void *cls,
422 const struct GNUNET_NAT_RegisterMessage *message)
424 struct ClientHandle *ch = cls;
428 if ( (0 != ch->proto) ||
429 (NULL != ch->addrs) )
431 /* double registration not allowed */
433 GNUNET_SERVICE_client_drop (ch->client);
436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
437 "Received REGISTER message from client\n");
438 ch->flags = message->flags;
439 ch->proto = message->proto;
440 ch->adv_port = ntohs (message->adv_port);
441 ch->num_addrs = ntohs (message->adv_port);
442 ch->addrs = GNUNET_new_array (ch->num_addrs,
444 left = ntohs (message->header.size) - sizeof (*message);
445 off = (const char *) &message[1];
446 for (unsigned int i=0;i<ch->num_addrs;i++)
449 const struct sockaddr *sa = (const struct sockaddr *) off;
451 if (sizeof (sa_family_t) > left)
454 GNUNET_SERVICE_client_drop (ch->client);
457 switch (sa->sa_family)
461 const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
463 alen = sizeof (struct sockaddr_in);
464 if (is_nat_v4 (&s4->sin_addr))
465 ch->natted_address = GNUNET_YES;
470 const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
472 alen = sizeof (struct sockaddr_in6);
473 if (is_nat_v6 (&s6->sin6_addr))
474 ch->natted_address = GNUNET_YES;
479 alen = sizeof (struct sockaddr_un);
484 GNUNET_SERVICE_client_drop (ch->client);
487 GNUNET_assert (alen <= left);
488 ch->addrs[i] = GNUNET_malloc (alen);
489 GNUNET_memcpy (ch->addrs[i],
494 GNUNET_SERVICE_client_continue (ch->client);
499 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
502 * @param cls client who sent the message
503 * @param message the message received
504 * @return #GNUNET_OK if message is well-formed
507 check_stun (void *cls,
508 const struct GNUNET_NAT_HandleStunMessage *message)
510 size_t sa_len = ntohs (message->sender_addr_size);
511 size_t expect = sa_len + ntohs (message->payload_size);
513 if (ntohs (message->header.size) - sizeof (*message) != expect)
516 return GNUNET_SYSERR;
518 if (sa_len < sizeof (sa_family_t))
521 return GNUNET_SYSERR;
528 * Notify all clients about our external IP address
529 * as reported by the STUN server.
531 * @param ip the external IP
532 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
535 notify_clients_stun_change (const struct sockaddr_in *ip,
538 for (struct ClientHandle *ch = ch_head;
542 struct sockaddr_in v4;
543 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
544 struct GNUNET_MQ_Envelope *env;
546 if (! ch->natted_address)
549 v4.sin_port = htons (ch->adv_port);
550 env = GNUNET_MQ_msg_extra (msg,
552 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
553 msg->add_remove = htonl ((int32_t) add);
554 msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN |
555 GNUNET_NAT_AC_GLOBAL);
556 GNUNET_memcpy (&msg[1],
559 GNUNET_MQ_send (ch->mq,
566 * Function to be called when we decide that an
567 * external IP address as told to us by a STUN
568 * server has gone stale.
570 * @param cls the `struct StunExternalIP` to drop
573 stun_ip_timeout (void *cls)
575 struct StunExternalIP *se = cls;
577 se->timeout_task = NULL;
578 notify_clients_stun_change (&se->external_addr,
580 GNUNET_CONTAINER_DLL_remove (se_head,
588 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
591 * @param cls client who sent the message
592 * @param message the message received
595 handle_stun (void *cls,
596 const struct GNUNET_NAT_HandleStunMessage *message)
598 struct ClientHandle *ch = cls;
599 const char *buf = (const char *) &message[1];
600 const struct sockaddr *sa;
604 struct sockaddr_in external_addr;
606 sa_len = ntohs (message->sender_addr_size);
607 payload_size = ntohs (message->payload_size);
608 sa = (const struct sockaddr *) &buf[0];
609 payload = (const struct sockaddr *) &buf[sa_len];
610 switch (sa->sa_family)
613 if (sa_len != sizeof (struct sockaddr_in))
616 GNUNET_SERVICE_client_drop (ch->client);
621 if (sa_len != sizeof (struct sockaddr_in6))
624 GNUNET_SERVICE_client_drop (ch->client);
629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
630 "Received HANDLE_STUN message from client\n");
632 GNUNET_NAT_stun_handle_packet_ (payload,
636 /* We now know that a server at "sa" claims that
637 we are visible at IP "external_addr".
639 We should (for some fixed period of time) tell
640 all of our clients that listen to a NAT'ed address
641 that they might want to consider the given 'external_ip'
642 as their public IP address (this includes TCP and UDP
643 clients, even if only UDP sends STUN requests).
645 If we do not get a renewal, the "external_addr" should be
646 removed again. The timeout frequency should be configurable
647 (with a sane default), so that the UDP plugin can tell how
648 often to re-request STUN.
650 struct StunExternalIP *se;
652 /* Check if we had a prior response from this STUN server */
653 for (se = se_head; NULL != se; se = se->next)
655 if ( (se->stun_server_addr_len != sa_len) ||
657 &se->stun_server_addr,
659 continue; /* different STUN server */
660 if (0 != memcmp (&external_addr,
662 sizeof (struct sockaddr_in)))
664 /* external IP changed, update! */
665 notify_clients_stun_change (&se->external_addr,
667 se->external_addr = external_addr;
668 notify_clients_stun_change (&se->external_addr,
672 GNUNET_SCHEDULER_cancel (se->timeout_task);
674 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
679 /* STUN server is completely new, create fresh entry */
680 se = GNUNET_new (struct StunExternalIP);
681 se->external_addr = external_addr;
682 GNUNET_memcpy (&se->stun_server_addr,
685 se->stun_server_addr_len = sa_len;
686 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
689 GNUNET_CONTAINER_DLL_insert (se_head,
692 notify_clients_stun_change (&se->external_addr,
695 GNUNET_SERVICE_client_continue (ch->client);
701 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
704 * @param cls client who sent the message
705 * @param message the message received
706 * @return #GNUNET_OK if message is well-formed
709 check_request_connection_reversal (void *cls,
710 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
714 expect = ntohs (message->local_addr_size)
715 + ntohs (message->remote_addr_size);
716 if (ntohs (message->header.size) - sizeof (*message) != expect)
719 return GNUNET_SYSERR;
726 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
727 * message from client.
729 * @param cls client who sent the message
730 * @param message the message received
733 handle_request_connection_reversal (void *cls,
734 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
736 struct ClientHandle *ch = cls;
737 const char *buf = (const char *) &message[1];
738 size_t local_sa_len = ntohs (message->local_addr_size);
739 size_t remote_sa_len = ntohs (message->remote_addr_size);
740 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
741 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
742 const struct sockaddr_in *l4 = NULL;
743 const struct sockaddr_in *r4;
746 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
747 "Received REQUEST CONNECTION REVERSAL message from client\n");
748 switch (local_sa->sa_family)
751 if (local_sa_len != sizeof (struct sockaddr_in))
754 GNUNET_SERVICE_client_drop (ch->client);
757 l4 = (const struct sockaddr_in *) local_sa;
760 if (local_sa_len != sizeof (struct sockaddr_in6))
763 GNUNET_SERVICE_client_drop (ch->client);
766 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
767 _("Connection reversal for IPv6 not supported yet\n"));
772 GNUNET_SERVICE_client_drop (ch->client);
775 switch (remote_sa->sa_family)
778 if (remote_sa_len != sizeof (struct sockaddr_in))
781 GNUNET_SERVICE_client_drop (ch->client);
784 r4 = (const struct sockaddr_in *) remote_sa;
785 ret = GN_request_connection_reversal (&l4->sin_addr,
786 ntohs (l4->sin_port),
790 if (remote_sa_len != sizeof (struct sockaddr_in6))
793 GNUNET_SERVICE_client_drop (ch->client);
796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
797 _("Connection reversal for IPv6 not supported yet\n"));
802 GNUNET_SERVICE_client_drop (ch->client);
805 if (GNUNET_OK != ret)
806 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
807 _("Connection reversal request failed\n"));
808 GNUNET_SERVICE_client_continue (ch->client);
813 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
816 * @param cls client who sent the message
817 * @param message the message received
818 * @return #GNUNET_OK if message is well-formed
821 check_autoconfig_request (void *cls,
822 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
824 return GNUNET_OK; /* checked later */
829 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
832 * @param cls client who sent the message
833 * @param message the message received
836 handle_autoconfig_request (void *cls,
837 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
839 struct ClientHandle *ch = cls;
840 size_t left = ntohs (message->header.size);
841 struct GNUNET_CONFIGURATION_Handle *c;
843 c = GNUNET_CONFIGURATION_create ();
845 GNUNET_CONFIGURATION_deserialize (c,
846 (const char *) &message[1],
851 GNUNET_SERVICE_client_drop (ch->client);
854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855 "Received REQUEST_AUTO_CONFIG message from client\n");
856 // FIXME: actually handle request...
857 GNUNET_CONFIGURATION_destroy (c);
858 GNUNET_SERVICE_client_continue (ch->client);
863 * Task run during shutdown.
868 shutdown_task (void *cls)
870 struct StunExternalIP *se;
872 while (NULL != (se = se_head))
874 GNUNET_CONTAINER_DLL_remove (se_head,
877 GNUNET_SCHEDULER_cancel (se->timeout_task);
880 if (NULL != scan_task)
882 GNUNET_SCHEDULER_cancel (scan_task);
887 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
895 * Closure for #ifc_proc.
897 struct IfcProcContext
901 * Head of DLL of local addresses.
903 struct LocalAddressList *lal_head;
906 * Tail of DLL of local addresses.
908 struct LocalAddressList *lal_tail;
914 * Callback function invoked for each interface found. Adds them
915 * to our new address list.
917 * @param cls a `struct IfcProcContext *`
918 * @param name name of the interface (can be NULL for unknown)
919 * @param isDefault is this presumably the default interface
920 * @param addr address of this interface (can be NULL for unknown or unassigned)
921 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
922 * @param netmask the network mask (can be NULL for unknown or unassigned)
923 * @param addrlen length of the address
924 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
930 const struct sockaddr *addr,
931 const struct sockaddr *broadcast_addr,
932 const struct sockaddr *netmask,
935 struct IfcProcContext *ifc_ctx = cls;
936 struct LocalAddressList *lal;
938 const struct in_addr *ip4;
939 const struct in6_addr *ip6;
940 enum GNUNET_NAT_AddressClass ac;
942 switch (addr->sa_family)
945 alen = sizeof (struct sockaddr_in);
946 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
947 if (match_ipv4 ("127.0.0.0", ip4, 8))
948 ac = GNUNET_NAT_AC_LOOPBACK;
949 else if (is_nat_v4 (ip4))
950 ac = GNUNET_NAT_AC_LAN;
952 ac = GNUNET_NAT_AC_GLOBAL;
955 alen = sizeof (struct sockaddr_in6);
956 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
957 if (match_ipv6 ("::1", ip6, 128))
958 ac = GNUNET_NAT_AC_LOOPBACK;
959 else if (is_nat_v6 (ip6))
960 ac = GNUNET_NAT_AC_LAN;
962 ac = GNUNET_NAT_AC_GLOBAL;
963 if ( (ip6->s6_addr[11] == 0xFF) &&
964 (ip6->s6_addr[12] == 0xFE) )
966 /* contains a MAC, be extra careful! */
967 ac |= GNUNET_NAT_AC_PRIVATE;
979 lal = GNUNET_malloc (sizeof (*lal));
980 lal->af = addr->sa_family;
982 GNUNET_memcpy (&lal->addr,
985 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
993 * Notify client about a change in the list
994 * of addresses this peer has.
996 * @param delta the entry in the list that changed
997 * @param ch client to contact
998 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
999 * @param addr the address that changed
1000 * @param addr_len number of bytes in @a addr
1003 notify_client (struct LocalAddressList *delta,
1004 struct ClientHandle *ch,
1009 struct GNUNET_MQ_Envelope *env;
1010 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1012 env = GNUNET_MQ_msg_extra (msg,
1014 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1015 msg->add_remove = htonl (add);
1016 msg->addr_class = htonl (delta->ac);
1017 GNUNET_memcpy (&msg[1],
1020 GNUNET_MQ_send (ch->mq,
1026 * Notify all clients about a change in the list
1027 * of addresses this peer has.
1029 * @param delta the entry in the list that changed
1030 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1033 notify_clients (struct LocalAddressList *delta,
1036 for (struct ClientHandle *ch = ch_head;
1041 struct sockaddr_in v4;
1042 struct sockaddr_in6 v6;
1044 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
1049 alen = sizeof (struct sockaddr_in);
1053 for (unsigned int i=0;i<ch->num_addrs;i++)
1055 const struct sockaddr_in *c4;
1057 if (AF_INET != ch->addrs[i]->sa_family)
1058 continue; /* IPv4 not relevant */
1059 c4 = (const struct sockaddr_in *) ch->addrs[i];
1060 v4.sin_port = c4->sin_port;
1061 notify_client (delta,
1069 alen = sizeof (struct sockaddr_in6);
1073 for (unsigned int i=0;i<ch->num_addrs;i++)
1075 const struct sockaddr_in6 *c6;
1077 if (AF_INET6 != ch->addrs[i]->sa_family)
1078 continue; /* IPv4 not relevant */
1079 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
1080 v6.sin6_port = c6->sin6_port;
1081 notify_client (delta,
1097 * Task we run periodically to scan for network interfaces.
1102 run_scan (void *cls)
1104 struct IfcProcContext ifc_ctx;
1107 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1113 GNUNET_OS_network_interfaces_list (&ifc_proc,
1115 for (struct LocalAddressList *lal = lal_head;
1120 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1124 if ( (pos->af == lal->af) &&
1125 (0 == memcmp (&lal->addr,
1127 (AF_INET == lal->af)
1128 ? sizeof (struct sockaddr_in)
1129 : sizeof (struct sockaddr_in6))) )
1132 if (GNUNET_NO == found)
1133 notify_clients (lal,
1137 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1142 for (struct LocalAddressList *lal = lal_head;
1146 if ( (pos->af == lal->af) &&
1147 (0 == memcmp (&lal->addr,
1149 (AF_INET == lal->af)
1150 ? sizeof (struct sockaddr_in)
1151 : sizeof (struct sockaddr_in6))) )
1154 if (GNUNET_NO == found)
1155 notify_clients (pos,
1160 lal_head = ifc_ctx.lal_head;
1161 lal_tail = ifc_ctx.lal_tail;
1166 * Handle network size estimate clients.
1168 * @param cls closure
1169 * @param c configuration to use
1170 * @param service the initialized service
1174 const struct GNUNET_CONFIGURATION_Handle *c,
1175 struct GNUNET_SERVICE_Handle *service)
1179 GNUNET_CONFIGURATION_get_value_time (cfg,
1182 &stun_stale_timeout))
1183 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1184 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1186 stats = GNUNET_STATISTICS_create ("nat",
1188 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1194 * Callback called when a client connects to the service.
1196 * @param cls closure for the service
1197 * @param c the new client that connected to the service
1198 * @param mq the message queue used to send messages to the client
1199 * @return a `struct ClientHandle`
1202 client_connect_cb (void *cls,
1203 struct GNUNET_SERVICE_Client *c,
1204 struct GNUNET_MQ_Handle *mq)
1206 struct ClientHandle *ch;
1208 ch = GNUNET_new (struct ClientHandle);
1211 GNUNET_CONTAINER_DLL_insert (ch_head,
1219 * Callback called when a client disconnected from the service
1221 * @param cls closure for the service
1222 * @param c the client that disconnected
1223 * @param internal_cls a `struct ClientHandle *`
1226 client_disconnect_cb (void *cls,
1227 struct GNUNET_SERVICE_Client *c,
1230 struct ClientHandle *ch = internal_cls;
1232 GNUNET_CONTAINER_DLL_remove (ch_head,
1235 for (unsigned int i=0;i<ch->num_addrs;i++)
1236 GNUNET_free_non_null (ch->addrs[i]);
1237 GNUNET_free_non_null (ch->addrs);
1243 * Define "main" method using service macro.
1247 GNUNET_SERVICE_OPTION_NONE,
1250 &client_disconnect_cb,
1252 GNUNET_MQ_hd_var_size (register,
1253 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1254 struct GNUNET_NAT_RegisterMessage,
1256 GNUNET_MQ_hd_var_size (stun,
1257 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1258 struct GNUNET_NAT_HandleStunMessage,
1260 GNUNET_MQ_hd_var_size (request_connection_reversal,
1261 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1262 struct GNUNET_NAT_RequestConnectionReversalMessage,
1264 GNUNET_MQ_hd_var_size (autoconfig_request,
1265 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1266 struct GNUNET_NAT_AutoconfigRequestMessage,
1268 GNUNET_MQ_handler_end ());
1271 #if defined(LINUX) && defined(__GLIBC__)
1275 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1277 void __attribute__ ((constructor))
1278 GNUNET_ARM_memory_init ()
1280 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1281 mallopt (M_TOP_PAD, 1 * 1024);
1286 /* end of gnunet-service-nat.c */