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