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