Merge remote-tracking branch 'origin/master' into credentials
[oweals/gnunet.git] / src / nat / gnunet-service-nat.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2016, 2017 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  * - test and document (!) ICMP based NAT traversal
32  * - implement manual hole punching support (incl. DNS
33  *   lookup for DynDNS setups!)
34  * - implement "more" autoconfig:
35  *   re-work gnunet-nat-server & integrate!
36  *   + test manually punched NAT (how?)
37  * - implement & test STUN processing to classify NAT;
38  *   basically, open port & try different methods.
39  * - implement NEW logic for external IP detection
40  */
41 #include "platform.h"
42 #include <math.h>
43 #include "gnunet_util_lib.h"
44 #include "gnunet_protocols.h"
45 #include "gnunet_signatures.h"
46 #include "gnunet_statistics_service.h"
47 #include "gnunet_nat_service.h"
48 #include "gnunet-service-nat_stun.h"
49 #include "gnunet-service-nat_mini.h"
50 #include "gnunet-service-nat_helper.h"
51 #include "nat.h"
52 #include <gcrypt.h>
53
54
55 /**
56  * How often should we ask the OS about a list of active
57  * network interfaces?
58  */
59 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
60
61 /**
62  * How long do we wait until we forcefully terminate autoconfiguration?
63  */
64 #define AUTOCONFIG_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
65
66 /**
67  * How long do we wait until we re-try running `external-ip` if the
68  * command failed to terminate nicely?
69  */
70 #define EXTERN_IP_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
71
72 /**
73  * How long do we wait until we re-try running `external-ip` if the
74  * command failed (but terminated)?
75  */
76 #define EXTERN_IP_RETRY_FAILURE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
77
78 /**
79  * How long do we wait until we re-try running `external-ip` if the
80  * command succeeded?
81  */
82 #define EXTERN_IP_RETRY_SUCCESS GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
83
84
85 /**
86  * Information we track per client address. 
87  */
88 struct ClientAddress
89 {
90   /**
91    * Network address used by the client.
92    */
93   struct sockaddr_storage ss;
94
95   /**
96    * Handle to active UPnP request where we asked upnpc to open
97    * a port at the NAT.  NULL if we do not have such a request
98    * pending.
99    */
100   struct GNUNET_NAT_MiniHandle *mh;
101   
102 };
103
104
105 /**
106  * Internal data structure we track for each of our clients.
107  */
108 struct ClientHandle
109 {
110
111   /**
112    * Kept in a DLL.
113    */
114   struct ClientHandle *next;
115   
116   /**
117    * Kept in a DLL.
118    */
119   struct ClientHandle *prev;
120
121   /**
122    * Underlying handle for this client with the service.
123    */ 
124   struct GNUNET_SERVICE_Client *client;
125
126   /**
127    * Message queue for communicating with the client.
128    */
129   struct GNUNET_MQ_Handle *mq;
130
131   /**
132    * Array of addresses used by the service.
133    */
134   struct ClientAddress *caddrs;
135
136   /**
137    * External DNS name and port given by user due to manual
138    * hole punching.  Special DNS name 'AUTO' is used to indicate
139    * desire for automatic determination of the external IP 
140    * (instead of DNS or manual configuration, i.e. to be used 
141    * if the IP keeps changing and we have no DynDNS, but we do
142    * have a hole punched).
143    */
144   char *hole_external;
145   
146   /**
147    * What does this client care about?
148    */
149   enum GNUNET_NAT_RegisterFlags flags;
150
151   /**
152    * Is any of the @e caddrs in a reserved subnet for NAT?
153    */
154   int natted_address;
155   
156   /**
157    * Number of addresses that this service is bound to.
158    * Length of the @e caddrs array.
159    */
160   uint16_t num_caddrs;
161   
162   /**
163    * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
164    */
165   uint8_t proto;
166
167 };
168
169
170 /**
171  * List of local addresses this system has.
172  */
173 struct LocalAddressList
174 {
175   /**
176    * This is a linked list.
177    */
178   struct LocalAddressList *next;
179
180   /**
181    * Previous entry.
182    */
183   struct LocalAddressList *prev;
184
185   /**
186    * Context for a gnunet-helper-nat-server used to listen
187    * for ICMP messages to this client for connection reversal.
188    */
189   struct HelperContext *hc;
190   
191   /**
192    * The address itself (i.e. `struct sockaddr_in` or `struct
193    * sockaddr_in6`, in the respective byte order).
194    */
195   struct sockaddr_storage addr;
196
197   /**
198    * Address family.
199    */
200   int af;
201
202   /**
203    * What type of address is this?
204    */
205   enum GNUNET_NAT_AddressClass ac;
206   
207 };
208
209
210 /**
211  * External IP address as given to us via some STUN server.
212  */
213 struct StunExternalIP
214 {
215   /**
216    * Kept in a DLL.
217    */ 
218   struct StunExternalIP *next;
219
220   /**
221    * Kept in a DLL.
222    */ 
223   struct StunExternalIP *prev;
224
225   /**
226    * Task we run to remove this entry when it is stale.
227    */
228   struct GNUNET_SCHEDULER_Task *timeout_task;
229
230   /**
231    * Our external IP address as reported by the 
232    * STUN server.
233    */
234   struct sockaddr_in external_addr;
235
236   /**
237    * Address of the reporting STUN server.  Used to 
238    * detect when a STUN server changes its opinion
239    * to more quickly remove stale results.
240    */
241   struct sockaddr_storage stun_server_addr;
242
243   /**
244    * Number of bytes used in @e stun_server_addr.
245    */
246   size_t stun_server_addr_len;
247 };
248
249
250 /**
251  * Context for autoconfiguration operations.
252  */
253 struct AutoconfigContext
254 {
255   /**
256    * Kept in a DLL.
257    */
258   struct AutoconfigContext *prev;
259
260   /**
261    * Kept in a DLL.
262    */
263   struct AutoconfigContext *next;
264
265   /**
266    * Which client asked the question.
267    */
268   struct ClientHandle *ch;
269
270   /**
271    * Configuration we are creating.
272    */ 
273   struct GNUNET_CONFIGURATION_Handle *c;
274
275   /**
276    * Original configuration (for diffing).
277    */ 
278   struct GNUNET_CONFIGURATION_Handle *orig;
279
280   /**
281    * Timeout task to force termination.
282    */
283   struct GNUNET_SCHEDULER_Task *timeout_task;
284
285   /**
286    * What type of system are we on?
287    */
288   char *system_type;
289
290   /**
291    * Handle to activity to probe for our external IP.
292    */
293   struct GNUNET_NAT_ExternalHandle *probe_external;
294
295   /**
296    * #GNUNET_YES if upnpc should be used,
297    * #GNUNET_NO if upnpc should not be used,
298    * #GNUNET_SYSERR if we should simply not change the option.
299    */
300   int enable_upnpc;
301
302   /**
303    * Status code to return to the client.
304    */
305   enum GNUNET_NAT_StatusCode status_code;
306
307   /**
308    * NAT type to return to the client.
309    */
310   enum GNUNET_NAT_Type type;
311 };
312
313
314 /**
315  * DLL of our autoconfiguration operations.
316  */
317 static struct AutoconfigContext *ac_head;
318
319 /**
320  * DLL of our autoconfiguration operations.
321  */
322 static struct AutoconfigContext *ac_tail;
323
324 /**
325  * Timeout to use when STUN data is considered stale.
326  */
327 static struct GNUNET_TIME_Relative stun_stale_timeout;
328
329 /**
330  * Handle to our current configuration.
331  */
332 static const struct GNUNET_CONFIGURATION_Handle *cfg;
333
334 /**
335  * Handle to the statistics service.
336  */
337 static struct GNUNET_STATISTICS_Handle *stats;
338
339 /**
340  * Task scheduled to periodically scan our network interfaces.
341  */
342 static struct GNUNET_SCHEDULER_Task *scan_task;
343
344 /**
345  * Head of client DLL.
346  */
347 static struct ClientHandle *ch_head;
348   
349 /**
350  * Tail of client DLL.
351  */
352 static struct ClientHandle *ch_tail;
353
354 /**
355  * Head of DLL of local addresses.
356  */
357 static struct LocalAddressList *lal_head;
358
359 /**
360  * Tail of DLL of local addresses.
361  */
362 static struct LocalAddressList *lal_tail;
363
364 /**
365  * Kept in a DLL.
366  */ 
367 static struct StunExternalIP *se_head;
368
369 /**
370  * Kept in a DLL.
371  */ 
372 static struct StunExternalIP *se_tail;
373
374 /**
375  * Is UPnP enabled? #GNUNET_YES if enabled, #GNUNET_NO if disabled,
376  * #GNUNET_SYSERR if configuration enabled but binary is unavailable.
377  */
378 static int enable_upnp;
379
380 /**
381  * Task run to obtain our external IP (if #enable_upnp is set
382  * and if we find we have a NATed IP address).
383  */
384 static struct GNUNET_SCHEDULER_Task *probe_external_ip_task;
385
386 /**
387  * Handle to our operation to run `external-ip`.
388  */
389 static struct GNUNET_NAT_ExternalHandle *probe_external_ip_op;
390
391 /**
392  * What is our external IP address as claimed by `external-ip`?
393  * 0 for unknown.
394  */
395 static struct in_addr mini_external_ipv4;
396
397
398 /**
399  * Remove and free an entry from the #lal_head DLL.
400  *
401  * @param lal entry to free
402  */
403 static void
404 free_lal (struct LocalAddressList *lal)
405 {
406   GNUNET_CONTAINER_DLL_remove (lal_head,
407                                lal_tail,
408                                lal);
409   if (NULL != lal->hc)
410   {
411     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
412                 "Lost NATed local address %s, stopping NAT server\n",
413                 GNUNET_a2s ((const struct sockaddr *) &lal->addr,
414                             sizeof (struct sockaddr_in)));
415
416     GN_stop_gnunet_nat_server_ (lal->hc);
417     lal->hc = NULL;
418   }
419   GNUNET_free (lal);
420 }
421
422
423 /**
424  * Free the DLL starting at #lal_head.
425  */ 
426 static void
427 destroy_lal ()
428 {
429   struct LocalAddressList *lal;
430
431   while (NULL != (lal = lal_head))
432     free_lal (lal);
433 }
434
435
436 /**
437  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
438  * client.
439  *
440  * @param cls client who sent the message
441  * @param message the message received
442  * @return #GNUNET_OK if message is well-formed
443  */
444 static int
445 check_register (void *cls,
446                 const struct GNUNET_NAT_RegisterMessage *message)
447 {
448   uint16_t num_addrs = ntohs (message->num_addrs);
449   const char *off = (const char *) &message[1];
450   size_t left = ntohs (message->header.size) - sizeof (*message);
451
452   for (unsigned int i=0;i<num_addrs;i++)
453   {
454     size_t alen;
455     const struct sockaddr *sa = (const struct sockaddr *) off;
456
457     if (sizeof (sa_family_t) > left)
458     {
459       GNUNET_break (0);
460       return GNUNET_SYSERR;
461     }
462     switch (sa->sa_family)
463     {
464     case AF_INET:
465       alen = sizeof (struct sockaddr_in);
466       break;
467     case AF_INET6:
468       alen = sizeof (struct sockaddr_in6);
469       break;
470 #if AF_UNIX
471     case AF_UNIX:
472       alen = sizeof (struct sockaddr_un);
473       break;
474 #endif
475     default:
476       GNUNET_break (0);
477       return GNUNET_SYSERR;      
478     }
479     if (alen > left)
480     {
481       GNUNET_break (0);
482       return GNUNET_SYSERR;      
483     }
484     off += alen;
485     left -= alen;
486   }
487   if (left != ntohs (message->hole_external_len))
488   {
489     GNUNET_break (0);
490     return GNUNET_SYSERR;      
491   }
492   return GNUNET_OK; 
493 }
494
495
496 /**
497  * Check if @a ip is in @a network with @a bits netmask.
498  *
499  * @param network to test
500  * @param ip IP address to test
501  * @param bits bitmask for the network
502  * @return #GNUNET_YES if @a ip is in @a network
503  */
504 static int
505 match_ipv4 (const char *network,
506             const struct in_addr *ip,
507             uint8_t bits)
508 {
509   struct in_addr net;
510
511   if (0 == ip->s_addr)
512     return GNUNET_YES;
513   if (0 == bits)
514     return GNUNET_YES;
515   GNUNET_assert (1 == inet_pton (AF_INET,
516                                  network,
517                                  &net));
518   return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
519 }
520
521
522 /**
523  * Check if @a ip is in @a network with @a bits netmask.
524  *
525  * @param network to test
526  * @param ip IP address to test
527  * @param bits bitmask for the network
528  * @return #GNUNET_YES if @a ip is in @a network
529  */
530 static int
531 match_ipv6 (const char *network,
532             const struct in6_addr *ip,
533             uint8_t bits)
534 {
535   struct in6_addr net;
536   struct in6_addr mask;
537   unsigned int off;
538   
539   if (0 == bits)
540     return GNUNET_YES;
541   GNUNET_assert (1 == inet_pton (AF_INET6,
542                                  network,
543                                  &net));
544   memset (&mask, 0, sizeof (mask));
545   if (0 == memcmp (&mask,
546                    ip,
547                    sizeof (mask)))
548     return GNUNET_YES;
549   off = 0;
550   while (bits > 8)
551   {
552     mask.s6_addr[off++] = 0xFF;
553     bits -= 8;
554   }
555   while (bits > 0)
556   {
557     mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
558     bits--;
559   }
560   for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
561     if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
562         (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
563       return GNUNET_NO;
564   return GNUNET_YES;
565 }
566
567
568 /**
569  * Test if the given IPv4 address is in a known range
570  * for private networks.
571  *
572  * @param ip address to test
573  * @return #GNUNET_YES if @a ip is in a NAT range
574  */
575 static int
576 is_nat_v4 (const struct in_addr *ip)
577 {
578   return
579     match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
580     match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
581     match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
582     match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
583     match_ipv4 ("172.16.0.0", ip, 16);  /* RFC 1918 */
584 }
585
586
587 /**
588  * Test if the given IPv6 address is in a known range
589  * for private networks.
590  *
591  * @param ip address to test
592  * @return #GNUNET_YES if @a ip is in a NAT range
593  */
594 static int
595 is_nat_v6 (const struct in6_addr *ip)
596 {
597   return
598     match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
599     match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
600     match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
601 }
602
603
604 /**
605  * Closure for #ifc_proc.
606  */
607 struct IfcProcContext
608 {
609
610   /** 
611    * Head of DLL of local addresses.
612    */
613   struct LocalAddressList *lal_head;
614
615   /**
616    * Tail of DLL of local addresses.
617    */
618   struct LocalAddressList *lal_tail;
619
620 };
621
622
623 /**
624  * Callback function invoked for each interface found.  Adds them
625  * to our new address list.
626  *
627  * @param cls a `struct IfcProcContext *`
628  * @param name name of the interface (can be NULL for unknown)
629  * @param isDefault is this presumably the default interface
630  * @param addr address of this interface (can be NULL for unknown or unassigned)
631  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
632  * @param netmask the network mask (can be NULL for unknown or unassigned)
633  * @param addrlen length of the address
634  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
635  */
636 static int
637 ifc_proc (void *cls,
638           const char *name,
639           int isDefault,
640           const struct sockaddr *addr,
641           const struct sockaddr *broadcast_addr,
642           const struct sockaddr *netmask,
643           socklen_t addrlen)
644 {
645   struct IfcProcContext *ifc_ctx = cls;
646   struct LocalAddressList *lal;
647   size_t alen;
648   const struct in_addr *ip4;
649   const struct in6_addr *ip6;
650   enum GNUNET_NAT_AddressClass ac;
651
652   switch (addr->sa_family)
653   {
654   case AF_INET:
655     alen = sizeof (struct sockaddr_in);
656     ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
657     if (match_ipv4 ("127.0.0.0", ip4, 8))
658       ac = GNUNET_NAT_AC_LOOPBACK;
659     else if (is_nat_v4 (ip4))
660       ac = GNUNET_NAT_AC_LAN;
661     else
662       ac = GNUNET_NAT_AC_GLOBAL;
663     break;
664   case AF_INET6:
665     alen = sizeof (struct sockaddr_in6);
666     ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
667     if (match_ipv6 ("::1", ip6, 128))
668       ac = GNUNET_NAT_AC_LOOPBACK;
669     else if (is_nat_v6 (ip6))
670       ac = GNUNET_NAT_AC_LAN;
671     else
672       ac = GNUNET_NAT_AC_GLOBAL;
673     if ( (ip6->s6_addr[11] == 0xFF) &&
674          (ip6->s6_addr[12] == 0xFE) )
675     {
676       /* contains a MAC, be extra careful! */
677       ac |= GNUNET_NAT_AC_PRIVATE;
678     }
679     break;
680 #if AF_UNIX
681   case AF_UNIX:
682     GNUNET_break (0);
683     return GNUNET_OK;
684 #endif
685   default:
686     GNUNET_break (0);
687     return GNUNET_OK;
688   }
689   lal = GNUNET_malloc (sizeof (*lal));
690   lal->af = addr->sa_family;
691   lal->ac = ac;
692   GNUNET_memcpy (&lal->addr,
693                  addr,
694                  alen);
695   GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
696                                ifc_ctx->lal_tail,
697                                lal);
698   return GNUNET_OK;
699 }
700
701
702 /**
703  * Notify client about a change in the list of addresses this peer
704  * has.
705  *
706  * @param ac address class of the entry in the list that changed
707  * @param ch client to contact
708  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
709  * @param addr the address that changed
710  * @param addr_len number of bytes in @a addr
711  */
712 static void
713 notify_client (enum GNUNET_NAT_AddressClass ac,
714                struct ClientHandle *ch,
715                int add,
716                const void *addr,
717                size_t addr_len)
718 {
719   struct GNUNET_MQ_Envelope *env;
720   struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
721   
722   env = GNUNET_MQ_msg_extra (msg,
723                              addr_len,
724                              GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
725   msg->add_remove = htonl (add);
726   msg->addr_class = htonl (ac);
727   GNUNET_memcpy (&msg[1],
728                  addr,
729                  addr_len);
730   GNUNET_MQ_send (ch->mq,
731                   env);
732 }                      
733
734
735 /**
736  * Check if we should bother to notify this client about this
737  * address change, and if so, do it.
738  *
739  * @param delta the entry in the list that changed
740  * @param ch client to check
741  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
742  */
743 static void
744 check_notify_client (struct LocalAddressList *delta,
745                      struct ClientHandle *ch,
746                      int add)
747 {
748   size_t alen;
749   struct sockaddr_in v4;
750   struct sockaddr_in6 v6;
751   
752   if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
753     return;
754   switch (delta->af)
755   {
756   case AF_INET:
757     alen = sizeof (struct sockaddr_in);
758     GNUNET_memcpy (&v4,
759                    &delta->addr,
760                    alen);
761     
762     /* Check for client notifications */
763     for (unsigned int i=0;i<ch->num_caddrs;i++)
764     {
765       const struct sockaddr_in *c4;
766
767       if (AF_INET != ch->caddrs[i].ss.ss_family)
768         return; /* IPv4 not relevant */
769       c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
770       if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
771            (0 != c4->sin_addr.s_addr) &&
772            (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
773         continue; /* bound to loopback, but this is not loopback */
774       if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
775            (0 != c4->sin_addr.s_addr) &&
776            match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
777         continue; /* bound to non-loopback, but this is loopback */
778       if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
779            (0 != c4->sin_addr.s_addr) &&
780            (! is_nat_v4 (&v4.sin_addr)) )
781         continue; /* based on external-IP, but this IP is not
782                      from private address range. */
783       if ( (0 != memcmp (&v4.sin_addr,
784                          &c4->sin_addr,
785                          sizeof (struct in_addr))) &&
786            (0 != c4->sin_addr.s_addr) &&
787            ( (! is_nat_v4 (&c4->sin_addr)) ||
788              (0 == (ch->flags & GNUNET_NAT_AC_EXTERN))) )
789         continue; /* this IP is not from private address range,
790                      and IP does not match. */
791
792       /* OK, IP seems relevant, notify client */
793       v4.sin_port = c4->sin_port;
794       notify_client (delta->ac,
795                      ch,
796                      add,
797                      &v4,
798                      alen);
799     }
800     break;
801   case AF_INET6:
802     alen = sizeof (struct sockaddr_in6);
803     GNUNET_memcpy (&v6,
804                    &delta->addr,
805                    alen);
806     for (unsigned int i=0;i<ch->num_caddrs;i++)
807     {
808       const struct sockaddr_in6 *c6;
809       
810       if (AF_INET6 != ch->caddrs[i].ss.ss_family)
811         return; /* IPv4 not relevant */
812       c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
813       if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
814            (0 != memcmp (&c6->sin6_addr,
815                          &in6addr_any,
816                          sizeof (struct in6_addr))) &&
817            (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
818         continue; /* bound to loopback, but this is not loopback */
819       if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
820            (0 != memcmp (&c6->sin6_addr,
821                          &in6addr_any,
822                          sizeof (struct in6_addr))) &&
823            match_ipv6 ("::1", &v6.sin6_addr, 128) )
824         continue; /* bound to non-loopback, but this is loopback */
825       if ( (0 != (ch->flags & GNUNET_NAT_AC_EXTERN)) &&
826            (0 != memcmp (&c6->sin6_addr,
827                          &in6addr_any,
828                          sizeof (struct in6_addr))) &&
829            (! is_nat_v6 (&v6.sin6_addr)) )
830         continue; /* based on external-IP, but this IP is not
831                      from private address range. */
832       if ( (0 != memcmp (&v6.sin6_addr,
833                          &c6->sin6_addr,
834                          sizeof (struct in6_addr))) &&
835            (0 != memcmp (&c6->sin6_addr,
836                          &in6addr_any,
837                          sizeof (struct in6_addr))) &&
838            (! is_nat_v6 (&c6->sin6_addr)) )
839         continue; /* this IP is not from private address range,
840                      and IP does not match. */
841       if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
842            (0 != memcmp (&c6->sin6_addr,
843                          &in6addr_any,
844                          sizeof (struct in6_addr))) &&
845            (0 != memcmp (&v6.sin6_addr,
846                          &c6->sin6_addr,
847                          sizeof (struct in6_addr))) &&
848            (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
849         continue; /* client bound to link-local, and the other address
850                      does not match and is not an external IP */
851
852       /* OK, IP seems relevant, notify client */
853       v6.sin6_port = c6->sin6_port;
854       notify_client (delta->ac,
855                      ch,
856                      add,
857                      &v6,
858                      alen);
859     }
860     break;
861   default:
862     GNUNET_break (0);
863     return;
864   }
865 }
866
867
868 /**
869  * Notify all clients about a change in the list
870  * of addresses this peer has.
871  *
872  * @param delta the entry in the list that changed
873  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
874  */
875 static void
876 notify_clients (struct LocalAddressList *delta,
877                 int add)
878 {
879   for (struct ClientHandle *ch = ch_head;
880        NULL != ch;
881        ch = ch->next)
882     check_notify_client (delta,
883                          ch,
884                          add);
885 }
886
887
888 /**
889  * Tell relevant client about a change in our external
890  * IPv4 address.
891  * 
892  * @param v4 the external address that changed
893  * @param ch client to check if it cares and possibly notify
894  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
895  */
896 static void
897 check_notify_client_external_ipv4_change (const struct in_addr *v4,
898                                           struct ClientHandle *ch,
899                                           int add)
900 {
901   struct sockaddr_in sa;
902   int have_v4;
903
904   /* (1) check if client cares. */
905   if (! ch->natted_address)
906     return;
907   if (0 == (GNUNET_NAT_RF_ADDRESSES & ch->flags))
908     return;
909   have_v4 = GNUNET_NO;
910   for (unsigned int i=0;i<ch->num_caddrs;i++)
911   {
912     const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
913
914     if (AF_INET != ss->ss_family)
915       continue;
916     have_v4 = GNUNET_YES;
917     break;
918   }
919   if (GNUNET_NO == have_v4)
920     return; /* IPv6-only */
921
922   /* build address info */
923   memset (&sa,
924           0,
925           sizeof (sa));
926   sa.sin_family = AF_INET;
927   sa.sin_addr = *v4;
928   sa.sin_port = htons (0);
929   
930   /* (3) notify client of change */
931   notify_client (is_nat_v4 (v4)
932                  ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN 
933                  : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
934                  ch,
935                  add,
936                  &sa,
937                  sizeof (sa));
938 }
939
940
941 /**
942  * Tell relevant clients about a change in our external
943  * IPv4 address.
944  * 
945  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
946  * @param v4 the external address that changed
947  */
948 static void
949 notify_clients_external_ipv4_change (int add,
950                                      const struct in_addr *v4)
951 {
952   for (struct ClientHandle *ch = ch_head;
953        NULL != ch;
954        ch = ch->next)
955     check_notify_client_external_ipv4_change (v4,
956                                               ch,
957                                               add);
958 }
959
960
961 /**
962  * Task used to run `external-ip` to get our external IPv4
963  * address and pass it to NATed clients if possible.
964  *
965  * @param cls NULL
966  */
967 static void
968 run_external_ip (void *cls);
969
970
971 /**
972  * We learn our current external IP address.  If it changed,
973  * notify all of our applicable clients. Also re-schedule
974  * #run_external_ip with an appropriate timeout.
975  * 
976  * @param cls NULL
977  * @param addr the address, NULL on errors
978  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
979  */
980 static void
981 handle_external_ip (void *cls,
982                     const struct in_addr *addr,
983                     enum GNUNET_NAT_StatusCode result)
984 {
985   char buf[INET_ADDRSTRLEN];
986   
987   probe_external_ip_op = NULL;
988   GNUNET_SCHEDULER_cancel (probe_external_ip_task);
989   probe_external_ip_task
990     = GNUNET_SCHEDULER_add_delayed ((NULL == addr)
991                                     ? EXTERN_IP_RETRY_FAILURE
992                                     : EXTERN_IP_RETRY_SUCCESS,
993                                     &run_external_ip,
994                                     NULL);
995   switch (result)
996   {
997   case GNUNET_NAT_ERROR_SUCCESS:
998     if (addr->s_addr == mini_external_ipv4.s_addr)
999       return; /* not change */
1000     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001                 "Our external IP is now %s\n",
1002                 inet_ntop (AF_INET,
1003                            addr,
1004                            buf,
1005                            sizeof (buf)));
1006     if (0 != mini_external_ipv4.s_addr)
1007       notify_clients_external_ipv4_change (GNUNET_NO,
1008                                            &mini_external_ipv4);
1009     mini_external_ipv4 = *addr;
1010     notify_clients_external_ipv4_change (GNUNET_YES,
1011                                          &mini_external_ipv4);
1012     break;
1013   default:
1014     if (0 != mini_external_ipv4.s_addr)
1015       notify_clients_external_ipv4_change (GNUNET_NO,
1016                                            &mini_external_ipv4);
1017     mini_external_ipv4.s_addr = 0; 
1018     break;
1019   }
1020 }
1021
1022
1023 /**
1024  * Task used to run `external-ip` to get our external IPv4
1025  * address and pass it to NATed clients if possible.
1026  *
1027  * @param cls NULL
1028  */
1029 static void
1030 run_external_ip (void *cls)
1031 {
1032   probe_external_ip_task
1033     = GNUNET_SCHEDULER_add_delayed (EXTERN_IP_RETRY_TIMEOUT,
1034                                     &run_external_ip,
1035                                     NULL);
1036   if (NULL != probe_external_ip_op)
1037   {
1038     GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1039     probe_external_ip_op = NULL;
1040   }
1041   probe_external_ip_op
1042     = GNUNET_NAT_mini_get_external_ipv4_ (&handle_external_ip,
1043                                           NULL);
1044 }
1045
1046
1047 /**
1048  * We got a connection reversal request from another peer.
1049  * Notify applicable clients.
1050  *
1051  * @param cls closure with the `struct LocalAddressList` 
1052  * @param ra IP address of the peer who wants us to connect to it 
1053  */
1054 static void
1055 reversal_callback (void *cls,
1056                    const struct sockaddr_in *ra)
1057 {
1058   struct LocalAddressList *lal = cls;
1059   const struct sockaddr_in *l4;
1060
1061   GNUNET_assert (AF_INET == lal->af);
1062   l4 = (const struct sockaddr_in *) &lal->addr;
1063   for (struct ClientHandle *ch = ch_head;
1064        NULL != ch;
1065        ch = ch->next)
1066   {    
1067     struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
1068     struct GNUNET_MQ_Envelope *env;
1069     int match;
1070
1071     /* Check if client is in applicable range for ICMP NAT traversal
1072        for this local address */
1073     if (! ch->natted_address)
1074       continue;
1075     match = GNUNET_NO;
1076     for (unsigned int i=0;i<ch->num_caddrs;i++)
1077     {
1078       struct ClientAddress *ca = &ch->caddrs[i];
1079       const struct sockaddr_in *c4;
1080       
1081       if (AF_INET != ca->ss.ss_family)
1082         continue;
1083       c4 = (const struct sockaddr_in *) &ca->ss;
1084       if ( (0 != c4->sin_addr.s_addr) &&
1085            (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
1086         continue;
1087       match = GNUNET_YES;
1088       break;
1089     }
1090     if (! match)
1091       continue;
1092
1093     /* Notify applicable client about connection reversal request */
1094     env = GNUNET_MQ_msg_extra (crrm,
1095                                sizeof (struct sockaddr_in),
1096                                GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
1097     GNUNET_memcpy (&crrm[1],
1098                    ra,
1099                    sizeof (struct sockaddr_in));
1100     GNUNET_MQ_send (ch->mq,
1101                     env);
1102   }
1103 }
1104
1105
1106 /**
1107  * Task we run periodically to scan for network interfaces.
1108  *
1109  * @param cls NULL
1110  */ 
1111 static void
1112 run_scan (void *cls)
1113 {
1114   struct IfcProcContext ifc_ctx;
1115   int found;
1116   int have_nat;
1117   struct LocalAddressList *lnext;
1118   
1119   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1120                                             &run_scan,
1121                                             NULL);
1122   memset (&ifc_ctx,
1123           0,
1124           sizeof (ifc_ctx));
1125   GNUNET_OS_network_interfaces_list (&ifc_proc,
1126                                      &ifc_ctx);
1127   /* remove addresses that disappeared */
1128   for (struct LocalAddressList *lal = lal_head;
1129        NULL != lal;
1130        lal = lnext)
1131   {
1132     lnext = lal->next;
1133     found = GNUNET_NO;
1134     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1135          NULL != pos;
1136          pos = pos->next)
1137     {
1138       if ( (pos->af == lal->af) &&
1139            (0 == memcmp (&lal->addr,
1140                          &pos->addr,
1141                          (AF_INET == lal->af)
1142                          ? sizeof (struct sockaddr_in)
1143                          : sizeof (struct sockaddr_in6))) )
1144       {
1145         found = GNUNET_YES;
1146       }
1147     }
1148     if (GNUNET_NO == found)
1149     {
1150       notify_clients (lal,
1151                       GNUNET_NO);
1152       free_lal (lal);
1153     }
1154   }
1155
1156   /* add addresses that appeared */
1157   have_nat = GNUNET_NO;
1158   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1159        NULL != pos;
1160        pos = ifc_ctx.lal_head)
1161   {
1162     found = GNUNET_NO;
1163     if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1164       have_nat = GNUNET_YES;
1165     for (struct LocalAddressList *lal = lal_head;
1166          NULL != lal;
1167          lal = lal->next)
1168     {
1169       if ( (pos->af == lal->af) &&
1170            (0 == memcmp (&lal->addr,
1171                          &pos->addr,
1172                          (AF_INET == lal->af)
1173                          ? sizeof (struct sockaddr_in)
1174                          : sizeof (struct sockaddr_in6))) )
1175         found = GNUNET_YES;
1176     }
1177     GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1178                                  ifc_ctx.lal_tail,
1179                                  pos);
1180     if (GNUNET_YES == found)
1181     {
1182       GNUNET_free (pos);
1183     }
1184     else
1185     {
1186       notify_clients (pos,
1187                       GNUNET_YES);
1188       GNUNET_CONTAINER_DLL_insert (lal_head,
1189                                    lal_tail,
1190                                    pos);
1191       if ( (AF_INET == pos->af) &&
1192            (NULL == pos->hc) &&
1193            (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1194       {
1195         const struct sockaddr_in *s4
1196           = (const struct sockaddr_in *) &pos->addr;
1197         
1198         GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1199                     "Found NATed local address %s, starting NAT server\n",
1200                     GNUNET_a2s ((void *) &pos->addr, sizeof (*s4)));
1201         pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1202                                                &reversal_callback,
1203                                                pos);
1204       }
1205     }
1206   }
1207   if ( (GNUNET_YES == have_nat) &&
1208        (GNUNET_YES == enable_upnp) &&
1209        (NULL == probe_external_ip_task) &&
1210        (NULL == probe_external_ip_op) )
1211   {
1212     probe_external_ip_task
1213       = GNUNET_SCHEDULER_add_now (&run_external_ip,
1214                                   NULL);
1215   }
1216   if ( (GNUNET_NO == have_nat) &&
1217        (GNUNET_YES == enable_upnp) )
1218   {
1219     if (NULL != probe_external_ip_task)
1220     {
1221       GNUNET_SCHEDULER_cancel (probe_external_ip_task);
1222       probe_external_ip_task = NULL;
1223     }
1224     if (NULL != probe_external_ip_op)
1225     {
1226       GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
1227       probe_external_ip_op = NULL;
1228     }
1229   }
1230 }
1231
1232
1233 /**
1234  * Function called whenever our set of external addresses
1235  * as created by `upnpc` changes.
1236  *
1237  * @param cls closure with our `struct ClientHandle *`
1238  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1239  *     the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1240  * @param addr either the previous or the new public IP address
1241  * @param addrlen actual length of the @a addr
1242  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1243  */
1244 static void
1245 upnp_addr_change_cb (void *cls,
1246                      int add_remove,
1247                      const struct sockaddr *addr,
1248                      socklen_t addrlen,
1249                      enum GNUNET_NAT_StatusCode result)
1250 {
1251   struct ClientHandle *ch = cls;
1252   enum GNUNET_NAT_AddressClass ac;
1253
1254   switch (result)
1255   {
1256   case GNUNET_NAT_ERROR_SUCCESS:
1257     GNUNET_assert (NULL != addr);
1258     break;
1259   case GNUNET_NAT_ERROR_UPNPC_FAILED:
1260   case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1261   case GNUNET_NAT_ERROR_IPC_FAILURE:
1262     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1263                 "Running upnpc failed: %d\n",
1264                 result);
1265     return;
1266   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1267     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1268                 "external-ip binary not found\n");
1269     return;
1270   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1271     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1272                 "external-ip binary could not be run\n");
1273     return;
1274   case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1275     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1276                 "upnpc failed to create port mapping\n");
1277     return;
1278   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1279     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1280                 "Invalid output from upnpc\n");
1281     return;
1282   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1283     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1284                 "Invalid address returned by upnpc\n");
1285     return;
1286   default:
1287     GNUNET_break (0); /* should not be possible */
1288     return;
1289   }
1290   switch (addr->sa_family)
1291   {
1292   case AF_INET:
1293     ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1294       ? GNUNET_NAT_AC_LAN
1295       : GNUNET_NAT_AC_EXTERN;
1296     break;
1297   case AF_INET6:
1298     ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1299       ? GNUNET_NAT_AC_LAN
1300       : GNUNET_NAT_AC_EXTERN;
1301     break;
1302   default:
1303     GNUNET_break (0);
1304     return;
1305   }
1306   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1307               "upnp external address %s: %s\n",
1308               add_remove ? "added" : "removed",
1309               GNUNET_a2s (addr,
1310                           addrlen));
1311   notify_client (ac,
1312                  ch,
1313                  add_remove,
1314                  addr,
1315                  addrlen);
1316 }
1317
1318
1319 /**
1320  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1321  * We remember the client for updates upon future NAT events.
1322  *
1323  * @param cls client who sent the message
1324  * @param message the message received
1325  */
1326 static void
1327 handle_register (void *cls,
1328                  const struct GNUNET_NAT_RegisterMessage *message)
1329 {
1330   struct ClientHandle *ch = cls;
1331   const char *off;
1332   size_t left;
1333
1334   if ( (0 != ch->proto) ||
1335        (NULL != ch->caddrs) )
1336   {
1337     /* double registration not allowed */
1338     GNUNET_break (0);
1339     GNUNET_SERVICE_client_drop (ch->client);
1340     return;
1341   }
1342   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1343               "Received REGISTER message from client\n");
1344   ch->flags = message->flags;
1345   ch->proto = message->proto;
1346   ch->num_caddrs = ntohs (message->num_addrs);
1347   ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1348                                  struct ClientAddress);
1349   left = ntohs (message->header.size) - sizeof (*message);
1350   off = (const char *) &message[1];
1351   for (unsigned int i=0;i<ch->num_caddrs;i++)
1352   {
1353     size_t alen;
1354     const struct sockaddr *sa = (const struct sockaddr *) off;
1355     uint16_t port;
1356     int is_nat;
1357
1358     if (sizeof (sa_family_t) > left)
1359     {
1360       GNUNET_break (0);
1361       GNUNET_SERVICE_client_drop (ch->client);
1362       return;
1363     }
1364     is_nat = GNUNET_NO;
1365     switch (sa->sa_family)
1366     {
1367     case AF_INET:
1368       {
1369         const struct sockaddr_in *s4 = (const struct sockaddr_in *) sa;
1370         
1371         alen = sizeof (struct sockaddr_in);
1372         if (is_nat_v4 (&s4->sin_addr))
1373           is_nat = GNUNET_YES;
1374         port = ntohs (s4->sin_port);
1375       }
1376       break;
1377     case AF_INET6:
1378       {
1379         const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) sa;
1380         
1381         alen = sizeof (struct sockaddr_in6);
1382         if (is_nat_v6 (&s6->sin6_addr))
1383           is_nat = GNUNET_YES;
1384         port = ntohs (s6->sin6_port);
1385       }
1386       break;
1387 #if AF_UNIX
1388     case AF_UNIX:
1389       alen = sizeof (struct sockaddr_un);
1390       port = 0;
1391       break;
1392 #endif
1393     default:
1394       GNUNET_break (0);
1395       GNUNET_SERVICE_client_drop (ch->client);
1396       return;      
1397     }
1398     /* store address */
1399     GNUNET_assert (alen <= left);
1400     GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1401     GNUNET_memcpy (&ch->caddrs[i].ss,
1402                    sa,
1403                    alen);    
1404
1405     /* If applicable, try UPNPC NAT punching */
1406     if ( (is_nat) &&
1407          (enable_upnp) &&
1408          ( (IPPROTO_TCP == ch->proto) ||
1409            (IPPROTO_UDP == ch->proto) ) )
1410     {
1411       ch->natted_address = GNUNET_YES;
1412       ch->caddrs[i].mh
1413         = GNUNET_NAT_mini_map_start (port,
1414                                      IPPROTO_TCP == ch->proto,
1415                                      &upnp_addr_change_cb,
1416                                      ch);
1417     }
1418
1419     off += alen;
1420   }
1421
1422   ch->hole_external
1423     = GNUNET_strndup (off,
1424                       ntohs (message->hole_external_len));
1425     
1426   /* Actually send IP address list to client */
1427   for (struct LocalAddressList *lal = lal_head;
1428        NULL != lal;
1429        lal = lal->next)
1430   {
1431     check_notify_client (lal,
1432                          ch,
1433                          GNUNET_YES);
1434   }
1435   /* Also consider IPv4 determined by `external-ip` */
1436   if (0 != mini_external_ipv4.s_addr)
1437   {
1438     check_notify_client_external_ipv4_change (&mini_external_ipv4,
1439                                               ch,
1440                                               GNUNET_YES);
1441   }
1442   GNUNET_SERVICE_client_continue (ch->client);
1443 }
1444
1445
1446 /**
1447  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1448  * client.
1449  *
1450  * @param cls client who sent the message
1451  * @param message the message received
1452  * @return #GNUNET_OK if message is well-formed
1453  */
1454 static int
1455 check_stun (void *cls,
1456             const struct GNUNET_NAT_HandleStunMessage *message)
1457 {
1458   size_t sa_len = ntohs (message->sender_addr_size);
1459   size_t expect = sa_len + ntohs (message->payload_size);
1460   
1461   if (ntohs (message->header.size) - sizeof (*message) != expect)
1462   {
1463     GNUNET_break (0);
1464     return GNUNET_SYSERR;
1465   }
1466   if (sa_len < sizeof (sa_family_t))
1467   {
1468     GNUNET_break (0);
1469     return GNUNET_SYSERR;
1470   }
1471   return GNUNET_OK;
1472 }
1473
1474
1475 /**
1476  * Notify all clients about our external IP address
1477  * as reported by the STUN server.
1478  *
1479  * @param ip the external IP
1480  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1481  */
1482 static void
1483 notify_clients_stun_change (const struct sockaddr_in *ip,
1484                             int add)
1485 {
1486   for (struct ClientHandle *ch = ch_head;
1487        NULL != ch;
1488        ch = ch->next)
1489   {
1490     struct sockaddr_in v4;
1491     struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1492     struct GNUNET_MQ_Envelope *env;
1493     
1494     if (! ch->natted_address)
1495       continue;
1496     v4 = *ip;
1497     v4.sin_port = htons (0);
1498     env = GNUNET_MQ_msg_extra (msg,
1499                                sizeof (v4),
1500                                GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1501     msg->add_remove = htonl ((int32_t) add);
1502     msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1503                              GNUNET_NAT_AC_GLOBAL);
1504     GNUNET_memcpy (&msg[1],
1505                    &v4,
1506                    sizeof (v4));
1507     GNUNET_MQ_send (ch->mq,
1508                     env);
1509   }
1510 }
1511
1512
1513 /**
1514  * Function to be called when we decide that an
1515  * external IP address as told to us by a STUN
1516  * server has gone stale.
1517  *
1518  * @param cls the `struct StunExternalIP` to drop
1519  */
1520 static void
1521 stun_ip_timeout (void *cls)
1522 {
1523   struct StunExternalIP *se = cls;
1524
1525   se->timeout_task = NULL;
1526   notify_clients_stun_change (&se->external_addr,
1527                               GNUNET_NO);
1528   GNUNET_CONTAINER_DLL_remove (se_head,
1529                                se_tail,
1530                                se);
1531   GNUNET_free (se);
1532 }
1533
1534
1535 /**
1536  * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1537  * client.
1538  *
1539  * @param cls client who sent the message
1540  * @param message the message received
1541  */
1542 static void
1543 handle_stun (void *cls,
1544              const struct GNUNET_NAT_HandleStunMessage *message)
1545 {
1546   struct ClientHandle *ch = cls;
1547   const char *buf = (const char *) &message[1];
1548   const struct sockaddr *sa;
1549   const void *payload;
1550   size_t sa_len;
1551   size_t payload_size;
1552   struct sockaddr_in external_addr;
1553
1554   sa_len = ntohs (message->sender_addr_size);
1555   payload_size = ntohs (message->payload_size);
1556   sa = (const struct sockaddr *) &buf[0];
1557   payload = (const struct sockaddr *) &buf[sa_len];
1558   switch (sa->sa_family)
1559   {
1560   case AF_INET:
1561     if (sa_len != sizeof (struct sockaddr_in))
1562     {
1563       GNUNET_break (0);
1564       GNUNET_SERVICE_client_drop (ch->client);
1565       return;
1566     }
1567     break;
1568   case AF_INET6:
1569     if (sa_len != sizeof (struct sockaddr_in6))
1570     {
1571       GNUNET_break (0);
1572       GNUNET_SERVICE_client_drop (ch->client);
1573       return;
1574     }
1575     break;
1576   }
1577   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1578               "Received HANDLE_STUN message from client\n");
1579   if (GNUNET_OK ==
1580       GNUNET_NAT_stun_handle_packet_ (payload,
1581                                       payload_size,
1582                                       &external_addr))
1583   {     
1584     /* We now know that a server at "sa" claims that
1585        we are visible at IP "external_addr". 
1586
1587        We should (for some fixed period of time) tell
1588        all of our clients that listen to a NAT'ed address
1589        that they might want to consider the given 'external_ip'
1590        as their public IP address (this includes TCP and UDP
1591        clients, even if only UDP sends STUN requests).
1592
1593        If we do not get a renewal, the "external_addr" should be
1594        removed again.  The timeout frequency should be configurable
1595        (with a sane default), so that the UDP plugin can tell how
1596        often to re-request STUN.
1597     */
1598     struct StunExternalIP *se;
1599
1600     /* Check if we had a prior response from this STUN server */
1601     for (se = se_head; NULL != se; se = se->next)
1602     {
1603       if ( (se->stun_server_addr_len != sa_len) ||
1604            (0 != memcmp (sa,
1605                          &se->stun_server_addr,
1606                          sa_len)) )
1607         continue; /* different STUN server */
1608       if (0 != memcmp (&external_addr,
1609                        &se->external_addr,
1610                        sizeof (struct sockaddr_in)))
1611       {
1612         /* external IP changed, update! */
1613         notify_clients_stun_change (&se->external_addr,
1614                                     GNUNET_NO);
1615         se->external_addr = external_addr;
1616         notify_clients_stun_change (&se->external_addr,
1617                                     GNUNET_YES);
1618       }
1619       /* update timeout */
1620       GNUNET_SCHEDULER_cancel (se->timeout_task);
1621       se->timeout_task
1622         = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1623                                         &stun_ip_timeout,
1624                                         se);
1625       return;
1626     }
1627     /* STUN server is completely new, create fresh entry */
1628     se = GNUNET_new (struct StunExternalIP);
1629     se->external_addr = external_addr;
1630     GNUNET_memcpy (&se->stun_server_addr,
1631                    sa,
1632                    sa_len);
1633     se->stun_server_addr_len = sa_len;
1634     se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1635                                                      &stun_ip_timeout,
1636                                                      se);
1637     GNUNET_CONTAINER_DLL_insert (se_head,
1638                                  se_tail,
1639                                  se);
1640     notify_clients_stun_change (&se->external_addr,
1641                                 GNUNET_NO);
1642   }
1643   GNUNET_SERVICE_client_continue (ch->client);
1644 }
1645
1646
1647 /**
1648  * Check validity of
1649  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1650  * client.
1651  *
1652  * @param cls client who sent the message
1653  * @param message the message received
1654  * @return #GNUNET_OK if message is well-formed
1655  */
1656 static int
1657 check_request_connection_reversal (void *cls,
1658                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1659 {
1660   size_t expect;
1661
1662   expect = ntohs (message->local_addr_size)
1663     + ntohs (message->remote_addr_size);
1664   if (ntohs (message->header.size) - sizeof (*message) != expect)
1665   {
1666     GNUNET_break (0);
1667     return GNUNET_SYSERR;
1668   }
1669   return GNUNET_OK;
1670 }
1671
1672
1673 /**
1674  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1675  * message from client.
1676  *
1677  * @param cls client who sent the message
1678  * @param message the message received
1679  */
1680 static void
1681 handle_request_connection_reversal (void *cls,
1682                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1683 {
1684   struct ClientHandle *ch = cls;
1685   const char *buf = (const char *) &message[1];
1686   size_t local_sa_len = ntohs (message->local_addr_size);
1687   size_t remote_sa_len = ntohs (message->remote_addr_size);
1688   const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
1689   const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
1690   const struct sockaddr_in *l4 = NULL;
1691   const struct sockaddr_in *r4;
1692   int ret;
1693   
1694   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695               "Received REQUEST CONNECTION REVERSAL message from client\n");
1696   switch (local_sa->sa_family)
1697   {
1698   case AF_INET:
1699     if (local_sa_len != sizeof (struct sockaddr_in))
1700     {
1701       GNUNET_break (0);
1702       GNUNET_SERVICE_client_drop (ch->client);
1703       return;
1704     }
1705     l4 = (const struct sockaddr_in *) local_sa;    
1706     break;
1707   case AF_INET6:
1708     if (local_sa_len != sizeof (struct sockaddr_in6))
1709     {
1710       GNUNET_break (0);
1711       GNUNET_SERVICE_client_drop (ch->client);
1712       return;
1713     }
1714     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1715                 _("Connection reversal for IPv6 not supported yet\n"));
1716     ret = GNUNET_SYSERR;
1717     break;
1718   default:
1719     GNUNET_break (0);
1720     GNUNET_SERVICE_client_drop (ch->client);
1721     return;
1722   }
1723   switch (remote_sa->sa_family)
1724   {
1725   case AF_INET:
1726     if (remote_sa_len != sizeof (struct sockaddr_in))
1727     {
1728       GNUNET_break (0);
1729       GNUNET_SERVICE_client_drop (ch->client);
1730       return;
1731     }
1732     r4 = (const struct sockaddr_in *) remote_sa;
1733     ret = GN_request_connection_reversal (&l4->sin_addr,
1734                                           ntohs (l4->sin_port),
1735                                           &r4->sin_addr);
1736     break;
1737   case AF_INET6:
1738     if (remote_sa_len != sizeof (struct sockaddr_in6))
1739     {
1740       GNUNET_break (0);
1741       GNUNET_SERVICE_client_drop (ch->client);
1742       return;
1743     }
1744     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1745                 _("Connection reversal for IPv6 not supported yet\n"));
1746     ret = GNUNET_SYSERR;
1747     break;
1748   default:
1749     GNUNET_break (0);
1750     GNUNET_SERVICE_client_drop (ch->client);
1751     return;
1752   }
1753   if (GNUNET_OK != ret)
1754     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1755                 _("Connection reversal request failed\n"));  
1756   GNUNET_SERVICE_client_continue (ch->client);
1757 }
1758
1759
1760 /**
1761  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
1762  * from client.
1763  *
1764  * @param cls client who sent the message
1765  * @param message the message received
1766  * @return #GNUNET_OK if message is well-formed
1767  */
1768 static int
1769 check_autoconfig_request (void *cls,
1770                           const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1771 {
1772   return GNUNET_OK;  /* checked later */
1773 }
1774
1775
1776 /**
1777  * Stop all pending activities with respect to the @a ac
1778  *
1779  * @param ac autoconfiguration to terminate activities for
1780  */
1781 static void
1782 terminate_ac_activities (struct AutoconfigContext *ac)
1783 {
1784   if (NULL != ac->probe_external)
1785   {
1786     GNUNET_NAT_mini_get_external_ipv4_cancel_ (ac->probe_external);
1787     ac->probe_external = NULL;
1788   }
1789   if (NULL != ac->timeout_task)
1790   {
1791     GNUNET_SCHEDULER_cancel (ac->timeout_task);
1792     ac->timeout_task = NULL;
1793   }
1794 }
1795
1796
1797 /**
1798  * Finish handling the autoconfiguration request and send
1799  * the response to the client.
1800  *
1801  * @param cls the `struct AutoconfigContext` to conclude
1802  */
1803 static void
1804 conclude_autoconfig_request (void *cls)
1805 {
1806   struct AutoconfigContext *ac = cls;
1807   struct ClientHandle *ch = ac->ch;
1808   struct GNUNET_NAT_AutoconfigResultMessage *arm;
1809   struct GNUNET_MQ_Envelope *env;
1810   size_t c_size;
1811   char *buf;
1812   struct GNUNET_CONFIGURATION_Handle *diff;
1813   
1814   ac->timeout_task = NULL;
1815   terminate_ac_activities (ac);
1816
1817   /* Send back response */
1818   diff = GNUNET_CONFIGURATION_get_diff (ac->orig,
1819                                         ac->c);
1820   buf = GNUNET_CONFIGURATION_serialize (diff,
1821                                         &c_size);
1822   GNUNET_CONFIGURATION_destroy (diff);
1823   env = GNUNET_MQ_msg_extra (arm,
1824                              c_size,
1825                              GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT);
1826   arm->status_code = htonl ((uint32_t) ac->status_code);
1827   arm->type = htonl ((uint32_t) ac->type);
1828   GNUNET_memcpy (&arm[1],
1829                  buf,
1830                  c_size);
1831   GNUNET_free (buf);
1832   GNUNET_MQ_send (ch->mq,
1833                   env);
1834
1835   /* clean up */
1836   GNUNET_free (ac->system_type);
1837   GNUNET_CONFIGURATION_destroy (ac->orig);
1838   GNUNET_CONFIGURATION_destroy (ac->c);
1839   GNUNET_CONTAINER_DLL_remove (ac_head,
1840                                ac_tail,
1841                                ac);
1842   GNUNET_free (ac);
1843   GNUNET_SERVICE_client_continue (ch->client);
1844 }
1845
1846
1847 /**
1848  * Check if all autoconfiguration operations have concluded,
1849  * and if they have, send the result back to the client.
1850  *
1851  * @param ac autoconfiguation context to check
1852  */
1853 static void
1854 check_autoconfig_finished (struct AutoconfigContext *ac)
1855 {
1856   if (NULL != ac->probe_external)
1857     return;
1858   GNUNET_SCHEDULER_cancel (ac->timeout_task);
1859   ac->timeout_task
1860     = GNUNET_SCHEDULER_add_now (&conclude_autoconfig_request,
1861                                 ac);
1862 }
1863
1864
1865 /**
1866  * Update ENABLE_UPNPC configuration option.
1867  *
1868  * @param ac autoconfiguration to update
1869  */
1870 static void
1871 update_enable_upnpc_option (struct AutoconfigContext *ac)
1872 {
1873   switch (ac->enable_upnpc)
1874   {
1875   case GNUNET_YES:
1876     GNUNET_CONFIGURATION_set_value_string (ac->c,
1877                                            "NAT",
1878                                            "ENABLE_UPNP",
1879                                            "YES");
1880     break;
1881   case GNUNET_NO:
1882     GNUNET_CONFIGURATION_set_value_string (ac->c,
1883                                            "NAT",
1884                                            "ENABLE_UPNP",
1885                                            "NO");
1886     break;
1887   case GNUNET_SYSERR:
1888     /* We are unsure, do not change option */
1889     break;
1890   }
1891 }
1892
1893
1894 /**
1895  * Handle result from external IP address probe during
1896  * autoconfiguration.
1897  *
1898  * @param cls our `struct AutoconfigContext`
1899  * @param addr the address, NULL on errors
1900  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1901  */
1902 static void
1903 auto_external_result_cb (void *cls,
1904                          const struct in_addr *addr,
1905                          enum GNUNET_NAT_StatusCode result)
1906 {
1907   struct AutoconfigContext *ac = cls;
1908
1909   ac->probe_external = NULL;
1910   switch (result)
1911   {
1912   case GNUNET_NAT_ERROR_SUCCESS:
1913     ac->enable_upnpc = GNUNET_YES;
1914     break;
1915   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1916   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1917   case GNUNET_NAT_ERROR_IPC_FAILURE:
1918     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1919                 "Disabling UPNPC: %d\n",
1920                 (int) result);
1921     ac->enable_upnpc = GNUNET_NO; /* did not work */
1922     break;
1923   default:
1924     GNUNET_break (0); /* unexpected */
1925     ac->enable_upnpc = GNUNET_SYSERR;
1926     break;    
1927   }
1928   update_enable_upnpc_option (ac);
1929   check_autoconfig_finished (ac);
1930 }
1931
1932
1933 /**
1934  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
1935  * client.
1936  *
1937  * @param cls client who sent the message
1938  * @param message the message received
1939  */
1940 static void
1941 handle_autoconfig_request (void *cls,
1942                            const struct GNUNET_NAT_AutoconfigRequestMessage *message)
1943 {
1944   struct ClientHandle *ch = cls;
1945   size_t left = ntohs (message->header.size) - sizeof (*message);
1946   struct LocalAddressList *lal;
1947   struct AutoconfigContext *ac;
1948
1949   ac = GNUNET_new (struct AutoconfigContext);
1950   ac->status_code = GNUNET_NAT_ERROR_SUCCESS;
1951   ac->ch = ch;
1952   ac->c = GNUNET_CONFIGURATION_create ();
1953   if (GNUNET_OK !=
1954       GNUNET_CONFIGURATION_deserialize (ac->c,
1955                                         (const char *) &message[1],
1956                                         left,
1957                                         GNUNET_NO))
1958   {
1959     GNUNET_break (0);
1960     GNUNET_SERVICE_client_drop (ch->client);
1961     GNUNET_CONFIGURATION_destroy (ac->c);
1962     GNUNET_free (ac);
1963     return;
1964   }
1965   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966               "Received REQUEST_AUTO_CONFIG message from client\n");
1967
1968   if (GNUNET_OK !=
1969       GNUNET_CONFIGURATION_get_value_string (ac->c,
1970                                              "PEER",
1971                                              "SYSTEM_TYPE",
1972                                              &ac->system_type))
1973     ac->system_type = GNUNET_strdup ("UNKNOWN");
1974
1975   GNUNET_CONTAINER_DLL_insert (ac_head,
1976                                ac_tail,
1977                                ac);
1978   ac->orig
1979     = GNUNET_CONFIGURATION_dup (ac->c);
1980   ac->timeout_task
1981     = GNUNET_SCHEDULER_add_delayed (AUTOCONFIG_TIMEOUT,
1982                                     &conclude_autoconfig_request,
1983                                     ac);
1984   ac->enable_upnpc = GNUNET_SYSERR; /* undecided */
1985   
1986   /* Probe for upnpc */
1987   if (GNUNET_SYSERR ==
1988       GNUNET_OS_check_helper_binary ("upnpc",
1989                                      GNUNET_NO,
1990                                      NULL))
1991   {
1992     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1993                 _("UPnP client `upnpc` command not found, disabling UPnP\n"));
1994     ac->enable_upnpc = GNUNET_NO;
1995   }
1996   else
1997   {
1998     for (lal = lal_head; NULL != lal; lal = lal->next)
1999       if (GNUNET_NAT_AC_LAN == (lal->ac & GNUNET_NAT_AC_LAN))
2000         /* we are behind NAT, useful to try upnpc */
2001         ac->enable_upnpc = GNUNET_YES;
2002   }
2003   if (GNUNET_YES == ac->enable_upnpc)
2004   {
2005     /* If we are a mobile device, always leave it on as the network
2006        may change to one that supports UPnP anytime.  If we are
2007        stationary, check if our network actually supports UPnP, and if
2008        not, disable it. */
2009     if ( (0 == strcasecmp (ac->system_type,
2010                            "INFRASTRUCTURE")) ||
2011          (0 == strcasecmp (ac->system_type,
2012                            "DESKTOP")) )
2013     {
2014       /* Check if upnpc gives us an external IP */
2015       ac->probe_external
2016         = GNUNET_NAT_mini_get_external_ipv4_ (&auto_external_result_cb,
2017                                               ac);
2018     }
2019   }
2020   if (NULL == ac->probe_external)
2021     update_enable_upnpc_option (ac);
2022
2023   /* Finally, check if we are already done */  
2024   check_autoconfig_finished (ac);
2025 }
2026
2027
2028 /**
2029  * Task run during shutdown.
2030  *
2031  * @param cls unused
2032  */
2033 static void
2034 shutdown_task (void *cls)
2035 {
2036   struct StunExternalIP *se;
2037   struct AutoconfigContext *ac;
2038
2039   while (NULL != (ac = ac_head))
2040   {
2041     GNUNET_CONTAINER_DLL_remove (ac_head,
2042                                  ac_tail,
2043                                  ac);
2044     terminate_ac_activities (ac);
2045     GNUNET_free (ac);
2046   }
2047   while (NULL != (se = se_head))
2048   {
2049     GNUNET_CONTAINER_DLL_remove (se_head,
2050                                  se_tail,
2051                                  se);
2052     GNUNET_SCHEDULER_cancel (se->timeout_task);
2053     GNUNET_free (se);
2054   }
2055   if (NULL != probe_external_ip_task)
2056   {
2057     GNUNET_SCHEDULER_cancel (probe_external_ip_task);
2058     probe_external_ip_task = NULL;
2059   }
2060   if (NULL != probe_external_ip_op)
2061   {
2062     GNUNET_NAT_mini_get_external_ipv4_cancel_ (probe_external_ip_op);
2063     probe_external_ip_op = NULL;
2064   }
2065   if (NULL != scan_task)
2066   {
2067     GNUNET_SCHEDULER_cancel (scan_task);
2068     scan_task = NULL;
2069   }
2070   if (NULL != stats)
2071   {
2072     GNUNET_STATISTICS_destroy (stats,
2073                                GNUNET_NO);
2074     stats = NULL;
2075   }
2076   destroy_lal ();
2077 }
2078
2079
2080 /**
2081  * Setup NAT service.
2082  *
2083  * @param cls closure
2084  * @param c configuration to use
2085  * @param service the initialized service
2086  */
2087 static void
2088 run (void *cls,
2089      const struct GNUNET_CONFIGURATION_Handle *c,
2090      struct GNUNET_SERVICE_Handle *service)
2091 {
2092   cfg = c;
2093   if (GNUNET_OK !=
2094       GNUNET_CONFIGURATION_get_value_time (cfg,
2095                                            "NAT",
2096                                            "STUN_STALE",
2097                                            &stun_stale_timeout))
2098     stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
2099
2100   /* Check for UPnP */
2101   enable_upnp 
2102     = GNUNET_CONFIGURATION_get_value_yesno (cfg,
2103                                             "NAT",
2104                                             "ENABLE_UPNP");
2105   if (GNUNET_YES == enable_upnp)
2106   {
2107     /* check if it works */
2108     if (GNUNET_SYSERR ==
2109         GNUNET_OS_check_helper_binary ("upnpc",
2110                                        GNUNET_NO,
2111                                        NULL))
2112     {
2113       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2114                   _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
2115       enable_upnp = GNUNET_SYSERR;
2116     }
2117   }
2118   
2119   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
2120                                  NULL);
2121   stats = GNUNET_STATISTICS_create ("nat",
2122                                     cfg);
2123   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
2124                                         NULL);
2125 }
2126
2127
2128 /**
2129  * Callback called when a client connects to the service.
2130  *
2131  * @param cls closure for the service
2132  * @param c the new client that connected to the service
2133  * @param mq the message queue used to send messages to the client
2134  * @return a `struct ClientHandle`
2135  */
2136 static void *
2137 client_connect_cb (void *cls,
2138                    struct GNUNET_SERVICE_Client *c,
2139                    struct GNUNET_MQ_Handle *mq)
2140 {
2141   struct ClientHandle *ch;
2142
2143   ch = GNUNET_new (struct ClientHandle);
2144   ch->mq = mq;
2145   ch->client = c;
2146   GNUNET_CONTAINER_DLL_insert (ch_head,
2147                                ch_tail,
2148                                ch);
2149   return ch;
2150 }
2151
2152
2153 /**
2154  * Callback called when a client disconnected from the service
2155  *
2156  * @param cls closure for the service
2157  * @param c the client that disconnected
2158  * @param internal_cls a `struct ClientHandle *`
2159  */
2160 static void
2161 client_disconnect_cb (void *cls,
2162                       struct GNUNET_SERVICE_Client *c,
2163                       void *internal_cls)
2164 {
2165   struct ClientHandle *ch = internal_cls;
2166
2167   GNUNET_CONTAINER_DLL_remove (ch_head,
2168                                ch_tail,
2169                                ch);
2170   for (unsigned int i=0;i<ch->num_caddrs;i++)
2171   {
2172     if (NULL != ch->caddrs[i].mh)
2173     {
2174       GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
2175       ch->caddrs[i].mh = NULL;
2176     }
2177   }
2178   GNUNET_free_non_null (ch->caddrs);
2179   GNUNET_free (ch->hole_external);
2180   GNUNET_free (ch);
2181 }
2182
2183
2184 /**
2185  * Define "main" method using service macro.
2186  */
2187 GNUNET_SERVICE_MAIN
2188 ("nat",
2189  GNUNET_SERVICE_OPTION_NONE,
2190  &run,
2191  &client_connect_cb,
2192  &client_disconnect_cb,
2193  NULL,
2194  GNUNET_MQ_hd_var_size (register,
2195                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2196                         struct GNUNET_NAT_RegisterMessage,
2197                         NULL),
2198  GNUNET_MQ_hd_var_size (stun,
2199                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2200                         struct GNUNET_NAT_HandleStunMessage,
2201                         NULL),
2202  GNUNET_MQ_hd_var_size (request_connection_reversal,
2203                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2204                         struct GNUNET_NAT_RequestConnectionReversalMessage,
2205                         NULL),
2206  GNUNET_MQ_hd_var_size (autoconfig_request,
2207                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
2208                         struct GNUNET_NAT_AutoconfigRequestMessage,
2209                         NULL),
2210  GNUNET_MQ_handler_end ());
2211
2212
2213 #if defined(LINUX) && defined(__GLIBC__)
2214 #include <malloc.h>
2215
2216 /**
2217  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2218  */
2219 void __attribute__ ((constructor))
2220 GNUNET_ARM_memory_init ()
2221 {
2222   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2223   mallopt (M_TOP_PAD, 1 * 1024);
2224   malloc_trim (0);
2225 }
2226 #endif
2227
2228 /* end of gnunet-service-nat.c */