enable sending only differences for autoconfiguration
[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  * - implement UPnPC/PMP-based NAT traversal
32  * - implement autoconfig
33  * - implement NEW logic for external IP detection
34  */
35 #include "platform.h"
36 #include <math.h>
37 #include "gnunet_util_lib.h"
38 #include "gnunet_protocols.h"
39 #include "gnunet_signatures.h"
40 #include "gnunet_statistics_service.h"
41 #include "gnunet_nat_service.h"
42 #include "gnunet-service-nat_stun.h"
43 #include "gnunet-service-nat_mini.h"
44 #include "gnunet-service-nat_helper.h"
45 #include "nat.h"
46 #include <gcrypt.h>
47
48
49 /**
50  * How often should we ask the OS about a list of active
51  * network interfaces?
52  */
53 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
54
55 /**
56  * How long do we wait until we forcefully terminate autoconfiguration?
57  */
58 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59
60
61 /**
62  * Internal data structure we track for each of our clients.
63  */
64 struct ClientHandle
65 {
66
67   /**
68    * Kept in a DLL.
69    */
70   struct ClientHandle *next;
71   
72   /**
73    * Kept in a DLL.
74    */
75   struct ClientHandle *prev;
76
77   /**
78    * Underlying handle for this client with the service.
79    */ 
80   struct GNUNET_SERVICE_Client *client;
81
82   /**
83    * Message queue for communicating with the client.
84    */
85   struct GNUNET_MQ_Handle *mq;
86
87   /**
88    * Array of addresses used by the service.
89    */
90   struct sockaddr **addrs;
91   
92   /**
93    * What does this client care about?
94    */
95   enum GNUNET_NAT_RegisterFlags flags;
96
97   /**
98    * Is any of the @e addrs in a reserved subnet for NAT?
99    */
100   int natted_address;
101   
102   /**
103    * Port we would like as we are configured to use this one for
104    * advertising (in addition to the one we are binding to).
105    */
106   uint16_t adv_port;
107
108   /**
109    * Number of addresses that this service is bound to.
110    */
111   uint16_t num_addrs;
112   
113   /**
114    * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
115    */
116   uint8_t proto;
117
118 };
119
120
121 /**
122  * List of local addresses this system has.
123  */
124 struct LocalAddressList
125 {
126   /**
127    * This is a linked list.
128    */
129   struct LocalAddressList *next;
130
131   /**
132    * Previous entry.
133    */
134   struct LocalAddressList *prev;
135
136   /**
137    * The address itself (i.e. `struct sockaddr_in` or `struct
138    * sockaddr_in6`, in the respective byte order).
139    */
140   struct sockaddr_storage addr;
141
142   /**
143    * Address family.
144    */
145   int af;
146
147   /**
148    * What type of address is this?
149    */
150   enum GNUNET_NAT_AddressClass ac;
151   
152 };
153
154
155 /**
156  * External IP address as given to us via some STUN server.
157  */
158 struct StunExternalIP
159 {
160   /**
161    * Kept in a DLL.
162    */ 
163   struct StunExternalIP *next;
164
165   /**
166    * Kept in a DLL.
167    */ 
168   struct StunExternalIP *prev;
169
170   /**
171    * Task we run to remove this entry when it is stale.
172    */
173   struct GNUNET_SCHEDULER_Task *timeout_task;
174
175   /**
176    * Our external IP address as reported by the 
177    * STUN server.
178    */
179   struct sockaddr_in external_addr;
180
181   /**
182    * Address of the reporting STUN server.  Used to 
183    * detect when a STUN server changes its opinion
184    * to more quickly remove stale results.
185    */
186   struct sockaddr_storage stun_server_addr;
187
188   /**
189    * Number of bytes used in @e stun_server_addr.
190    */
191   size_t stun_server_addr_len;
192 };
193
194
195 /**
196  * Context for autoconfiguration operations.
197  */
198 struct AutoconfigContext
199 {
200   /**
201    * Kept in a DLL.
202    */
203   struct AutoconfigContext *prev;
204
205   /**
206    * Kept in a DLL.
207    */
208   struct AutoconfigContext *next;
209
210   /**
211    * Which client asked the question.
212    */
213   struct ClientHandle *ch;
214
215   /**
216    * Configuration we are creating.
217    */ 
218   struct GNUNET_CONFIGURATION_Handle *c;
219
220   /**
221    * Original configuration (for diffing).
222    */ 
223   struct GNUNET_CONFIGURATION_Handle *orig;
224
225   /**
226    * Timeout task to force termination.
227    */
228   struct GNUNET_SCHEDULER_Task *timeout_task;
229
230   /**
231    * What type of system are we on?
232    */
233   char *system_type;
234
235   /**
236    * Handle to activity to probe for our external IP.
237    */
238   struct GNUNET_NAT_ExternalHandle *probe_external;
239
240   /**
241    * #GNUNET_YES if upnpc should be used,
242    * #GNUNET_NO if upnpc should not be used,
243    * #GNUNET_SYSERR if we should simply not change the option.
244    */
245   int enable_upnpc;
246
247   /**
248    * Status code to return to the client.
249    */
250   enum GNUNET_NAT_StatusCode status_code;
251
252   /**
253    * NAT type to return to the client.
254    */
255   enum GNUNET_NAT_Type type;
256 };
257
258
259 /**
260  * DLL of our autoconfiguration operations.
261  */
262 static struct AutoconfigContext *ac_head;
263
264 /**
265  * DLL of our autoconfiguration operations.
266  */
267 static struct AutoconfigContext *ac_tail;
268
269 /**
270  * Timeout to use when STUN data is considered stale.
271  */
272 static struct GNUNET_TIME_Relative stun_stale_timeout;
273
274 /**
275  * Handle to our current configuration.
276  */
277 static const struct GNUNET_CONFIGURATION_Handle *cfg;
278
279 /**
280  * Handle to the statistics service.
281  */
282 static struct GNUNET_STATISTICS_Handle *stats;
283
284 /**
285  * Task scheduled to periodically scan our network interfaces.
286  */
287 static struct GNUNET_SCHEDULER_Task *scan_task;
288
289 /**
290  * Head of client DLL.
291  */
292 static struct ClientHandle *ch_head;
293   
294 /**
295  * Tail of client DLL.
296  */
297 static struct ClientHandle *ch_tail;
298
299 /**
300  * Head of DLL of local addresses.
301  */
302 static struct LocalAddressList *lal_head;
303
304 /**
305  * Tail of DLL of local addresses.
306  */
307 static struct LocalAddressList *lal_tail;
308
309 /**
310  * Kept in a DLL.
311  */ 
312 static struct StunExternalIP *se_head;
313
314 /**
315  * Kept in a DLL.
316  */ 
317 static struct StunExternalIP *se_tail;
318
319 /**
320  * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
321  * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
322  */
323 static int enable_upnp;
324
325
326 /**
327  * Free the DLL starting at #lal_head.
328  */ 
329 static void
330 destroy_lal ()
331 {
332   struct LocalAddressList *lal;
333
334   while (NULL != (lal = lal_head))
335   {
336     GNUNET_CONTAINER_DLL_remove (lal_head,
337                                  lal_tail,
338                                  lal);
339     GNUNET_free (lal);
340   }
341 }
342
343
344 /**
345  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
346  * client.
347  *
348  * @param cls client who sent the message
349  * @param message the message received
350  * @return #GNUNET_OK if message is well-formed
351  */
352 static int
353 check_register (void *cls,
354                 const struct GNUNET_NAT_RegisterMessage *message)
355 {
356   uint16_t num_addrs = ntohs (message->num_addrs);
357   const char *off = (const char *) &message[1];
358   size_t left = ntohs (message->header.size) - sizeof (*message);
359
360   for (unsigned int i=0;i<num_addrs;i++)
361   {
362     size_t alen;
363     const struct sockaddr *sa = (const struct sockaddr *) off;
364
365     if (sizeof (sa_family_t) > left)
366     {
367       GNUNET_break (0);
368       return GNUNET_SYSERR;
369     }
370     switch (sa->sa_family)
371     {
372     case AF_INET:
373       alen = sizeof (struct sockaddr_in);
374       break;
375     case AF_INET6:
376       alen = sizeof (struct sockaddr_in6);
377       break;
378 #if AF_UNIX
379     case AF_UNIX:
380       alen = sizeof (struct sockaddr_un);
381       break;
382 #endif
383     default:
384       GNUNET_break (0);
385       return GNUNET_SYSERR;      
386     }
387     if (alen > left)
388     {
389       GNUNET_break (0);
390       return GNUNET_SYSERR;      
391     }
392   }  
393   return GNUNET_OK; 
394 }
395
396
397 /**
398  * Check if @a ip is in @a network with @a bits netmask.
399  *
400  * @param network to test
401  * @param ip IP address to test
402  * @param bits bitmask for the network
403  * @return #GNUNET_YES if @a ip is in @a network
404  */
405 static int
406 match_ipv4 (const char *network,
407             const struct in_addr *ip,
408             uint8_t bits)
409 {
410   struct in_addr net;
411
412   if (0 == ip->s_addr)
413     return GNUNET_YES;
414   if (0 == bits)
415     return GNUNET_YES;
416   GNUNET_assert (1 == inet_pton (AF_INET,
417                                  network,
418                                  &net));
419   return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
420 }
421
422
423 /**
424  * Check if @a ip is in @a network with @a bits netmask.
425  *
426  * @param network to test
427  * @param ip IP address to test
428  * @param bits bitmask for the network
429  * @return #GNUNET_YES if @a ip is in @a network
430  */
431 static int
432 match_ipv6 (const char *network,
433             const struct in6_addr *ip,
434             uint8_t bits)
435 {
436   struct in6_addr net;
437   struct in6_addr mask;
438   unsigned int off;
439   
440   if (0 == bits)
441     return GNUNET_YES;
442   GNUNET_assert (1 == inet_pton (AF_INET6,
443                                  network,
444                                  &net));
445   memset (&mask, 0, sizeof (mask));
446   if (0 == memcmp (&mask,
447                    ip,
448                    sizeof (mask)))
449     return GNUNET_YES;
450   off = 0;
451   while (bits > 8)
452   {
453     mask.s6_addr[off++] = 0xFF;
454     bits -= 8;
455   }
456   while (bits > 0)
457   {
458     mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
459     bits--;
460   }
461   for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
462     if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
463         (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
464       return GNUNET_NO;
465   return GNUNET_YES;
466 }
467
468
469 /**
470  * Test if the given IPv4 address is in a known range
471  * for private networks.
472  *
473  * @param ip address to test
474  * @return #GNUNET_YES if @a ip is in a NAT range
475  */
476 static int
477 is_nat_v4 (const struct in_addr *ip)
478 {
479   return
480     match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
481     match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
482     match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
483     match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
484     match_ipv4 ("172.16.0.0", ip, 16);  /* RFC 1918 */
485 }
486
487
488 /**
489  * Test if the given IPv6 address is in a known range
490  * for private networks.
491  *
492  * @param ip address to test
493  * @return #GNUNET_YES if @a ip is in a NAT range
494  */
495 static int
496 is_nat_v6 (const struct in6_addr *ip)
497 {
498   return
499     match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
500     match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
501     match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
502 }
503
504
505 /**
506  * Closure for #ifc_proc.
507  */
508 struct IfcProcContext
509 {
510
511   /** 
512    * Head of DLL of local addresses.
513    */
514   struct LocalAddressList *lal_head;
515
516   /**
517    * Tail of DLL of local addresses.
518    */
519   struct LocalAddressList *lal_tail;
520
521 };
522
523
524 /**
525  * Callback function invoked for each interface found.  Adds them
526  * to our new address list.
527  *
528  * @param cls a `struct IfcProcContext *`
529  * @param name name of the interface (can be NULL for unknown)
530  * @param isDefault is this presumably the default interface
531  * @param addr address of this interface (can be NULL for unknown or unassigned)
532  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
533  * @param netmask the network mask (can be NULL for unknown or unassigned)
534  * @param addrlen length of the address
535  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
536  */
537 static int
538 ifc_proc (void *cls,
539           const char *name,
540           int isDefault,
541           const struct sockaddr *addr,
542           const struct sockaddr *broadcast_addr,
543           const struct sockaddr *netmask,
544           socklen_t addrlen)
545 {
546   struct IfcProcContext *ifc_ctx = cls;
547   struct LocalAddressList *lal;
548   size_t alen;
549   const struct in_addr *ip4;
550   const struct in6_addr *ip6;
551   enum GNUNET_NAT_AddressClass ac;
552
553   switch (addr->sa_family)
554   {
555   case AF_INET:
556     alen = sizeof (struct sockaddr_in);
557     ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
558     if (match_ipv4 ("127.0.0.0", ip4, 8))
559       ac = GNUNET_NAT_AC_LOOPBACK;
560     else if (is_nat_v4 (ip4))
561       ac = GNUNET_NAT_AC_LAN;
562     else
563       ac = GNUNET_NAT_AC_GLOBAL;
564     break;
565   case AF_INET6:
566     alen = sizeof (struct sockaddr_in6);
567     ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
568     if (match_ipv6 ("::1", ip6, 128))
569       ac = GNUNET_NAT_AC_LOOPBACK;
570     else if (is_nat_v6 (ip6))
571       ac = GNUNET_NAT_AC_LAN;
572     else
573       ac = GNUNET_NAT_AC_GLOBAL;
574     if ( (ip6->s6_addr[11] == 0xFF) &&
575          (ip6->s6_addr[12] == 0xFE) )
576     {
577       /* contains a MAC, be extra careful! */
578       ac |= GNUNET_NAT_AC_PRIVATE;
579     }
580     break;
581 #if AF_UNIX
582   case AF_UNIX:
583     GNUNET_break (0);
584     return GNUNET_OK;
585 #endif
586   default:
587     GNUNET_break (0);
588     return GNUNET_OK;
589   }
590   lal = GNUNET_malloc (sizeof (*lal));
591   lal->af = addr->sa_family;
592   lal->ac = ac;
593   GNUNET_memcpy (&lal->addr,
594                  addr,
595                  alen);
596   GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
597                                ifc_ctx->lal_tail,
598                                lal);
599   return GNUNET_OK;
600 }
601
602
603 /**
604  * Notify client about a change in the list of addresses this peer
605  * has.
606  *
607  * @param delta the entry in the list that changed
608  * @param ch client to contact
609  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
610  * @param addr the address that changed
611  * @param addr_len number of bytes in @a addr
612  */
613 static void
614 notify_client (struct LocalAddressList *delta,
615                struct ClientHandle *ch,
616                int add,
617                const void *addr,
618                size_t addr_len)
619 {
620   struct GNUNET_MQ_Envelope *env;
621   struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
622   
623   env = GNUNET_MQ_msg_extra (msg,
624                              addr_len,
625                              GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
626   msg->add_remove = htonl (add);
627   msg->addr_class = htonl (delta->ac);
628   GNUNET_memcpy (&msg[1],
629                  addr,
630                  addr_len);
631   GNUNET_MQ_send (ch->mq,
632                   env);
633 }                      
634
635
636 /**
637  * Check if we should bother to notify this client about this
638  * address change, and if so, do it.
639  *
640  * @param delta the entry in the list that changed
641  * @param ch client to check
642  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
643  */
644 static void
645 check_notify_client (struct LocalAddressList *delta,
646                      struct ClientHandle *ch,
647                      int add)
648 {
649   size_t alen;
650   struct sockaddr_in v4;
651   struct sockaddr_in6 v6;
652   
653   if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
654     return;
655   switch (delta->af)
656   {
657   case AF_INET:
658     alen = sizeof (struct sockaddr_in);
659     GNUNET_memcpy (&v4,
660                    &delta->addr,
661                    alen);
662     for (unsigned int i=0;i<ch->num_addrs;i++)
663     {
664       const struct sockaddr_in *c4;
665       
666       if (AF_INET != ch->addrs[i]->sa_family)
667         return; /* IPv4 not relevant */
668       c4 = (const struct sockaddr_in *) ch->addrs[i];
669       v4.sin_port = c4->sin_port;
670       notify_client (delta,
671                      ch,
672                      add,
673                      &v4,
674                      alen);
675     }
676     break;
677   case AF_INET6:
678     alen = sizeof (struct sockaddr_in6);
679     GNUNET_memcpy (&v6,
680                    &delta->addr,
681                    alen);
682     for (unsigned int i=0;i<ch->num_addrs;i++)
683     {
684       const struct sockaddr_in6 *c6;
685       
686       if (AF_INET6 != ch->addrs[i]->sa_family)
687         return; /* IPv4 not relevant */
688       c6 = (const struct sockaddr_in6 *) ch->addrs[i];
689       v6.sin6_port = c6->sin6_port;
690       notify_client (delta,
691                      ch,
692                      add,
693                      &v6,
694                      alen);
695     }
696     break;
697   default:
698     GNUNET_break (0);
699     return;
700   }
701 }
702
703
704 /**
705  * Notify all clients about a change in the list
706  * of addresses this peer has.
707  *
708  * @param delta the entry in the list that changed
709  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
710  */
711 static void
712 notify_clients (struct LocalAddressList *delta,
713                 int add)
714 {
715   for (struct ClientHandle *ch = ch_head;
716        NULL != ch;
717        ch = ch->next)
718     check_notify_client (delta,
719                          ch,
720                          add);
721 }
722
723
724 /**
725  * Task we run periodically to scan for network interfaces.
726  *
727  * @param cls NULL
728  */ 
729 static void
730 run_scan (void *cls)
731 {
732   struct IfcProcContext ifc_ctx;
733   int found;
734   
735   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
736                                             &run_scan,
737                                             NULL);
738   memset (&ifc_ctx,
739           0,
740           sizeof (ifc_ctx));
741   GNUNET_OS_network_interfaces_list (&ifc_proc,
742                                      &ifc_ctx);
743   /* remove addresses that disappeared */
744   for (struct LocalAddressList *lal = lal_head;
745        NULL != lal;
746        lal = lal->next)
747   {
748     found = GNUNET_NO;
749     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
750          NULL != pos;
751          pos = pos->next)
752     {
753       if ( (pos->af == lal->af) &&
754            (0 == memcmp (&lal->addr,
755                          &pos->addr,
756                          (AF_INET == lal->af)
757                          ? sizeof (struct sockaddr_in)
758                          : sizeof (struct sockaddr_in6))) )
759         found = GNUNET_YES;
760     }
761     if (GNUNET_NO == found)
762       notify_clients (lal,
763                       GNUNET_NO);
764   }
765
766   /* add addresses that appeared */
767   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
768        NULL != pos;
769        pos = pos->next)
770   {
771     found = GNUNET_NO;
772     for (struct LocalAddressList *lal = lal_head;
773          NULL != lal;
774          lal = lal->next)
775     {
776       if ( (pos->af == lal->af) &&
777            (0 == memcmp (&lal->addr,
778                          &pos->addr,
779                          (AF_INET == lal->af)
780                          ? sizeof (struct sockaddr_in)
781                          : sizeof (struct sockaddr_in6))) )
782         found = GNUNET_YES;
783     }
784     if (GNUNET_NO == found)
785       notify_clients (pos,
786                       GNUNET_YES);
787   }
788
789   destroy_lal ();
790   lal_head = ifc_ctx.lal_head;
791   lal_tail = ifc_ctx.lal_tail;
792 }
793
794
795 /**
796  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
797  * We remember the client for updates upon future NAT events.
798  *
799  * @param cls client who sent the message
800  * @param message the message received
801  */
802 static void
803 handle_register (void *cls,
804                  const struct GNUNET_NAT_RegisterMessage *message)
805 {
806   struct ClientHandle *ch = cls;
807   const char *off;
808   size_t left;
809
810   if ( (0 != ch->proto) ||
811        (NULL != ch->addrs) )
812   {
813     /* double registration not allowed */
814     GNUNET_break (0);
815     GNUNET_SERVICE_client_drop (ch->client);
816     return;
817   }
818   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819               "Received REGISTER message from client\n");
820   ch->flags = message->flags;
821   ch->proto = message->proto;
822   ch->adv_port = ntohs (message->adv_port);
823   ch->num_addrs = ntohs (message->num_addrs);
824   ch->addrs = GNUNET_new_array (ch->num_addrs,
825                                 struct sockaddr *);
826   left = ntohs (message->header.size) - sizeof (*message);
827   off = (const char *) &message[1];
828   for (unsigned int i=0;i<ch->num_addrs;i++)
829   {
830     size_t alen;
831     const struct sockaddr *sa = (const struct sockaddr *) off;
832
833     if (sizeof (sa_family_t) > left)
834     {
835       GNUNET_break (0);
836       GNUNET_SERVICE_client_drop (ch->client);
837       return;
838     }
839     switch (sa->sa_family)
840     {
841     case AF_INET:
842       {
843         const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
844         
845         alen = sizeof (struct sockaddr_in);
846         if (is_nat_v4 (&s4->sin_addr))
847           ch->natted_address = GNUNET_YES;
848       }
849       break;
850     case AF_INET6:
851       {
852         const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
853         
854         alen = sizeof (struct sockaddr_in6);
855         if (is_nat_v6 (&s6->sin6_addr))
856           ch->natted_address = GNUNET_YES;
857       }
858       break;
859 #if AF_UNIX
860     case AF_UNIX:
861       alen = sizeof (struct sockaddr_un);
862       break;
863 #endif
864     default:
865       GNUNET_break (0);
866       GNUNET_SERVICE_client_drop (ch->client);
867       return;      
868     }
869     GNUNET_assert (alen <= left);
870     ch->addrs[i] = GNUNET_malloc (alen);
871     GNUNET_memcpy (ch->addrs[i],
872                    sa,
873                    alen);    
874     off += alen;
875   }
876   /* Actually send IP address list to client */
877   for (struct LocalAddressList *lal = lal_head;
878        NULL != lal;
879        lal = lal->next)
880   {
881     check_notify_client (lal,
882                          ch,
883                          GNUNET_YES);
884   }
885   GNUNET_SERVICE_client_continue (ch->client);
886 }
887
888
889 /**
890  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
891  * client.
892  *
893  * @param cls client who sent the message
894  * @param message the message received
895  * @return #GNUNET_OK if message is well-formed
896  */
897 static int
898 check_stun (void *cls,
899             const struct GNUNET_NAT_HandleStunMessage *message)
900 {
901   size_t sa_len = ntohs (message->sender_addr_size);
902   size_t expect = sa_len + ntohs (message->payload_size);
903   
904   if (ntohs (message->header.size) - sizeof (*message) != expect)
905   {
906     GNUNET_break (0);
907     return GNUNET_SYSERR;
908   }
909   if (sa_len < sizeof (sa_family_t))
910   {
911     GNUNET_break (0);
912     return GNUNET_SYSERR;
913   }
914   return GNUNET_OK;
915 }
916
917
918 /**
919  * Notify all clients about our external IP address
920  * as reported by the STUN server.
921  *
922  * @param ip the external IP
923  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
924  */
925 static void
926 notify_clients_stun_change (const struct sockaddr_in *ip,
927                             int add)
928 {
929   for (struct ClientHandle *ch = ch_head;
930        NULL != ch;
931        ch = ch->next)
932   {
933     struct sockaddr_in v4;
934     struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
935     struct GNUNET_MQ_Envelope *env;
936     
937     if (! ch->natted_address)
938       continue;
939     v4 = *ip;
940     v4.sin_port = htons (ch->adv_port);
941     env = GNUNET_MQ_msg_extra (msg,
942                                sizeof (v4),
943                                GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
944     msg->add_remove = htonl ((int32_t) add);
945     msg->addr_class = htonl (GNUNET_NAT_AC_GLOBAL_EXTERN |
946                              GNUNET_NAT_AC_GLOBAL);
947     GNUNET_memcpy (&msg[1],
948                    &v4,
949                    sizeof (v4));
950     GNUNET_MQ_send (ch->mq,
951                     env);
952   }
953 }
954
955
956 /**
957  * Function to be called when we decide that an
958  * external IP address as told to us by a STUN
959  * server has gone stale.
960  *
961  * @param cls the `struct StunExternalIP` to drop
962  */
963 static void
964 stun_ip_timeout (void *cls)
965 {
966   struct StunExternalIP *se = cls;
967
968   se->timeout_task = NULL;
969   notify_clients_stun_change (&se->external_addr,
970                               GNUNET_NO);
971   GNUNET_CONTAINER_DLL_remove (se_head,
972                                se_tail,
973                                se);
974   GNUNET_free (se);
975 }
976
977
978 /**
979  * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
980  * client.
981  *
982  * @param cls client who sent the message
983  * @param message the message received
984  */
985 static void
986 handle_stun (void *cls,
987              const struct GNUNET_NAT_HandleStunMessage *message)
988 {
989   struct ClientHandle *ch = cls;
990   const char *buf = (const char *) &message[1];
991   const struct sockaddr *sa;
992   const void *payload;
993   size_t sa_len;
994   size_t payload_size;
995   struct sockaddr_in external_addr;
996
997   sa_len = ntohs (message->sender_addr_size);
998   payload_size = ntohs (message->payload_size);
999   sa = (const struct sockaddr *) &buf[0];
1000   payload = (const struct sockaddr *) &buf[sa_len];
1001   switch (sa->sa_family)
1002   {
1003   case AF_INET:
1004     if (sa_len != sizeof (struct sockaddr_in))
1005     {
1006       GNUNET_break (0);
1007       GNUNET_SERVICE_client_drop (ch->client);
1008       return;
1009     }
1010     break;
1011   case AF_INET6:
1012     if (sa_len != sizeof (struct sockaddr_in6))
1013     {
1014       GNUNET_break (0);
1015       GNUNET_SERVICE_client_drop (ch->client);
1016       return;
1017     }
1018     break;
1019   }
1020   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1021               "Received HANDLE_STUN message from client\n");
1022   if (GNUNET_OK ==
1023       GNUNET_NAT_stun_handle_packet_ (payload,
1024                                       payload_size,
1025                                       &external_addr))
1026   {     
1027     /* We now know that a server at "sa" claims that
1028        we are visible at IP "external_addr". 
1029
1030        We should (for some fixed period of time) tell
1031        all of our clients that listen to a NAT'ed address
1032        that they might want to consider the given 'external_ip'
1033        as their public IP address (this includes TCP and UDP
1034        clients, even if only UDP sends STUN requests).
1035
1036        If we do not get a renewal, the "external_addr" should be
1037        removed again.  The timeout frequency should be configurable
1038        (with a sane default), so that the UDP plugin can tell how
1039        often to re-request STUN.
1040     */
1041     struct StunExternalIP *se;
1042
1043     /* Check if we had a prior response from this STUN server */
1044     for (se = se_head; NULL != se; se = se->next)
1045     {
1046       if ( (se->stun_server_addr_len != sa_len) ||
1047            (0 != memcmp (sa,
1048                          &se->stun_server_addr,
1049                          sa_len)) )
1050         continue; /* different STUN server */
1051       if (0 != memcmp (&external_addr,
1052                        &se->external_addr,
1053                        sizeof (struct sockaddr_in)))
1054       {
1055         /* external IP changed, update! */
1056         notify_clients_stun_change (&se->external_addr,
1057                                     GNUNET_NO);
1058         se->external_addr = external_addr;
1059         notify_clients_stun_change (&se->external_addr,
1060                                     GNUNET_YES);
1061       }
1062       /* update timeout */
1063       GNUNET_SCHEDULER_cancel (se->timeout_task);
1064       se->timeout_task
1065         = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1066                                         &stun_ip_timeout,
1067                                         se);
1068       return;
1069     }
1070     /* STUN server is completely new, create fresh entry */
1071     se = GNUNET_new (struct StunExternalIP);
1072     se->external_addr = external_addr;
1073     GNUNET_memcpy (&se->stun_server_addr,
1074                    sa,
1075                    sa_len);
1076     se->stun_server_addr_len = sa_len;
1077     se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1078                                                      &stun_ip_timeout,
1079                                                      se);
1080     GNUNET_CONTAINER_DLL_insert (se_head,
1081                                  se_tail,
1082                                  se);
1083     notify_clients_stun_change (&se->external_addr,
1084                                 GNUNET_NO);
1085   }
1086   GNUNET_SERVICE_client_continue (ch->client);
1087 }
1088
1089
1090 /**
1091  * Check validity of
1092  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1093  * client.
1094  *
1095  * @param cls client who sent the message
1096  * @param message the message received
1097  * @return #GNUNET_OK if message is well-formed
1098  */
1099 static int
1100 check_request_connection_reversal (void *cls,
1101                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1102 {
1103   size_t expect;
1104
1105   expect = ntohs (message->local_addr_size)
1106     + ntohs (message->remote_addr_size);
1107   if (ntohs (message->header.size) - sizeof (*message) != expect)
1108   {
1109     GNUNET_break (0);
1110     return GNUNET_SYSERR;
1111   }
1112   return GNUNET_OK;
1113 }
1114
1115
1116 /**
1117  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1118  * message from client.
1119  *
1120  * @param cls client who sent the message
1121  * @param message the message received
1122  */
1123 static void
1124 handle_request_connection_reversal (void *cls,
1125                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1126 {
1127   struct ClientHandle *ch = cls;
1128   const char *buf = (const char *) &message[1];
1129   size_t local_sa_len = ntohs (message->local_addr_size);
1130   size_t remote_sa_len = ntohs (message->remote_addr_size);
1131   const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1132   const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1133   const struct sockaddr_in *l4 = NULL;
1134   const struct sockaddr_in *r4;
1135   int ret;
1136   
1137   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1138               "Received REQUEST CONNECTION REVERSAL message from client\n");
1139   switch (local_sa->sa_family)
1140   {
1141   case AF_INET:
1142     if (local_sa_len != sizeof (struct sockaddr_in))
1143     {
1144       GNUNET_break (0);
1145       GNUNET_SERVICE_client_drop (ch->client);
1146       return;
1147     }
1148     l4 = (const struct sockaddr_in *) local_sa;    
1149     break;
1150   case AF_INET6:
1151     if (local_sa_len != sizeof (struct sockaddr_in6))
1152     {
1153       GNUNET_break (0);
1154       GNUNET_SERVICE_client_drop (ch->client);
1155       return;
1156     }
1157     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1158                 _("Connection reversal for IPv6 not supported yet\n"));
1159     ret = GNUNET_SYSERR;
1160     break;
1161   default:
1162     GNUNET_break (0);
1163     GNUNET_SERVICE_client_drop (ch->client);
1164     return;
1165   }
1166   switch (remote_sa->sa_family)
1167   {
1168   case AF_INET:
1169     if (remote_sa_len != sizeof (struct sockaddr_in))
1170     {
1171       GNUNET_break (0);
1172       GNUNET_SERVICE_client_drop (ch->client);
1173       return;
1174     }
1175     r4 = (const struct sockaddr_in *) remote_sa;
1176     ret = GN_request_connection_reversal (&l4->sin_addr,
1177                                           ntohs (l4->sin_port),
1178                                           &r4->sin_addr);
1179     break;
1180   case AF_INET6:
1181     if (remote_sa_len != sizeof (struct sockaddr_in6))
1182     {
1183       GNUNET_break (0);
1184       GNUNET_SERVICE_client_drop (ch->client);
1185       return;
1186     }
1187     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1188                 _("Connection reversal for IPv6 not supported yet\n"));
1189     ret = GNUNET_SYSERR;
1190     break;
1191   default:
1192     GNUNET_break (0);
1193     GNUNET_SERVICE_client_drop (ch->client);
1194     return;
1195   }
1196   if (GNUNET_OK != ret)
1197     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1198                 _("Connection reversal request failed\n"));  
1199   GNUNET_SERVICE_client_continue (ch->client);
1200 }
1201
1202
1203 /**
1204  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1205  * from client.
1206  *
1207  * @param cls client who sent the message
1208  * @param message the message received
1209  * @return #GNUNET_OK if message is well-formed
1210  */
1211 static int
1212 check_autoconfig_request (void *cls,
1213                           const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1214 {
1215   return GNUNET_OK;  /* checked later */
1216 }
1217
1218
1219 /**
1220  * Stop all pending activities with respect to the @a ac
1221  *
1222  * @param ac autoconfiguration to terminate activities for
1223  */
1224 static void
1225 terminate_ac_activities (struct AutoconfigContext *ac)
1226 {
1227   if (NULL != ac->probe_external)
1228   {
1229     GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1230     ac->probe_external = NULL;
1231   }
1232   if (NULL != ac->timeout_task)
1233   {
1234     GNUNET_SCHEDULER_cancel (ac->timeout_task);
1235     ac->timeout_task = NULL;
1236   }
1237 }
1238
1239
1240 /**
1241  * Finish handling the autoconfiguration request and send
1242  * the response to the client.
1243  *
1244  * @param cls the `struct AutoconfigContext` to conclude
1245  */
1246 static void
1247 conclude_autoconfig_request (void *cls)
1248 {
1249   struct AutoconfigContext *ac = cls;
1250   struct ClientHandle *ch = ac->ch;
1251   struct GNUNET_NAT_AutoconfigResultMessage *arm;
1252   struct GNUNET_MQ_Envelope *env;
1253   size_t c_size;
1254   char *buf;
1255   struct GNUNET_CONFIGURATION_Handle *diff;
1256   
1257   ac->timeout_task = NULL;
1258   terminate_ac_activities (ac);
1259
1260   /* Send back response */
1261   diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1262                                         ac->c);
1263   buf = GNUNET_CONFIGURATION_serialize (diff,
1264                                         &c_size);
1265   GNUNET_CONFIGURATION_destroy (diff);
1266   env = GNUNET_MQ_msg_extra (arm,
1267                              c_size,
1268                              GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1269   arm->status_code = htonl ((uint32_t) ac->status_code);
1270   arm->type = htonl ((uint32_t) ac->type);
1271   GNUNET_memcpy (&arm[1],
1272                  buf,
1273                  c_size);
1274   GNUNET_free (buf);
1275   GNUNET_MQ_send (ch->mq,
1276                   env);
1277
1278   /* clean up */
1279   GNUNET_free (ac->system_type);
1280   GNUNET_CONFIGURATION_destroy (ac->orig);
1281   GNUNET_CONFIGURATION_destroy (ac->c);
1282   GNUNET_CONTAINER_DLL_remove (ac_head,
1283                                ac_tail,
1284                                ac);
1285   GNUNET_free (ac);
1286   GNUNET_SERVICE_client_continue (ch->client);
1287 }
1288
1289
1290 /**
1291  * Check if all autoconfiguration operations have concluded,
1292  * and if they have, send the result back to the client.
1293  *
1294  * @param ac autoconfiguation context to check
1295  */
1296 static void
1297 check_autoconfig_finished (struct AutoconfigContext *ac)
1298 {
1299   if (NULL != ac->probe_external)
1300     return;
1301   GNUNET_SCHEDULER_cancel (ac->timeout_task);
1302   ac->timeout_task
1303     = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1304                                 ac);
1305 }
1306
1307
1308 /**
1309  * Update ENABLE_UPNPC configuration option.
1310  *
1311  * @param ac autoconfiguration to update
1312  */
1313 static void
1314 update_enable_upnpc_option (struct AutoconfigContext *ac)
1315 {
1316   switch (ac->enable_upnpc)
1317   {
1318   case GNUNET_YES:
1319     GNUNET_CONFIGURATION_set_value_string (ac->c,
1320                                            "NAT",
1321                                            "ENABLE_UPNPC",
1322                                            "YES");
1323     break;
1324   case GNUNET_NO:
1325     GNUNET_CONFIGURATION_set_value_string (ac->c,
1326                                            "NAT",
1327                                            "ENABLE_UPNPC",
1328                                            "NO");
1329     break;
1330   case GNUNET_SYSERR:
1331     /* We are unsure, do not change option */
1332     break;
1333   }
1334 }
1335
1336
1337 /**
1338  * Handle result from external IP address probe during
1339  * autoconfiguration.
1340  *
1341  * @param cls our `struct AutoconfigContext`
1342  * @param addr the address, NULL on errors
1343  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1344  */
1345 static void
1346 auto_external_result_cb (void *cls,
1347                          const struct in_addr *addr,
1348                          enum GNUNET_NAT_StatusCode result)
1349 {
1350   struct AutoconfigContext *ac = cls;
1351
1352   ac->probe_external = NULL;
1353   switch (result)
1354   {
1355   case GNUNET_NAT_ERROR_SUCCESS:
1356     ac->enable_upnpc = GNUNET_YES;
1357     break;
1358   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1359   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1360   case GNUNET_NAT_ERROR_IPC_FAILURE:
1361     ac->enable_upnpc = GNUNET_NO; /* did not work */
1362     break;
1363   default:
1364     GNUNET_break (0); /* unexpected */
1365     ac->enable_upnpc = GNUNET_SYSERR;
1366     break;    
1367   }
1368   update_enable_upnpc_option (ac);
1369   check_autoconfig_finished (ac);
1370 }
1371
1372
1373 /**
1374  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1375  * client.
1376  *
1377  * @param cls client who sent the message
1378  * @param message the message received
1379  */
1380 static void
1381 handle_autoconfig_request (void *cls,
1382                            const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1383 {
1384   struct ClientHandle *ch = cls;
1385   size_t left = ntohs (message->header.size) - sizeof (*message);
1386   struct LocalAddressList *lal;
1387   struct AutoconfigContext *ac;
1388
1389   ac = GNUNET_new (struct AutoconfigContext);
1390   ac->ch = ch;
1391   ac->c = GNUNET_CONFIGURATION_create ();
1392   if (GNUNET_OK !=
1393       GNUNET_CONFIGURATION_deserialize (ac->c,
1394                                         (const char *) &message[1],
1395                                         left,
1396                                         GNUNET_NO))
1397   {
1398     GNUNET_break (0);
1399     GNUNET_SERVICE_client_drop (ch->client);
1400     GNUNET_CONFIGURATION_destroy (ac->c);
1401     GNUNET_free (ac);
1402     return;
1403   }
1404   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1405               "Received REQUEST_AUTO_CONFIG message from client\n");
1406
1407   if (GNUNET_OK !=
1408       GNUNET_CONFIGURATION_get_value_string (ac->c,
1409                                              "PEER",
1410                                              "SYSTEM_TYPE",
1411                                              &ac->system_type))
1412     ac->system_type = GNUNET_strdup ("UNKNOWN");
1413
1414   GNUNET_CONTAINER_DLL_insert (ac_head,
1415                                ac_tail,
1416                                ac);
1417   ac->orig
1418     = GNUNET_CONFIGURATION_dup (ac->c);
1419   ac->timeout_task
1420     = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1421                                     &conclude_autoconfig_request,
1422                                     ac);
1423   ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1424   
1425   /* Probe for upnpc */
1426   if (GNUNET_SYSERR ==
1427       GNUNET_OS_check_helper_binary ("upnpc",
1428                                      GNUNET_NO,
1429                                      NULL))
1430   {
1431     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1432                 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1433     ac->enable_upnpc = GNUNET_NO;
1434   }
1435   else
1436   {
1437     for (lal = lal_head; NULL != lal; lal = lal->next)
1438       if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
1439         /* we are behind NAT, useful to try upnpc */
1440         ac->enable_upnpc = GNUNET_YES;
1441   }
1442   if (GNUNET_YES == ac->enable_upnpc)
1443   {
1444     /* If we are a mobile device, always leave it on as the network
1445        may change to one that supports UPnP anytime.  If we are
1446        stationary, check if our network actually supports UPnP, and if
1447        not, disable it. */
1448     if ( (0 == strcasecmp (ac->system_type,
1449                            "INFRASTRUCTURE")) ||
1450          (0 == strcasecmp (ac->system_type,
1451                            "DESKTOP")) )
1452     {
1453       /* Check if upnpc gives us an external IP */
1454       ac->probe_external
1455         = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
1456                                               ac);
1457     }
1458   }
1459   if (NULL == ac->probe_external)
1460     update_enable_upnpc_option (ac);
1461
1462   /* Finally, check if we are already done */  
1463   check_autoconfig_finished (ac);
1464 }
1465
1466
1467 /**
1468  * Task run during shutdown.
1469  *
1470  * @param cls unused
1471  */
1472 static void
1473 shutdown_task (void *cls)
1474 {
1475   struct StunExternalIP *se;
1476   struct AutoconfigContext *ac;
1477
1478   while (NULL != (ac = ac_head))
1479   {
1480     GNUNET_CONTAINER_DLL_remove (ac_head,
1481                                  ac_tail,
1482                                  ac);
1483     terminate_ac_activities (ac);
1484     GNUNET_free (ac);
1485   }
1486   while (NULL != (se = se_head))
1487   {
1488     GNUNET_CONTAINER_DLL_remove (se_head,
1489                                  se_tail,
1490                                  se);
1491     GNUNET_SCHEDULER_cancel (se->timeout_task);
1492     GNUNET_free (se);
1493   }
1494   if (NULL != scan_task)
1495   {
1496     GNUNET_SCHEDULER_cancel (scan_task);
1497     scan_task = NULL;
1498   }
1499   if (NULL != stats)
1500   {
1501     GNUNET_STATISTICS_destroy (stats,
1502                                GNUNET_NO);
1503     stats = NULL;
1504   }
1505   destroy_lal ();
1506 }
1507
1508
1509 /**
1510  * Setup NAT service.
1511  *
1512  * @param cls closure
1513  * @param c configuration to use
1514  * @param service the initialized service
1515  */
1516 static void
1517 run (void *cls,
1518      const struct GNUNET_CONFIGURATION_Handle *c,
1519      struct GNUNET_SERVICE_Handle *service)
1520 {
1521   cfg = c;
1522   if (GNUNET_OK !=
1523       GNUNET_CONFIGURATION_get_value_time (cfg,
1524                                            "NAT",
1525                                            "STUN_STALE",
1526                                            &stun_stale_timeout))
1527     stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1528
1529   /* Check for UPnP */
1530   enable_upnp 
1531     = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1532                                             "NAT",
1533                                             "ENABLE_UPNP");
1534   if (GNUNET_YES == enable_upnp)
1535   {
1536     /* check if it works */
1537     if (GNUNET_SYSERR ==
1538         GNUNET_OS_check_helper_binary ("upnpc",
1539                                        GNUNET_NO,
1540                                        NULL))
1541     {
1542       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1543                   _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1544       enable_upnp = GNUNET_SYSERR;
1545     }
1546   }
1547   
1548   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1549                                  NULL);
1550   stats = GNUNET_STATISTICS_create ("nat",
1551                                     cfg);
1552   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1553                                         NULL);
1554 }
1555
1556
1557 /**
1558  * Callback called when a client connects to the service.
1559  *
1560  * @param cls closure for the service
1561  * @param c the new client that connected to the service
1562  * @param mq the message queue used to send messages to the client
1563  * @return a `struct ClientHandle`
1564  */
1565 static void *
1566 client_connect_cb (void *cls,
1567                    struct GNUNET_SERVICE_Client *c,
1568                    struct GNUNET_MQ_Handle *mq)
1569 {
1570   struct ClientHandle *ch;
1571
1572   ch = GNUNET_new (struct ClientHandle);
1573   ch->mq = mq;
1574   ch->client = c;
1575   GNUNET_CONTAINER_DLL_insert (ch_head,
1576                                ch_tail,
1577                                ch);
1578   return ch;
1579 }
1580
1581
1582 /**
1583  * Callback called when a client disconnected from the service
1584  *
1585  * @param cls closure for the service
1586  * @param c the client that disconnected
1587  * @param internal_cls a `struct ClientHandle *`
1588  */
1589 static void
1590 client_disconnect_cb (void *cls,
1591                       struct GNUNET_SERVICE_Client *c,
1592                       void *internal_cls)
1593 {
1594   struct ClientHandle *ch = internal_cls;
1595
1596   GNUNET_CONTAINER_DLL_remove (ch_head,
1597                                ch_tail,
1598                                ch);
1599   for (unsigned int i=0;i<ch->num_addrs;i++)
1600     GNUNET_free_non_null (ch->addrs[i]);
1601   GNUNET_free_non_null (ch->addrs);
1602   GNUNET_free (ch);
1603 }
1604
1605
1606 /**
1607  * Define "main" method using service macro.
1608  */
1609 GNUNET_SERVICE_MAIN
1610 ("nat",
1611  GNUNET_SERVICE_OPTION_NONE,
1612  &run,
1613  &client_connect_cb,
1614  &client_disconnect_cb,
1615  NULL,
1616  GNUNET_MQ_hd_var_size (register,
1617                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1618                         struct GNUNET_NAT_RegisterMessage,
1619                         NULL),
1620  GNUNET_MQ_hd_var_size (stun,
1621                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1622                         struct GNUNET_NAT_HandleStunMessage,
1623                         NULL),
1624  GNUNET_MQ_hd_var_size (request_connection_reversal,
1625                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1626                         struct GNUNET_NAT_RequestConnectionReversalMessage,
1627                         NULL),
1628  GNUNET_MQ_hd_var_size (autoconfig_request,
1629                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1630                         struct GNUNET_NAT_AutoconfigRequestMessage,
1631                         NULL),
1632  GNUNET_MQ_handler_end ());
1633
1634
1635 #if defined(LINUX) && defined(__GLIBC__)
1636 #include <malloc.h>
1637
1638 /**
1639  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1640  */
1641 void __attribute__ ((constructor))
1642 GNUNET_ARM_memory_init ()
1643 {
1644   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1645   mallopt (M_TOP_PAD, 1 * 1024);
1646   malloc_trim (0);
1647 }
1648 #endif
1649
1650 /* end of gnunet-service-nat.c */