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