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