fix proper setting of scope information for IPv6
[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 "nat.h"
38 #include <gcrypt.h>
39
40
41 /**
42  * How often should we ask the OS about a list of active
43  * network interfaces?
44  */
45 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
46
47
48 /**
49  * Internal data structure we track for each of our clients.
50  */
51 struct ClientHandle
52 {
53
54   /**
55    * Kept in a DLL.
56    */
57   struct ClientHandle *next;
58   
59   /**
60    * Kept in a DLL.
61    */
62   struct ClientHandle *prev;
63
64   /**
65    * Underlying handle for this client with the service.
66    */ 
67   struct GNUNET_SERVICE_Client *client;
68
69   /**
70    * Message queue for communicating with the client.
71    */
72   struct GNUNET_MQ_Handle *mq;
73
74   /**
75    * Array of addresses used by the service.
76    */
77   struct sockaddr **addrs;
78   
79   /**
80    * What does this client care about?
81    */
82   enum GNUNET_NAT_RegisterFlags flags;
83
84   /**
85    * Port we would like as we are configured to use this one for
86    * advertising (in addition to the one we are binding to).
87    */
88   uint16_t adv_port;
89
90   /**
91    * Number of addresses that this service is bound to.
92    */
93   uint16_t num_addrs;
94   
95   /**
96    * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
97    */
98   uint8_t proto;
99
100 };
101
102
103 /**
104  * List of local addresses this system has.
105  */
106 struct LocalAddressList
107 {
108   /**
109    * This is a linked list.
110    */
111   struct LocalAddressList *next;
112
113   /**
114    * Previous entry.
115    */
116   struct LocalAddressList *prev;
117
118   /**
119    * The address itself (i.e. `struct sockaddr_in` or `struct
120    * sockaddr_in6`, in the respective byte order).
121    */
122   struct sockaddr_storage addr;
123
124   /**
125    * Address family.
126    */
127   int af;
128
129   /**
130    * What type of address is this?
131    */
132   enum GNUNET_NAT_AddressClass ac;
133   
134 };
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
366   sa_len = ntohs (message->sender_addr_size);
367   payload_size = ntohs (message->payload_size);
368   sa = (const struct sockaddr *) &buf[0];
369   payload = (const struct sockaddr *) &buf[sa_len];
370   switch (sa->sa_family)
371   {
372   case AF_INET:
373     if (sa_len != sizeof (struct sockaddr_in))
374     {
375       GNUNET_break (0);
376       GNUNET_SERVICE_client_drop (ch->client);
377       return;
378     }
379     break;
380   case AF_INET6:
381     if (sa_len != sizeof (struct sockaddr_in6))
382     {
383       GNUNET_break (0);
384       GNUNET_SERVICE_client_drop (ch->client);
385       return;
386     }
387     break;
388   }
389   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390               "Received HANDLE_STUN message from client\n");
391   // FIXME: actually handle STUN request!
392   GNUNET_SERVICE_client_continue (ch->client);
393 }
394
395
396 /**
397  * Check validity of
398  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
399  * client.
400  *
401  * @param cls client who sent the message
402  * @param message the message received
403  * @return #GNUNET_OK if message is well-formed
404  */
405 static int
406 check_request_connection_reversal (void *cls,
407                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
408 {
409   size_t expect;
410
411   expect = ntohs (message->local_addr_size)
412     + ntohs (message->remote_addr_size);
413   if (ntohs (message->header.size) - sizeof (*message) != expect)
414   {
415     GNUNET_break (0);
416     return GNUNET_SYSERR;
417   }
418   return GNUNET_OK;
419 }
420
421
422 /**
423  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
424  * message from client.
425  *
426  * @param cls client who sent the message
427  * @param message the message received
428  */
429 static void
430 handle_request_connection_reversal (void *cls,
431                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
432 {
433   struct ClientHandle *ch = cls;
434   const char *buf = (const char *) &message[1];
435   size_t local_sa_len = ntohs (message->local_addr_size);
436   size_t remote_sa_len = ntohs (message->remote_addr_size);
437   const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
438   const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
439   
440   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
441               "Received REQUEST CONNECTION REVERSAL message from client\n");
442   switch (local_sa->sa_family)
443   {
444   case AF_INET:
445     if (local_sa_len != sizeof (struct sockaddr_in))
446     {
447       GNUNET_break (0);
448       GNUNET_SERVICE_client_drop (ch->client);
449       return;
450     }
451     break;
452   case AF_INET6:
453     if (local_sa_len != sizeof (struct sockaddr_in6))
454     {
455       GNUNET_break (0);
456       GNUNET_SERVICE_client_drop (ch->client);
457       return;
458     }
459     break;
460   default:
461     GNUNET_break (0);
462     GNUNET_SERVICE_client_drop (ch->client);
463     return;
464   }
465   switch (remote_sa->sa_family)
466   {
467   case AF_INET:
468     if (remote_sa_len != sizeof (struct sockaddr_in))
469     {
470       GNUNET_break (0);
471       GNUNET_SERVICE_client_drop (ch->client);
472       return;
473     }
474     break;
475   case AF_INET6:
476     if (remote_sa_len != sizeof (struct sockaddr_in6))
477     {
478       GNUNET_break (0);
479       GNUNET_SERVICE_client_drop (ch->client);
480       return;
481     }
482     break;
483   default:
484     GNUNET_break (0);
485     GNUNET_SERVICE_client_drop (ch->client);
486     return;
487   }
488   /* FIXME: actually run the logic! */
489   
490   GNUNET_SERVICE_client_continue (ch->client);
491 }
492
493
494 /**
495  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
496  * client.
497  *
498  * @param cls client who sent the message
499  * @param message the message received
500  */
501 static void
502 handle_test (void *cls,
503              const struct GNUNET_NAT_RequestTestMessage *message)
504 {
505   struct ClientHandle *ch = cls;
506
507   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
508               "Received REQUEST_TEST message from client\n");
509   /* FIXME: actually process test request */
510   GNUNET_SERVICE_client_continue (ch->client);
511 }
512
513
514 /**
515  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
516  * from client.
517  *
518  * @param cls client who sent the message
519  * @param message the message received
520  * @return #GNUNET_OK if message is well-formed
521  */
522 static int
523 check_autoconfig_request (void *cls,
524                           const struct GNUNET_NAT_AutoconfigRequestMessage *message)
525 {
526   return GNUNET_OK;  /* checked later */
527 }
528
529
530 /**
531  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
532  * client.
533  *
534  * @param cls client who sent the message
535  * @param message the message received
536  */
537 static void
538 handle_autoconfig_request (void *cls,
539                            const struct GNUNET_NAT_AutoconfigRequestMessage *message)
540 {
541   struct ClientHandle *ch = cls;
542   size_t left = ntohs (message->header.size);
543   struct GNUNET_CONFIGURATION_Handle *c;
544
545   c = GNUNET_CONFIGURATION_create ();
546   if (GNUNET_OK !=
547       GNUNET_CONFIGURATION_deserialize (c,
548                                         (const char *) &message[1],
549                                         left,
550                                         GNUNET_NO))
551   {
552     GNUNET_break (0);
553     GNUNET_SERVICE_client_drop (ch->client);
554     return;
555   }
556   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
557               "Received REQUEST_AUTO_CONFIG message from client\n");
558   // FIXME: actually handle request...
559   GNUNET_CONFIGURATION_destroy (c);
560   GNUNET_SERVICE_client_continue (ch->client);
561 }
562
563
564 /**
565  * Task run during shutdown.
566  *
567  * @param cls unused
568  */
569 static void
570 shutdown_task (void *cls)
571 {
572   if (NULL != scan_task)
573   {
574     GNUNET_SCHEDULER_cancel (scan_task);
575     scan_task = NULL;
576   }
577   if (NULL != stats)
578   {
579     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
580     stats = NULL;
581   }
582   destroy_lal ();
583 }
584
585
586 /**
587  * Closure for #ifc_proc.
588  */
589 struct IfcProcContext
590 {
591
592   /** 
593    * Head of DLL of local addresses.
594    */
595   struct LocalAddressList *lal_head;
596
597   /**
598    * Tail of DLL of local addresses.
599    */
600   struct LocalAddressList *lal_tail;
601
602 };
603
604
605 /**
606  * Check if @a ip is in @a network with @a bits netmask.
607  *
608  * @param network to test
609  * @param ip IP address to test
610  * @param bits bitmask for the network
611  * @return #GNUNET_YES if @a ip is in @a network
612  */
613 static int
614 match_ipv4 (const char *network,
615             const struct in_addr *ip,
616             uint8_t bits)
617 {
618   struct in_addr net;
619   
620   if (0 == bits)
621     return GNUNET_YES;
622   GNUNET_assert (1 == inet_pton (AF_INET,
623                                  network,
624                                  &net));
625   return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
626 }
627
628
629 /**
630  * Check if @a ip is in @a network with @a bits netmask.
631  *
632  * @param network to test
633  * @param ip IP address to test
634  * @param bits bitmask for the network
635  * @return #GNUNET_YES if @a ip is in @a network
636  */
637 static int
638 match_ipv6 (const char *network,
639             const struct in6_addr *ip,
640             uint8_t bits)
641 {
642   struct in6_addr net;
643   struct in6_addr mask;
644   unsigned int off;
645   
646   if (0 == bits)
647     return GNUNET_YES;
648   GNUNET_assert (1 == inet_pton (AF_INET,
649                                  network,
650                                  &net));
651   memset (&mask, 0, sizeof (mask));
652   off = 0;
653   while (bits > 8)
654   {
655     mask.s6_addr[off++] = 0xFF;
656     bits -= 8;
657   }
658   while (bits > 0)
659   {
660     mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
661     bits--;
662   }
663   for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
664     if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
665         (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
666       return GNUNET_NO;
667   return GNUNET_YES;
668 }
669
670
671 /**
672  * Callback function invoked for each interface found.  Adds them
673  * to our new address list.
674  *
675  * @param cls a `struct IfcProcContext *`
676  * @param name name of the interface (can be NULL for unknown)
677  * @param isDefault is this presumably the default interface
678  * @param addr address of this interface (can be NULL for unknown or unassigned)
679  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
680  * @param netmask the network mask (can be NULL for unknown or unassigned)
681  * @param addrlen length of the address
682  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
683  */
684 static int
685 ifc_proc (void *cls,
686           const char *name,
687           int isDefault,
688           const struct sockaddr *addr,
689           const struct sockaddr *broadcast_addr,
690           const struct sockaddr *netmask,
691           socklen_t addrlen)
692 {
693   struct IfcProcContext *ifc_ctx = cls;
694   struct LocalAddressList *lal;
695   size_t alen;
696   const void *ip;
697   const struct in6_addr *v6;
698   enum GNUNET_NAT_AddressClass ac;
699
700   switch (addr->sa_family)
701   {
702   case AF_INET:
703     alen = sizeof (struct sockaddr_in);
704     ip = &((const struct sockaddr_in *) addr)->sin_addr;
705     if (match_ipv4 ("127.0.0.0", ip, 8))
706       ac = GNUNET_NAT_AC_LOOPBACK;
707     else if (match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
708              match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
709              match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
710              match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
711              match_ipv4 ("172.16.0.0", ip, 16))  /* RFC 1918 */
712       ac = GNUNET_NAT_AC_LAN;
713     else
714       ac = GNUNET_NAT_AC_GLOBAL;
715     break;
716   case AF_INET6:
717     alen = sizeof (struct sockaddr_in6);
718     ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
719     if (match_ipv6 ("::1", ip, 128))
720       ac = GNUNET_NAT_AC_LOOPBACK;
721     else if (match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
722              match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
723              match_ipv6 ("fe80::", ip, 10)) /* RFC 4291, link-local */
724       ac = GNUNET_NAT_AC_LAN;
725     else
726       ac = GNUNET_NAT_AC_GLOBAL;
727     v6 = ip;
728     if ( (v6->s6_addr[11] == 0xFF) &&
729          (v6->s6_addr[12] == 0xFE) )
730     {
731       /* contains a MAC, be extra careful! */
732       ac |= GNUNET_NAT_AC_PRIVATE;
733     }
734     break;
735 #if AF_UNIX
736   case AF_UNIX:
737     GNUNET_break (0);
738     return GNUNET_OK;
739 #endif
740   default:
741     GNUNET_break (0);
742     return GNUNET_OK;
743   }
744   lal = GNUNET_malloc (sizeof (*lal));
745   lal->af = addr->sa_family;
746   lal->ac = ac;
747   GNUNET_memcpy (&lal->addr,
748                  addr,
749                  alen);
750   GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
751                                ifc_ctx->lal_tail,
752                                lal);
753   return GNUNET_OK;
754 }
755
756
757 /**
758  * Notify all clients about a change in the list
759  * of addresses this peer has.
760  *
761  * @param delta the entry in the list that changed
762  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
763  */
764 static void
765 notify_clients (struct LocalAddressList *delta,
766                 int add)
767 {
768   for (struct ClientHandle *ch = ch_head;
769        NULL != ch;
770        ch = ch->next)
771   {
772     struct GNUNET_MQ_Envelope *env;
773     struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
774     size_t alen;
775     
776     if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
777       continue;
778     switch (delta->af)
779     {
780     case AF_INET:
781       alen = sizeof (struct sockaddr_in);
782       break;
783     case AF_INET6:
784       alen = sizeof (struct sockaddr_in6);
785       break;
786     default:
787       GNUNET_break (0);
788       continue;
789     }
790     env = GNUNET_MQ_msg_extra (msg,
791                                alen,
792                                GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
793     msg->add_remove = htonl (add);
794     msg->addr_class = htonl (delta->ac);
795     GNUNET_memcpy (&msg[1],
796                    &delta->addr,
797                    alen);
798     GNUNET_MQ_send (ch->mq,
799                     env);
800   }
801 }
802
803
804 /**
805  * Task we run periodically to scan for network interfaces.
806  *
807  * @param cls NULL
808  */ 
809 static void
810 run_scan (void *cls)
811 {
812   struct IfcProcContext ifc_ctx;
813   int found;
814   
815   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
816                                             &run_scan,
817                                             NULL);
818   memset (&ifc_ctx,
819           0,
820           sizeof (ifc_ctx));
821   GNUNET_OS_network_interfaces_list (&ifc_proc,
822                                      &ifc_ctx);
823   for (struct LocalAddressList *lal = lal_head;
824        NULL != lal;
825        lal = lal->next)
826   {
827     found = GNUNET_NO;
828     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
829          NULL != pos;
830          pos = pos->next)
831     {
832       if ( (pos->af == lal->af) &&
833            (0 == memcmp (&lal->addr,
834                          &pos->addr,
835                          (AF_INET == lal->af)
836                          ? sizeof (struct sockaddr_in)
837                          : sizeof (struct sockaddr_in6))) )
838         found = GNUNET_YES;
839     }
840     if (GNUNET_NO == found)
841       notify_clients (lal,
842                       GNUNET_NO);
843   }
844
845   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
846        NULL != pos;
847        pos = pos->next)
848   {
849     found = GNUNET_NO;
850     for (struct LocalAddressList *lal = lal_head;
851          NULL != lal;
852          lal = lal->next)
853     {
854       if ( (pos->af == lal->af) &&
855            (0 == memcmp (&lal->addr,
856                          &pos->addr,
857                          (AF_INET == lal->af)
858                          ? sizeof (struct sockaddr_in)
859                          : sizeof (struct sockaddr_in6))) )
860         found = GNUNET_YES;
861     }
862     if (GNUNET_NO == found)
863       notify_clients (pos,
864                       GNUNET_YES);
865   }
866
867   destroy_lal ();
868   lal_head = ifc_ctx.lal_head;
869   lal_tail = ifc_ctx.lal_tail;
870 }
871
872
873 /**
874  * Handle network size estimate clients.
875  *
876  * @param cls closure
877  * @param c configuration to use
878  * @param service the initialized service
879  */
880 static void
881 run (void *cls,
882      const struct GNUNET_CONFIGURATION_Handle *c,
883      struct GNUNET_SERVICE_Handle *service)
884 {
885   cfg = c;
886   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
887                                  NULL);
888   stats = GNUNET_STATISTICS_create ("nat",
889                                     cfg);
890   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
891                                         NULL);
892 }
893
894
895 /**
896  * Callback called when a client connects to the service.
897  *
898  * @param cls closure for the service
899  * @param c the new client that connected to the service
900  * @param mq the message queue used to send messages to the client
901  * @return a `struct ClientHandle`
902  */
903 static void *
904 client_connect_cb (void *cls,
905                    struct GNUNET_SERVICE_Client *c,
906                    struct GNUNET_MQ_Handle *mq)
907 {
908   struct ClientHandle *ch;
909
910   ch = GNUNET_new (struct ClientHandle);
911   ch->mq = mq;
912   ch->client = c;
913   GNUNET_CONTAINER_DLL_insert (ch_head,
914                                ch_tail,
915                                ch);
916   return ch;
917 }
918
919
920 /**
921  * Callback called when a client disconnected from the service
922  *
923  * @param cls closure for the service
924  * @param c the client that disconnected
925  * @param internal_cls a `struct ClientHandle *`
926  */
927 static void
928 client_disconnect_cb (void *cls,
929                       struct GNUNET_SERVICE_Client *c,
930                       void *internal_cls)
931 {
932   struct ClientHandle *ch = internal_cls;
933
934   GNUNET_CONTAINER_DLL_remove (ch_head,
935                                ch_tail,
936                                ch);
937   for (unsigned int i=0;i<ch->num_addrs;i++)
938     GNUNET_free_non_null (ch->addrs[i]);
939   GNUNET_free_non_null (ch->addrs);
940   GNUNET_free (ch);
941 }
942
943
944 /**
945  * Define "main" method using service macro.
946  */
947 GNUNET_SERVICE_MAIN
948 ("nat",
949  GNUNET_SERVICE_OPTION_NONE,
950  &run,
951  &client_connect_cb,
952  &client_disconnect_cb,
953  NULL,
954  GNUNET_MQ_hd_var_size (register,
955                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
956                         struct GNUNET_NAT_RegisterMessage,
957                         NULL),
958  GNUNET_MQ_hd_var_size (stun,
959                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
960                         struct GNUNET_NAT_HandleStunMessage,
961                         NULL),
962  GNUNET_MQ_hd_var_size (request_connection_reversal,
963                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
964                         struct GNUNET_NAT_RequestConnectionReversalMessage,
965                         NULL),
966  GNUNET_MQ_hd_fixed_size (test,
967                           GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
968                           struct GNUNET_NAT_RequestTestMessage,
969                           NULL),
970  GNUNET_MQ_hd_var_size (autoconfig_request,
971                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
972                         struct GNUNET_NAT_AutoconfigRequestMessage,
973                         NULL),
974  GNUNET_MQ_handler_end ());
975
976
977 #if defined(LINUX) && defined(__GLIBC__)
978 #include <malloc.h>
979
980 /**
981  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
982  */
983 void __attribute__ ((constructor))
984 GNUNET_ARM_memory_init ()
985 {
986   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
987   mallopt (M_TOP_PAD, 1 * 1024);
988   malloc_trim (0);
989 }
990 #endif
991
992 /* end of gnunet-service-nat.c */