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