this is now done
[oweals/gnunet.git] / src / nat / gnunet-service-nat.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2016 GNUnet e.V.
4
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.
9
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.
14
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.
19  */
20
21 /**
22  * @file nat/gnunet-service-nat.c
23  * @brief network address translation traversal service
24  * @author Christian Grothoff
25  *
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.
29  *
30  * TODO:
31  * - call GN_start_gnunet_nat_server_() if possible (i.e.
32  *   when we find we have a non-global IPv4 address)
33  * - implement autoconfig
34  * - implmeent UPnPC/PMP-based NAT traversal
35  * - implement NEW logic for external IP detection
36  */
37 #include "platform.h"
38 #include <math.h>
39 #include "gnunet_util_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
42 #include "gnunet_statistics_service.h"
43 #include "gnunet_nat_service.h"
44 #include "gnunet-service-nat_stun.h"
45 #include "gnunet-service-nat_helper.h"
46 #include "nat.h"
47 #include <gcrypt.h>
48
49
50 /**
51  * How often should we ask the OS about a list of active
52  * network interfaces?
53  */
54 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
55
56
57 /**
58  * Internal data structure we track for each of our clients.
59  */
60 struct ClientHandle
61 {
62
63   /**
64    * Kept in a DLL.
65    */
66   struct ClientHandle *next;
67   
68   /**
69    * Kept in a DLL.
70    */
71   struct ClientHandle *prev;
72
73   /**
74    * Underlying handle for this client with the service.
75    */ 
76   struct GNUNET_SERVICE_Client *client;
77
78   /**
79    * Message queue for communicating with the client.
80    */
81   struct GNUNET_MQ_Handle *mq;
82
83   /**
84    * Array of addresses used by the service.
85    */
86   struct sockaddr **addrs;
87   
88   /**
89    * What does this client care about?
90    */
91   enum GNUNET_NAT_RegisterFlags flags;
92
93   /**
94    * Port we would like as we are configured to use this one for
95    * advertising (in addition to the one we are binding to).
96    */
97   uint16_t adv_port;
98
99   /**
100    * Number of addresses that this service is bound to.
101    */
102   uint16_t num_addrs;
103   
104   /**
105    * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
106    */
107   uint8_t proto;
108
109 };
110
111
112 /**
113  * List of local addresses this system has.
114  */
115 struct LocalAddressList
116 {
117   /**
118    * This is a linked list.
119    */
120   struct LocalAddressList *next;
121
122   /**
123    * Previous entry.
124    */
125   struct LocalAddressList *prev;
126
127   /**
128    * The address itself (i.e. `struct sockaddr_in` or `struct
129    * sockaddr_in6`, in the respective byte order).
130    */
131   struct sockaddr_storage addr;
132
133   /**
134    * Address family.
135    */
136   int af;
137
138   /**
139    * What type of address is this?
140    */
141   enum GNUNET_NAT_AddressClass ac;
142   
143 };
144
145
146 /**
147  * Handle to our current configuration.
148  */
149 static const struct GNUNET_CONFIGURATION_Handle *cfg;
150
151 /**
152  * Handle to the statistics service.
153  */
154 static struct GNUNET_STATISTICS_Handle *stats;
155
156 /**
157  * Task scheduled to periodically scan our network interfaces.
158  */
159 static struct GNUNET_SCHEDULER_Task *scan_task;
160
161 /**
162  * Head of client DLL.
163  */
164 static struct ClientHandle *ch_head;
165   
166 /**
167  * Tail of client DLL.
168  */
169 static struct ClientHandle *ch_tail;
170
171 /**
172  * Head of DLL of local addresses.
173  */
174 static struct LocalAddressList *lal_head;
175
176 /**
177  * Tail of DLL of local addresses.
178  */
179 static struct LocalAddressList *lal_tail;
180
181
182 /**
183  * Free the DLL starting at #lal_head.
184  */ 
185 static void
186 destroy_lal ()
187 {
188   struct LocalAddressList *lal;
189
190   while (NULL != (lal = lal_head))
191   {
192     GNUNET_CONTAINER_DLL_remove (lal_head,
193                                  lal_tail,
194                                  lal);
195     GNUNET_free (lal);
196   }
197 }
198
199
200 /**
201  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
202  * client.
203  *
204  * @param cls client who sent the message
205  * @param message the message received
206  * @return #GNUNET_OK if message is well-formed
207  */
208 static int
209 check_register (void *cls,
210                 const struct GNUNET_NAT_RegisterMessage *message)
211 {
212   uint16_t num_addrs = ntohs (message->num_addrs);
213   const char *off = (const char *) &message[1];
214   size_t left = ntohs (message->header.size) - sizeof (*message);
215
216   for (unsigned int i=0;i<num_addrs;i++)
217   {
218     size_t alen;
219     const struct sockaddr *sa = (const struct sockaddr *) off;
220
221     if (sizeof (sa_family_t) > left)
222     {
223       GNUNET_break (0);
224       return GNUNET_SYSERR;
225     }
226     switch (sa->sa_family)
227     {
228     case AF_INET:
229       alen = sizeof (struct sockaddr_in);
230       break;
231     case AF_INET6:
232       alen = sizeof (struct sockaddr_in6);
233       break;
234 #if AF_UNIX
235     case AF_UNIX:
236       alen = sizeof (struct sockaddr_un);
237       break;
238 #endif
239     default:
240       GNUNET_break (0);
241       return GNUNET_SYSERR;      
242     }
243     if (alen > left)
244     {
245       GNUNET_break (0);
246       return GNUNET_SYSERR;      
247     }
248   }  
249   return GNUNET_OK; 
250 }
251
252
253 /**
254  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
255  * We remember the client for updates upon future NAT events.
256  *
257  * @param cls client who sent the message
258  * @param message the message received
259  */
260 static void
261 handle_register (void *cls,
262                  const struct GNUNET_NAT_RegisterMessage *message)
263 {
264   struct ClientHandle *ch = cls;
265   const char *off;
266   size_t left;
267
268   if ( (0 != ch->proto) ||
269        (NULL != ch->addrs) )
270   {
271     /* double registration not allowed */
272     GNUNET_break (0);
273     GNUNET_SERVICE_client_drop (ch->client);
274     return;
275   }
276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
277               "Received REGISTER message from client\n");
278   ch->flags = message->flags;
279   ch->proto = message->proto;
280   ch->adv_port = ntohs (message->adv_port);
281   ch->num_addrs = ntohs (message->adv_port);
282   ch->addrs = GNUNET_new_array (ch->num_addrs,
283                                 struct sockaddr *);
284   left = ntohs (message->header.size) - sizeof (*message);
285   off = (const char *) &message[1];
286   for (unsigned int i=0;i<ch->num_addrs;i++)
287   {
288     size_t alen;
289     const struct sockaddr *sa = (const struct sockaddr *) off;
290
291     if (sizeof (sa_family_t) > left)
292     {
293       GNUNET_break (0);
294       GNUNET_SERVICE_client_drop (ch->client);
295       return;
296     }
297     switch (sa->sa_family)
298     {
299     case AF_INET:
300       alen = sizeof (struct sockaddr_in);
301       break;
302     case AF_INET6:
303       alen = sizeof (struct sockaddr_in6);
304       break;
305 #if AF_UNIX
306     case AF_UNIX:
307       alen = sizeof (struct sockaddr_un);
308       break;
309 #endif
310     default:
311       GNUNET_break (0);
312       GNUNET_SERVICE_client_drop (ch->client);
313       return;      
314     }
315     GNUNET_assert (alen <= left);
316     ch->addrs[i] = GNUNET_malloc (alen);
317     GNUNET_memcpy (ch->addrs[i],
318                    sa,
319                    alen);    
320     off += alen;
321   }  
322   GNUNET_SERVICE_client_continue (ch->client);
323 }
324
325
326 /**
327  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
328  * client.
329  *
330  * @param cls client who sent the message
331  * @param message the message received
332  * @return #GNUNET_OK if message is well-formed
333  */
334 static int
335 check_stun (void *cls,
336             const struct GNUNET_NAT_HandleStunMessage *message)
337 {
338   size_t sa_len = ntohs (message->sender_addr_size);
339   size_t expect = sa_len + ntohs (message->payload_size);
340   
341   if (ntohs (message->header.size) - sizeof (*message) != expect)
342   {
343     GNUNET_break (0);
344     return GNUNET_SYSERR;
345   }
346   if (sa_len < sizeof (sa_family_t))
347   {
348     GNUNET_break (0);
349     return GNUNET_SYSERR;
350   }
351   return GNUNET_OK;
352 }
353
354
355 /**
356  * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
357  * client.
358  *
359  * @param cls client who sent the message
360  * @param message the message received
361  */
362 static void
363 handle_stun (void *cls,
364              const struct GNUNET_NAT_HandleStunMessage *message)
365 {
366   struct ClientHandle *ch = cls;
367   const char *buf = (const char *) &message[1];
368   const struct sockaddr *sa;
369   const void *payload;
370   size_t sa_len;
371   size_t payload_size;
372   struct sockaddr_in external_addr;
373
374   sa_len = ntohs (message->sender_addr_size);
375   payload_size = ntohs (message->payload_size);
376   sa = (const struct sockaddr *) &buf[0];
377   payload = (const struct sockaddr *) &buf[sa_len];
378   switch (sa->sa_family)
379   {
380   case AF_INET:
381     if (sa_len != sizeof (struct sockaddr_in))
382     {
383       GNUNET_break (0);
384       GNUNET_SERVICE_client_drop (ch->client);
385       return;
386     }
387     break;
388   case AF_INET6:
389     if (sa_len != sizeof (struct sockaddr_in6))
390     {
391       GNUNET_break (0);
392       GNUNET_SERVICE_client_drop (ch->client);
393       return;
394     }
395     break;
396   }
397   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
398               "Received HANDLE_STUN message from client\n");
399   if (GNUNET_OK ==
400       GNUNET_NAT_stun_handle_packet_ (payload,
401                                       payload_size,
402                                       &external_addr))
403   {     
404     /* FIXME: do something with "external_addr"! We 
405        now know that a server at "sa" claims that
406        we are visible at IP "external_addr". 
407
408        We should (for some fixed period of time) tell
409        all of our clients that listen to a NAT'ed address
410        that they might want to consider the given 'external_ip'
411        as their public IP address (this includes TCP and UDP
412        clients, even if only UDP sends STUN requests).
413
414        If we do not get a renewal, the "external_addr" should be
415        removed again.  The timeout frequency should be configurable
416        (with a sane default), so that the UDP plugin can tell how
417        often to re-request STUN.
418     */
419     
420   }
421   GNUNET_SERVICE_client_continue (ch->client);
422 }
423
424
425 /**
426  * Check validity of
427  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
428  * client.
429  *
430  * @param cls client who sent the message
431  * @param message the message received
432  * @return #GNUNET_OK if message is well-formed
433  */
434 static int
435 check_request_connection_reversal (void *cls,
436                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
437 {
438   size_t expect;
439
440   expect = ntohs (message->local_addr_size)
441     + ntohs (message->remote_addr_size);
442   if (ntohs (message->header.size) - sizeof (*message) != expect)
443   {
444     GNUNET_break (0);
445     return GNUNET_SYSERR;
446   }
447   return GNUNET_OK;
448 }
449
450
451 /**
452  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
453  * message from client.
454  *
455  * @param cls client who sent the message
456  * @param message the message received
457  */
458 static void
459 handle_request_connection_reversal (void *cls,
460                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
461 {
462   struct ClientHandle *ch = cls;
463   const char *buf = (const char *) &message[1];
464   size_t local_sa_len = ntohs (message->local_addr_size);
465   size_t remote_sa_len = ntohs (message->remote_addr_size);
466   const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
467   const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
468   
469   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
470               "Received REQUEST CONNECTION REVERSAL message from client\n");
471   switch (local_sa->sa_family)
472   {
473   case AF_INET:
474     if (local_sa_len != sizeof (struct sockaddr_in))
475     {
476       GNUNET_break (0);
477       GNUNET_SERVICE_client_drop (ch->client);
478       return;
479     }
480     break;
481   case AF_INET6:
482     if (local_sa_len != sizeof (struct sockaddr_in6))
483     {
484       GNUNET_break (0);
485       GNUNET_SERVICE_client_drop (ch->client);
486       return;
487     }
488     break;
489   default:
490     GNUNET_break (0);
491     GNUNET_SERVICE_client_drop (ch->client);
492     return;
493   }
494   switch (remote_sa->sa_family)
495   {
496   case AF_INET:
497     if (remote_sa_len != sizeof (struct sockaddr_in))
498     {
499       GNUNET_break (0);
500       GNUNET_SERVICE_client_drop (ch->client);
501       return;
502     }
503     break;
504   case AF_INET6:
505     if (remote_sa_len != sizeof (struct sockaddr_in6))
506     {
507       GNUNET_break (0);
508       GNUNET_SERVICE_client_drop (ch->client);
509       return;
510     }
511     break;
512   default:
513     GNUNET_break (0);
514     GNUNET_SERVICE_client_drop (ch->client);
515     return;
516   }
517   /* FIXME: actually run the logic by
518      calling 'GN_request_connection_reversal()' */
519   
520   GNUNET_SERVICE_client_continue (ch->client);
521 }
522
523
524 /**
525  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
526  * from client.
527  *
528  * @param cls client who sent the message
529  * @param message the message received
530  * @return #GNUNET_OK if message is well-formed
531  */
532 static int
533 check_autoconfig_request (void *cls,
534                           const struct GNUNET_NAT_AutoconfigRequestMessage *message)
535 {
536   return GNUNET_OK;  /* checked later */
537 }
538
539
540 /**
541  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
542  * client.
543  *
544  * @param cls client who sent the message
545  * @param message the message received
546  */
547 static void
548 handle_autoconfig_request (void *cls,
549                            const struct GNUNET_NAT_AutoconfigRequestMessage *message)
550 {
551   struct ClientHandle *ch = cls;
552   size_t left = ntohs (message->header.size);
553   struct GNUNET_CONFIGURATION_Handle *c;
554
555   c = GNUNET_CONFIGURATION_create ();
556   if (GNUNET_OK !=
557       GNUNET_CONFIGURATION_deserialize (c,
558                                         (const char *) &message[1],
559                                         left,
560                                         GNUNET_NO))
561   {
562     GNUNET_break (0);
563     GNUNET_SERVICE_client_drop (ch->client);
564     return;
565   }
566   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
567               "Received REQUEST_AUTO_CONFIG message from client\n");
568   // FIXME: actually handle request...
569   GNUNET_CONFIGURATION_destroy (c);
570   GNUNET_SERVICE_client_continue (ch->client);
571 }
572
573
574 /**
575  * Task run during shutdown.
576  *
577  * @param cls unused
578  */
579 static void
580 shutdown_task (void *cls)
581 {
582   if (NULL != scan_task)
583   {
584     GNUNET_SCHEDULER_cancel (scan_task);
585     scan_task = NULL;
586   }
587   if (NULL != stats)
588   {
589     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
590     stats = NULL;
591   }
592   destroy_lal ();
593 }
594
595
596 /**
597  * Closure for #ifc_proc.
598  */
599 struct IfcProcContext
600 {
601
602   /** 
603    * Head of DLL of local addresses.
604    */
605   struct LocalAddressList *lal_head;
606
607   /**
608    * Tail of DLL of local addresses.
609    */
610   struct LocalAddressList *lal_tail;
611
612 };
613
614
615 /**
616  * Check if @a ip is in @a network with @a bits netmask.
617  *
618  * @param network to test
619  * @param ip IP address to test
620  * @param bits bitmask for the network
621  * @return #GNUNET_YES if @a ip is in @a network
622  */
623 static int
624 match_ipv4 (const char *network,
625             const struct in_addr *ip,
626             uint8_t bits)
627 {
628   struct in_addr net;
629   
630   if (0 == bits)
631     return GNUNET_YES;
632   GNUNET_assert (1 == inet_pton (AF_INET,
633                                  network,
634                                  &net));
635   return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
636 }
637
638
639 /**
640  * Check if @a ip is in @a network with @a bits netmask.
641  *
642  * @param network to test
643  * @param ip IP address to test
644  * @param bits bitmask for the network
645  * @return #GNUNET_YES if @a ip is in @a network
646  */
647 static int
648 match_ipv6 (const char *network,
649             const struct in6_addr *ip,
650             uint8_t bits)
651 {
652   struct in6_addr net;
653   struct in6_addr mask;
654   unsigned int off;
655   
656   if (0 == bits)
657     return GNUNET_YES;
658   GNUNET_assert (1 == inet_pton (AF_INET,
659                                  network,
660                                  &net));
661   memset (&mask, 0, sizeof (mask));
662   off = 0;
663   while (bits > 8)
664   {
665     mask.s6_addr[off++] = 0xFF;
666     bits -= 8;
667   }
668   while (bits > 0)
669   {
670     mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
671     bits--;
672   }
673   for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
674     if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
675         (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
676       return GNUNET_NO;
677   return GNUNET_YES;
678 }
679
680
681 /**
682  * Test if the given IPv4 address is in a known range
683  * for private networks.
684  *
685  * @param ip address to test
686  * @return #GNUNET_YES if @a ip is in a NAT range
687  */
688 static int
689 is_nat_v4 (const struct in_addr *ip)
690 {
691   return
692     match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
693     match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
694     match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
695     match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
696     match_ipv4 ("172.16.0.0", ip, 16);  /* RFC 1918 */
697 }
698
699
700 /**
701  * Test if the given IPv6 address is in a known range
702  * for private networks.
703  *
704  * @param ip address to test
705  * @return #GNUNET_YES if @a ip is in a NAT range
706  */
707 static int
708 is_nat_v6 (const struct in6_addr *ip)
709 {
710   return
711     match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
712     match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
713     match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
714 }
715
716
717 /**
718  * Callback function invoked for each interface found.  Adds them
719  * to our new address list.
720  *
721  * @param cls a `struct IfcProcContext *`
722  * @param name name of the interface (can be NULL for unknown)
723  * @param isDefault is this presumably the default interface
724  * @param addr address of this interface (can be NULL for unknown or unassigned)
725  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
726  * @param netmask the network mask (can be NULL for unknown or unassigned)
727  * @param addrlen length of the address
728  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
729  */
730 static int
731 ifc_proc (void *cls,
732           const char *name,
733           int isDefault,
734           const struct sockaddr *addr,
735           const struct sockaddr *broadcast_addr,
736           const struct sockaddr *netmask,
737           socklen_t addrlen)
738 {
739   struct IfcProcContext *ifc_ctx = cls;
740   struct LocalAddressList *lal;
741   size_t alen;
742   const struct in_addr *ip4;
743   const struct in6_addr *ip6;
744   enum GNUNET_NAT_AddressClass ac;
745
746   switch (addr->sa_family)
747   {
748   case AF_INET:
749     alen = sizeof (struct sockaddr_in);
750     ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
751     if (match_ipv4 ("127.0.0.0", ip4, 8))
752       ac = GNUNET_NAT_AC_LOOPBACK;
753     else if (is_nat_v4 (ip4))
754       ac = GNUNET_NAT_AC_LAN;
755     else
756       ac = GNUNET_NAT_AC_GLOBAL;
757     break;
758   case AF_INET6:
759     alen = sizeof (struct sockaddr_in6);
760     ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
761     if (match_ipv6 ("::1", ip6, 128))
762       ac = GNUNET_NAT_AC_LOOPBACK;
763     else if (is_nat_v6 (ip6))
764       ac = GNUNET_NAT_AC_LAN;
765     else
766       ac = GNUNET_NAT_AC_GLOBAL;
767     if ( (ip6->s6_addr[11] == 0xFF) &&
768          (ip6->s6_addr[12] == 0xFE) )
769     {
770       /* contains a MAC, be extra careful! */
771       ac |= GNUNET_NAT_AC_PRIVATE;
772     }
773     break;
774 #if AF_UNIX
775   case AF_UNIX:
776     GNUNET_break (0);
777     return GNUNET_OK;
778 #endif
779   default:
780     GNUNET_break (0);
781     return GNUNET_OK;
782   }
783   lal = GNUNET_malloc (sizeof (*lal));
784   lal->af = addr->sa_family;
785   lal->ac = ac;
786   GNUNET_memcpy (&lal->addr,
787                  addr,
788                  alen);
789   GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
790                                ifc_ctx->lal_tail,
791                                lal);
792   return GNUNET_OK;
793 }
794
795
796 /**
797  * Notify client about a change in the list
798  * of addresses this peer has.
799  *
800  * @param delta the entry in the list that changed
801  * @param ch client to contact
802  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
803  * @param addr the address that changed
804  * @param addr_len number of bytes in @a addr
805  */
806 static void
807 notify_client (struct LocalAddressList *delta,
808                struct ClientHandle *ch,
809                int add,
810                const void *addr,
811                size_t addr_len)
812 {
813   struct GNUNET_MQ_Envelope *env;
814   struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
815
816   env = GNUNET_MQ_msg_extra (msg,
817                              addr_len,
818                              GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
819   msg->add_remove = htonl (add);
820   msg->addr_class = htonl (delta->ac);
821   GNUNET_memcpy (&msg[1],
822                  addr,
823                  addr_len);
824   GNUNET_MQ_send (ch->mq,
825                   env);
826 }                      
827
828
829 /**
830  * Notify all clients about a change in the list
831  * of addresses this peer has.
832  *
833  * @param delta the entry in the list that changed
834  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
835  */
836 static void
837 notify_clients (struct LocalAddressList *delta,
838                 int add)
839 {
840   for (struct ClientHandle *ch = ch_head;
841        NULL != ch;
842        ch = ch->next)
843   {
844     size_t alen;
845     struct sockaddr_in v4;
846     struct sockaddr_in6 v6;
847     
848     if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
849       continue;
850     switch (delta->af)
851     {
852     case AF_INET:
853       alen = sizeof (struct sockaddr_in);
854       GNUNET_memcpy (&v4,
855                      &delta->addr,
856                      alen);
857       for (unsigned int i=0;i<ch->num_addrs;i++)
858       {
859         const struct sockaddr_in *c4;
860         
861         if (AF_INET != ch->addrs[i]->sa_family)
862           continue; /* IPv4 not relevant */
863         c4 = (const struct sockaddr_in *) ch->addrs[i];
864         v4.sin_port = c4->sin_port;
865         notify_client (delta,
866                        ch,
867                        add,
868                        &v4,
869                        alen);
870       }
871       break;
872     case AF_INET6:
873       alen = sizeof (struct sockaddr_in6);
874       GNUNET_memcpy (&v6,
875                      &delta->addr,
876                      alen);
877       for (unsigned int i=0;i<ch->num_addrs;i++)
878       {
879         const struct sockaddr_in6 *c6;
880         
881         if (AF_INET6 != ch->addrs[i]->sa_family)
882           continue; /* IPv4 not relevant */
883         c6 = (const struct sockaddr_in6 *) ch->addrs[i];
884         v6.sin6_port = c6->sin6_port;
885         notify_client (delta,
886                        ch,
887                        add,
888                        &v6,
889                        alen);
890       }
891       break;
892     default:
893       GNUNET_break (0);
894       continue;
895     }
896   }
897 }
898
899
900 /**
901  * Task we run periodically to scan for network interfaces.
902  *
903  * @param cls NULL
904  */ 
905 static void
906 run_scan (void *cls)
907 {
908   struct IfcProcContext ifc_ctx;
909   int found;
910   
911   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
912                                             &run_scan,
913                                             NULL);
914   memset (&ifc_ctx,
915           0,
916           sizeof (ifc_ctx));
917   GNUNET_OS_network_interfaces_list (&ifc_proc,
918                                      &ifc_ctx);
919   for (struct LocalAddressList *lal = lal_head;
920        NULL != lal;
921        lal = lal->next)
922   {
923     found = GNUNET_NO;
924     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
925          NULL != pos;
926          pos = pos->next)
927     {
928       if ( (pos->af == lal->af) &&
929            (0 == memcmp (&lal->addr,
930                          &pos->addr,
931                          (AF_INET == lal->af)
932                          ? sizeof (struct sockaddr_in)
933                          : sizeof (struct sockaddr_in6))) )
934         found = GNUNET_YES;
935     }
936     if (GNUNET_NO == found)
937       notify_clients (lal,
938                       GNUNET_NO);
939   }
940
941   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
942        NULL != pos;
943        pos = pos->next)
944   {
945     found = GNUNET_NO;
946     for (struct LocalAddressList *lal = lal_head;
947          NULL != lal;
948          lal = lal->next)
949     {
950       if ( (pos->af == lal->af) &&
951            (0 == memcmp (&lal->addr,
952                          &pos->addr,
953                          (AF_INET == lal->af)
954                          ? sizeof (struct sockaddr_in)
955                          : sizeof (struct sockaddr_in6))) )
956         found = GNUNET_YES;
957     }
958     if (GNUNET_NO == found)
959       notify_clients (pos,
960                       GNUNET_YES);
961   }
962
963   destroy_lal ();
964   lal_head = ifc_ctx.lal_head;
965   lal_tail = ifc_ctx.lal_tail;
966 }
967
968
969 /**
970  * Handle network size estimate clients.
971  *
972  * @param cls closure
973  * @param c configuration to use
974  * @param service the initialized service
975  */
976 static void
977 run (void *cls,
978      const struct GNUNET_CONFIGURATION_Handle *c,
979      struct GNUNET_SERVICE_Handle *service)
980 {
981   cfg = c;
982   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
983                                  NULL);
984   stats = GNUNET_STATISTICS_create ("nat",
985                                     cfg);
986   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
987                                         NULL);
988 }
989
990
991 /**
992  * Callback called when a client connects to the service.
993  *
994  * @param cls closure for the service
995  * @param c the new client that connected to the service
996  * @param mq the message queue used to send messages to the client
997  * @return a `struct ClientHandle`
998  */
999 static void *
1000 client_connect_cb (void *cls,
1001                    struct GNUNET_SERVICE_Client *c,
1002                    struct GNUNET_MQ_Handle *mq)
1003 {
1004   struct ClientHandle *ch;
1005
1006   ch = GNUNET_new (struct ClientHandle);
1007   ch->mq = mq;
1008   ch->client = c;
1009   GNUNET_CONTAINER_DLL_insert (ch_head,
1010                                ch_tail,
1011                                ch);
1012   return ch;
1013 }
1014
1015
1016 /**
1017  * Callback called when a client disconnected from the service
1018  *
1019  * @param cls closure for the service
1020  * @param c the client that disconnected
1021  * @param internal_cls a `struct ClientHandle *`
1022  */
1023 static void
1024 client_disconnect_cb (void *cls,
1025                       struct GNUNET_SERVICE_Client *c,
1026                       void *internal_cls)
1027 {
1028   struct ClientHandle *ch = internal_cls;
1029
1030   GNUNET_CONTAINER_DLL_remove (ch_head,
1031                                ch_tail,
1032                                ch);
1033   for (unsigned int i=0;i<ch->num_addrs;i++)
1034     GNUNET_free_non_null (ch->addrs[i]);
1035   GNUNET_free_non_null (ch->addrs);
1036   GNUNET_free (ch);
1037 }
1038
1039
1040 /**
1041  * Define "main" method using service macro.
1042  */
1043 GNUNET_SERVICE_MAIN
1044 ("nat",
1045  GNUNET_SERVICE_OPTION_NONE,
1046  &run,
1047  &client_connect_cb,
1048  &client_disconnect_cb,
1049  NULL,
1050  GNUNET_MQ_hd_var_size (register,
1051                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1052                         struct GNUNET_NAT_RegisterMessage,
1053                         NULL),
1054  GNUNET_MQ_hd_var_size (stun,
1055                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1056                         struct GNUNET_NAT_HandleStunMessage,
1057                         NULL),
1058  GNUNET_MQ_hd_var_size (request_connection_reversal,
1059                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1060                         struct GNUNET_NAT_RequestConnectionReversalMessage,
1061                         NULL),
1062  GNUNET_MQ_hd_var_size (autoconfig_request,
1063                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1064                         struct GNUNET_NAT_AutoconfigRequestMessage,
1065                         NULL),
1066  GNUNET_MQ_handler_end ());
1067
1068
1069 #if defined(LINUX) && defined(__GLIBC__)
1070 #include <malloc.h>
1071
1072 /**
1073  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1074  */
1075 void __attribute__ ((constructor))
1076 GNUNET_ARM_memory_init ()
1077 {
1078   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1079   mallopt (M_TOP_PAD, 1 * 1024);
1080   malloc_trim (0);
1081 }
1082 #endif
1083
1084 /* end of gnunet-service-nat.c */