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