Merge branch 'master' of gnunet.org:gnunet
[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   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
666               "Notifying client about %s of IP %s\n",
667               add ? "addition" : "removal",
668               GNUNET_a2s (addr,
669                           addr_len));
670   env = GNUNET_MQ_msg_extra (msg,
671                              addr_len,
672                              GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
673   msg->add_remove = htonl (add);
674   msg->addr_class = htonl (ac);
675   GNUNET_memcpy (&msg[1],
676                  addr,
677                  addr_len);
678   GNUNET_MQ_send (ch->mq,
679                   env);
680 }
681
682
683 /**
684  * Check if we should bother to notify this client about this
685  * address change, and if so, do it.
686  *
687  * @param delta the entry in the list that changed
688  * @param ch client to check
689  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
690  */
691 static void
692 check_notify_client (struct LocalAddressList *delta,
693                      struct ClientHandle *ch,
694                      int add)
695 {
696   size_t alen;
697   struct sockaddr_in v4;
698   struct sockaddr_in6 v6;
699
700   if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
701   {
702     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
703                 "Not notifying client as it does not care about addresses\n");
704     return;
705   }
706   switch (delta->af)
707   {
708   case AF_INET:
709     alen = sizeof (struct sockaddr_in);
710     GNUNET_memcpy (&v4,
711                    &delta->addr,
712                    alen);
713
714     /* Check for client notifications */
715     for (unsigned int i=0;i<ch->num_caddrs;i++)
716     {
717       const struct sockaddr_in *c4;
718
719       if (AF_INET != ch->caddrs[i].ss.ss_family)
720         continue; /* IPv4 not relevant */
721       c4 = (const struct sockaddr_in *) &ch->caddrs[i].ss;
722       if ( match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) &&
723            (0 != c4->sin_addr.s_addr) &&
724            (! match_ipv4 ("127.0.0.1", &v4.sin_addr, 8)) )
725         continue; /* bound to loopback, but this is not loopback */
726       if ( (! match_ipv4 ("127.0.0.1", &c4->sin_addr, 8) ) &&
727            match_ipv4 ("127.0.0.1", &v4.sin_addr, 8) )
728         continue; /* bound to non-loopback, but this is loopback */
729       if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
730            (0 != c4->sin_addr.s_addr) &&
731            (! is_nat_v4 (&v4.sin_addr)) )
732        continue; /* based on external-IP, but this IP is not
733                     from private address range. */
734       if ( (0 != memcmp (&v4.sin_addr,
735                          &c4->sin_addr,
736                          sizeof (struct in_addr))) &&
737            (0 != c4->sin_addr.s_addr) &&
738            (! is_nat_v4 (&c4->sin_addr)) )
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       if (0 == htons (v4.sin_port))
744         v4.sin_port = c4->sin_port;
745       notify_client (delta->ac,
746                      ch,
747                      add,
748                      &v4,
749                      alen);
750     }
751     break;
752   case AF_INET6:
753     alen = sizeof (struct sockaddr_in6);
754     GNUNET_memcpy (&v6,
755                    &delta->addr,
756                    alen);
757     for (unsigned int i=0;i<ch->num_caddrs;i++)
758     {
759       const struct sockaddr_in6 *c6;
760
761       if (AF_INET6 != ch->caddrs[i].ss.ss_family)
762         continue; /* IPv4 not relevant */
763       c6 = (const struct sockaddr_in6 *) &ch->caddrs[i].ss;
764       if ( match_ipv6 ("::1", &c6->sin6_addr, 128) &&
765            (0 != memcmp (&c6->sin6_addr,
766                          &in6addr_any,
767                          sizeof (struct in6_addr))) &&
768            (! match_ipv6 ("::1", &v6.sin6_addr, 128)) )
769         continue; /* bound to loopback, but this is not loopback */
770       if ( (! match_ipv6 ("::1", &c6->sin6_addr, 128) ) &&
771            match_ipv6 ("::1", &v6.sin6_addr, 128) )
772         continue; /* bound to non-loopback, but this is loopback */
773       if ( (0 != (delta->ac & GNUNET_NAT_AC_EXTERN)) &&
774            (0 != memcmp (&c6->sin6_addr,
775                          &in6addr_any,
776                          sizeof (struct in6_addr))) &&
777            (! is_nat_v6 (&v6.sin6_addr)) )
778         continue; /* based on external-IP, but this IP is not
779                      from private address range. */
780       if ( (0 != memcmp (&v6.sin6_addr,
781                          &c6->sin6_addr,
782                          sizeof (struct in6_addr))) &&
783            (0 != memcmp (&c6->sin6_addr,
784                          &in6addr_any,
785                          sizeof (struct in6_addr))) &&
786            (! is_nat_v6 (&c6->sin6_addr)) )
787         continue; /* this IP is not from private address range,
788                      and IP does not match. */
789       if ( (match_ipv6 ("fe80::", &c6->sin6_addr, 10)) &&
790            (0 != memcmp (&c6->sin6_addr,
791                          &in6addr_any,
792                          sizeof (struct in6_addr))) &&
793            (0 != memcmp (&v6.sin6_addr,
794                          &c6->sin6_addr,
795                          sizeof (struct in6_addr))) &&
796            (0 == (delta->ac & GNUNET_NAT_AC_EXTERN)) )
797         continue; /* client bound to link-local, and the other address
798                      does not match and is not an external IP */
799
800       /* OK, IP seems relevant, notify client */
801       if (0 == htons (v6.sin6_port))
802         v6.sin6_port = c6->sin6_port;
803       notify_client (delta->ac,
804                      ch,
805                      add,
806                      &v6,
807                      alen);
808     }
809     break;
810   default:
811     GNUNET_break (0);
812     return;
813   }
814 }
815
816
817 /**
818  * Notify all clients about a change in the list
819  * of addresses this peer has.
820  *
821  * @param delta the entry in the list that changed
822  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
823  */
824 static void
825 notify_clients (struct LocalAddressList *delta,
826                 int add)
827 {
828   for (struct ClientHandle *ch = ch_head;
829        NULL != ch;
830        ch = ch->next)
831     check_notify_client (delta,
832                          ch,
833                          add);
834 }
835
836
837 /**
838  * Tell relevant client about a change in our external
839  * IPv4 address.
840  *
841  * @param cls client to check if it cares and possibly notify
842  * @param v4 the external address that changed
843  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
844  */
845 static void
846 notify_client_external_ipv4_change (void *cls,
847                                     const struct in_addr *v4,
848                                     int add)
849 {
850   struct ClientHandle *ch = cls;
851   struct sockaddr_in sa;
852   int have_v4;
853
854   /* (0) check if this impacts 'hole_external' */
855   if ( (NULL != ch->hole_external) &&
856        (0 == strcasecmp (ch->hole_external,
857                          "AUTO")) )
858   {
859     struct LocalAddressList lal;
860     struct sockaddr_in *s4;
861
862     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863                 "Detected eternal IP, can now back-fill AUTO:%u in hole punching specification of `%s'\n",
864                 (unsigned int) ch->ext_dns_port,
865                 ch->section_name);
866     memset (&lal, 0, sizeof (lal));
867     s4 = (struct sockaddr_in *) &lal.addr;
868     s4->sin_family = AF_INET;
869     s4->sin_port = htons (ch->ext_dns_port);
870     s4->sin_addr = *v4;
871     lal.af = AF_INET;
872     lal.ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
873     check_notify_client (&lal,
874                          ch,
875                          add);
876   }
877
878   /* (1) check if client cares. */
879   if (! ch->natted_address)
880     return;
881   have_v4 = GNUNET_NO;
882   for (unsigned int i=0;i<ch->num_caddrs;i++)
883   {
884     const struct sockaddr_storage *ss = &ch->caddrs[i].ss;
885
886     if (AF_INET != ss->ss_family)
887       continue;
888     have_v4 = GNUNET_YES;
889     break;
890   }
891   if (GNUNET_NO == have_v4)
892     return; /* IPv6-only */
893
894   /* (2) build address info */
895   memset (&sa,
896           0,
897           sizeof (sa));
898   sa.sin_family = AF_INET;
899   sa.sin_addr = *v4;
900   sa.sin_port = htons (0);
901
902   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
903               "Detected eternal IP %s, notifying client of external IP (without port)\n",
904               GNUNET_a2s ((const struct sockaddr *) &sa,
905                           sizeof (sa)));
906   /* (3) notify client of change */
907   notify_client (is_nat_v4 (v4)
908                  ? GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_LAN
909                  : GNUNET_NAT_AC_EXTERN | GNUNET_NAT_AC_GLOBAL,
910                  ch,
911                  add,
912                  &sa,
913                  sizeof (sa));
914 }
915
916
917 /**
918  * We got a connection reversal request from another peer.
919  * Notify applicable clients.
920  *
921  * @param cls closure with the `struct LocalAddressList`
922  * @param ra IP address of the peer who wants us to connect to it
923  */
924 static void
925 reversal_callback (void *cls,
926                    const struct sockaddr_in *ra)
927 {
928   struct LocalAddressList *lal = cls;
929   const struct sockaddr_in *l4;
930
931   GNUNET_assert (AF_INET == lal->af);
932   l4 = (const struct sockaddr_in *) &lal->addr;
933   for (struct ClientHandle *ch = ch_head;
934        NULL != ch;
935        ch = ch->next)
936   {
937     struct GNUNET_NAT_ConnectionReversalRequestedMessage *crrm;
938     struct GNUNET_MQ_Envelope *env;
939     int match;
940
941     /* Check if client is in applicable range for ICMP NAT traversal
942        for this local address */
943     if (! ch->natted_address)
944       continue;
945     match = GNUNET_NO;
946     for (unsigned int i=0;i<ch->num_caddrs;i++)
947     {
948       struct ClientAddress *ca = &ch->caddrs[i];
949       const struct sockaddr_in *c4;
950
951       if (AF_INET != ca->ss.ss_family)
952         continue;
953       c4 = (const struct sockaddr_in *) &ca->ss;
954       if ( (0 != c4->sin_addr.s_addr) &&
955            (l4->sin_addr.s_addr != c4->sin_addr.s_addr) )
956         continue;
957       match = GNUNET_YES;
958       break;
959     }
960     if (! match)
961       continue;
962
963     /* Notify applicable client about connection reversal request */
964     env = GNUNET_MQ_msg_extra (crrm,
965                                sizeof (struct sockaddr_in),
966                                GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED);
967     GNUNET_memcpy (&crrm[1],
968                    ra,
969                    sizeof (struct sockaddr_in));
970     GNUNET_MQ_send (ch->mq,
971                     env);
972   }
973 }
974
975
976 /**
977  * Task we run periodically to scan for network interfaces.
978  *
979  * @param cls NULL
980  */
981 static void
982 run_scan (void *cls)
983 {
984   struct IfcProcContext ifc_ctx;
985   int found;
986   int have_nat;
987   struct LocalAddressList *lnext;
988
989   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
990                                             &run_scan,
991                                             NULL);
992   memset (&ifc_ctx,
993           0,
994           sizeof (ifc_ctx));
995   GNUNET_OS_network_interfaces_list (&ifc_proc,
996                                      &ifc_ctx);
997   /* remove addresses that disappeared */
998   for (struct LocalAddressList *lal = lal_head;
999        NULL != lal;
1000        lal = lnext)
1001   {
1002     lnext = lal->next;
1003     found = GNUNET_NO;
1004     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1005          NULL != pos;
1006          pos = pos->next)
1007     {
1008       if ( (pos->af == lal->af) &&
1009            (0 == memcmp (&lal->addr,
1010                          &pos->addr,
1011                          (AF_INET == lal->af)
1012                          ? sizeof (struct sockaddr_in)
1013                          : sizeof (struct sockaddr_in6))) )
1014       {
1015         found = GNUNET_YES;
1016       }
1017     }
1018     if (GNUNET_NO == found)
1019     {
1020       notify_clients (lal,
1021                       GNUNET_NO);
1022       free_lal (lal);
1023     }
1024   }
1025
1026   /* add addresses that appeared */
1027   have_nat = GNUNET_NO;
1028   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1029        NULL != pos;
1030        pos = ifc_ctx.lal_head)
1031   {
1032     found = GNUNET_NO;
1033     if (GNUNET_NAT_AC_LAN == (GNUNET_NAT_AC_LAN & pos->ac))
1034       have_nat = GNUNET_YES;
1035     for (struct LocalAddressList *lal = lal_head;
1036          NULL != lal;
1037          lal = lal->next)
1038     {
1039       if ( (pos->af == lal->af) &&
1040            (0 == memcmp (&lal->addr,
1041                          &pos->addr,
1042                          (AF_INET == lal->af)
1043                          ? sizeof (struct sockaddr_in)
1044                          : sizeof (struct sockaddr_in6))) )
1045         found = GNUNET_YES;
1046     }
1047     GNUNET_CONTAINER_DLL_remove (ifc_ctx.lal_head,
1048                                  ifc_ctx.lal_tail,
1049                                  pos);
1050     if (GNUNET_YES == found)
1051     {
1052       GNUNET_free (pos);
1053     }
1054     else
1055     {
1056       notify_clients (pos,
1057                       GNUNET_YES);
1058       GNUNET_CONTAINER_DLL_insert (lal_head,
1059                                    lal_tail,
1060                                    pos);
1061       if ( (AF_INET == pos->af) &&
1062            (NULL == pos->hc) &&
1063            (0 != (GNUNET_NAT_AC_LAN & pos->ac)) )
1064       {
1065         const struct sockaddr_in *s4
1066           = (const struct sockaddr_in *) &pos->addr;
1067
1068         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1069                     "Found NATed local address %s, starting NAT server\n",
1070                     GNUNET_a2s ((const struct sockaddr *) &pos->addr,
1071                                 sizeof (*s4)));
1072         pos->hc = GN_start_gnunet_nat_server_ (&s4->sin_addr,
1073                                                &reversal_callback,
1074                                                pos);
1075       }
1076     }
1077   }
1078   GN_nat_status_changed (have_nat);
1079 }
1080
1081
1082 /**
1083  * Function called whenever our set of external addresses
1084  * as created by `upnpc` changes.
1085  *
1086  * @param cls closure with our `struct ClientHandle *`
1087  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1088  *     the previous (now invalid) one, #GNUNET_SYSERR indicates an error
1089  * @param addr either the previous or the new public IP address
1090  * @param addrlen actual length of the @a addr
1091  * @param result #GNUNET_NAT_ERROR_SUCCESS on success, otherwise the specific error code
1092  */
1093 static void
1094 upnp_addr_change_cb (void *cls,
1095                      int add_remove,
1096                      const struct sockaddr *addr,
1097                      socklen_t addrlen,
1098                      enum GNUNET_NAT_StatusCode result)
1099 {
1100   struct ClientHandle *ch = cls;
1101   enum GNUNET_NAT_AddressClass ac;
1102
1103   switch (result)
1104   {
1105   case GNUNET_NAT_ERROR_SUCCESS:
1106     GNUNET_assert (NULL != addr);
1107     break;
1108   case GNUNET_NAT_ERROR_UPNPC_FAILED:
1109   case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1110   case GNUNET_NAT_ERROR_IPC_FAILURE:
1111     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1112                 "Running upnpc failed: %d\n",
1113                 result);
1114     return;
1115   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1116     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1117                 "external-ip binary not found\n");
1118     return;
1119   case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1120     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1121                 "upnpc binary not found\n");
1122     return;
1123   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1124     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1125                 "external-ip binary could not be run\n");
1126     return;
1127   case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1128     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1129                 "upnpc failed to create port mapping\n");
1130     return;
1131   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1132     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133                 "Invalid output from upnpc\n");
1134     return;
1135   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1136     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137                 "Invalid address returned by upnpc\n");
1138     return;
1139   default:
1140     GNUNET_break (0); /* should not be possible */
1141     return;
1142   }
1143   switch (addr->sa_family)
1144   {
1145   case AF_INET:
1146     ac = is_nat_v4 (&((const struct sockaddr_in *) addr)->sin_addr)
1147       ? GNUNET_NAT_AC_LAN
1148       : GNUNET_NAT_AC_EXTERN;
1149     break;
1150   case AF_INET6:
1151     ac = is_nat_v6 (&((const struct sockaddr_in6 *) addr)->sin6_addr)
1152       ? GNUNET_NAT_AC_LAN
1153       : GNUNET_NAT_AC_EXTERN;
1154     break;
1155   default:
1156     GNUNET_break (0);
1157     return;
1158   }
1159   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1160               "upnp external address %s: %s\n",
1161               add_remove ? "added" : "removed",
1162               GNUNET_a2s (addr,
1163                           addrlen));
1164   notify_client (ac,
1165                  ch,
1166                  add_remove,
1167                  addr,
1168                  addrlen);
1169 }
1170
1171
1172 /**
1173  * Resolve the `hole_external` name to figure out our
1174  * external address from a manually punched hole.  The
1175  * port number has already been parsed, this task is
1176  * responsible for periodically doing a DNS lookup.
1177  *
1178  * @param ch client handle to act upon
1179  */
1180 static void
1181 dyndns_lookup (void *cls);
1182
1183
1184 /**
1185  * Our (external) hostname was resolved.  Update lists of
1186  * current external IPs (note that DNS may return multiple
1187  * addresses!) and notify client accordingly.
1188  *
1189  * @param cls the `struct ClientHandle`
1190  * @param addr NULL on error, otherwise result of DNS lookup
1191  * @param addrlen number of bytes in @a addr
1192  */
1193 static void
1194 process_external_ip (void *cls,
1195                      const struct sockaddr *addr,
1196                      socklen_t addrlen)
1197 {
1198   struct ClientHandle *ch = cls;
1199   struct LocalAddressList *lal;
1200   struct sockaddr_storage ss;
1201   struct sockaddr_in *v4;
1202   struct sockaddr_in6 *v6;
1203
1204   if (NULL == addr)
1205   {
1206     struct LocalAddressList *laln;
1207
1208     ch->ext_dns = NULL;
1209     ch->ext_dns_task
1210       = GNUNET_SCHEDULER_add_delayed (dyndns_frequency,
1211                                       &dyndns_lookup,
1212                                       ch);
1213     /* Current iteration is over, remove 'old' IPs now */
1214     for (lal = ch->ext_addr_head; NULL != lal; lal = laln)
1215     {
1216       laln = lal->next;
1217       if (GNUNET_YES == lal->old)
1218       {
1219         GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1220                                      ch->ext_addr_tail,
1221                                      lal);
1222         check_notify_client (lal,
1223                              ch,
1224                              GNUNET_NO);
1225         GNUNET_free (lal);
1226       }
1227     }
1228     return;
1229   }
1230   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1231               "Got IP `%s' for external address `%s'\n",
1232               GNUNET_a2s (addr,
1233                           addrlen),
1234               ch->hole_external);
1235
1236   /* build sockaddr storage with port number */
1237   memset (&ss,
1238           0,
1239           sizeof (ss));
1240   GNUNET_memcpy (&ss,
1241                  addr,
1242                  addrlen);
1243   switch (addr->sa_family)
1244   {
1245   case AF_INET:
1246     v4 = (struct sockaddr_in *) &ss;
1247     v4->sin_port = htons (ch->ext_dns_port);
1248     break;
1249   case AF_INET6:
1250     v6 = (struct sockaddr_in6 *) &ss;
1251     v6->sin6_port = htons (ch->ext_dns_port);
1252     break;
1253   default:
1254     GNUNET_break (0);
1255     return;
1256   }
1257   /* See if 'ss' matches any of our known addresses */
1258   for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1259   {
1260     if (GNUNET_NO == lal->old)
1261       continue; /* already processed, skip */
1262     if ( (addr->sa_family == lal->addr.ss_family) &&
1263          (0 == memcmp (&ss,
1264                        &lal->addr,
1265                        addrlen)) )
1266     {
1267       /* Address unchanged, remember so we do not remove */
1268       lal->old = GNUNET_NO;
1269       return; /* done here */
1270     }
1271   }
1272   /* notify client, and remember IP for later removal! */
1273   lal = GNUNET_new (struct LocalAddressList);
1274   lal->addr = ss;
1275   lal->af = ss.ss_family;
1276   lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1277   GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1278                                ch->ext_addr_tail,
1279                                lal);
1280   check_notify_client (lal,
1281                        ch,
1282                        GNUNET_YES);
1283 }
1284
1285
1286 /**
1287  * Resolve the `hole_external` name to figure out our
1288  * external address from a manually punched hole.  The
1289  * port number has already been parsed, this task is
1290  * responsible for periodically doing a DNS lookup.
1291  *
1292  * @param ch client handle to act upon
1293  */
1294 static void
1295 dyndns_lookup (void *cls)
1296 {
1297   struct ClientHandle *ch = cls;
1298   struct LocalAddressList *lal;
1299
1300   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1301               "Performing DNS lookup for punched hole given for `%s' as `%s:%u'\n",
1302               ch->section_name,
1303               ch->hole_external,
1304               (unsigned int) ch->ext_dns_port);
1305   for (lal = ch->ext_addr_head; NULL != lal; lal = lal->next)
1306     lal->old = GNUNET_YES;
1307   ch->ext_dns_task = NULL;
1308   ch->ext_dns = GNUNET_RESOLVER_ip_get (ch->hole_external,
1309                                         AF_UNSPEC,
1310                                         GNUNET_TIME_UNIT_MINUTES,
1311                                         &process_external_ip,
1312                                         ch);
1313 }
1314
1315
1316 /**
1317  * Resolve the `hole_external` name to figure out our
1318  * external address from a manually punched hole.  The
1319  * given name may be "AUTO" in which case we should use
1320  * the IP address(es) we have from upnpc or other methods.
1321  * The name can also be an IP address, in which case we
1322  * do not need to do DNS resolution.  Finally, we also
1323  * need to parse the port number.
1324  *
1325  * @param ch client handle to act upon
1326  */
1327 static void
1328 lookup_hole_external (struct ClientHandle *ch)
1329 {
1330   char *port;
1331   unsigned int pnum;
1332   struct sockaddr_in *s4;
1333   struct LocalAddressList *lal;
1334
1335   port = strrchr (ch->hole_external, ':');
1336   if (NULL == port)
1337   {
1338     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1339                 _("Malformed punched hole specification `%s' (lacks port)\n"),
1340                 ch->hole_external);
1341     return;
1342   }
1343   if ( (1 != sscanf (port + 1,
1344                      "%u",
1345                      &pnum)) ||
1346        (pnum > 65535) )
1347   {
1348     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1349                 _("Invalid port number in punched hole specification `%s' (lacks port)\n"),
1350                 port + 1);
1351     return;
1352   }
1353   ch->ext_dns_port = (uint16_t) pnum;
1354   *port = '\0';
1355
1356   lal = GNUNET_new (struct LocalAddressList);
1357   if ('[' == *ch->hole_external)
1358   {
1359     struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &lal->addr;
1360
1361     s6->sin6_family = AF_INET6;
1362     if (']' != (ch->hole_external[strlen(ch->hole_external)-1]))
1363     {
1364       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1365                   _("Malformed punched hole specification `%s' (lacks `]')\n"),
1366                   ch->hole_external);
1367       GNUNET_free (lal);
1368       return;
1369     }
1370     ch->hole_external[strlen(ch->hole_external)-1] = '\0';
1371     if (1 != inet_pton (AF_INET6,
1372                         ch->hole_external + 1,
1373                         &s6->sin6_addr))
1374     {
1375       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1376                   _("Malformed punched hole specification `%s' (IPv6 address invalid)"),
1377                   ch->hole_external + 1);
1378       GNUNET_free (lal);
1379       return;
1380     }
1381     s6->sin6_port = htons (ch->ext_dns_port);
1382     lal->af = AF_INET6;
1383     lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1384     GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1385                                  ch->ext_addr_tail,
1386                                  lal);
1387     check_notify_client (lal,
1388                          ch,
1389                          GNUNET_YES);
1390     return;
1391   }
1392
1393   s4 = (struct sockaddr_in *) &lal->addr;
1394   s4->sin_family = AF_INET;
1395   if (1 == inet_pton (AF_INET,
1396                       ch->hole_external,
1397                       &s4->sin_addr))
1398   {
1399     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1400                 "IPv4 punched hole given for `%s' via `%s:%u'\n",
1401                 ch->section_name,
1402                 ch->hole_external,
1403                 (unsigned int) ch->ext_dns_port);
1404     s4->sin_port = htons (ch->ext_dns_port);
1405     lal->af = AF_INET;
1406     lal->ac = GNUNET_NAT_AC_GLOBAL | GNUNET_NAT_AC_MANUAL;
1407     GNUNET_CONTAINER_DLL_insert (ch->ext_addr_head,
1408                                  ch->ext_addr_tail,
1409                                  lal);
1410     check_notify_client (lal,
1411                          ch,
1412                          GNUNET_YES);
1413     return;
1414   }
1415   if (0 == strcasecmp (ch->hole_external,
1416                        "AUTO"))
1417   {
1418     /* handled in #notify_client_external_ipv4_change() */
1419     GNUNET_free (lal);
1420     return;
1421   }
1422   /* got a DNS name, trigger lookup! */
1423   GNUNET_free (lal);
1424   ch->ext_dns_task
1425     = GNUNET_SCHEDULER_add_now (&dyndns_lookup,
1426                                 ch);
1427 }
1428
1429
1430 /**
1431  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
1432  * We remember the client for updates upon future NAT events.
1433  *
1434  * @param cls client who sent the message
1435  * @param message the message received
1436  */
1437 static void
1438 handle_register (void *cls,
1439                  const struct GNUNET_NAT_RegisterMessage *message)
1440 {
1441   struct ClientHandle *ch = cls;
1442   const char *off;
1443   size_t left;
1444
1445   if ( (0 != ch->proto) ||
1446        (NULL != ch->caddrs) )
1447   {
1448     /* double registration not allowed */
1449     GNUNET_break (0);
1450     GNUNET_SERVICE_client_drop (ch->client);
1451     return;
1452   }
1453   ch->flags = message->flags;
1454   ch->proto = message->proto;
1455   ch->num_caddrs = ntohs (message->num_addrs);
1456   ch->caddrs = GNUNET_new_array (ch->num_caddrs,
1457                                  struct ClientAddress);
1458   left = ntohs (message->header.size) - sizeof (*message);
1459   off = (const char *) &message[1];
1460   for (unsigned int i=0;i<ch->num_caddrs;i++)
1461   {
1462     const struct sockaddr *sa = (const struct sockaddr *) off;
1463     size_t alen;
1464     uint16_t port;
1465     int is_nat;
1466
1467     if (sizeof (sa_family_t) > left)
1468     {
1469       GNUNET_break (0);
1470       GNUNET_SERVICE_client_drop (ch->client);
1471       return;
1472     }
1473     is_nat = GNUNET_NO;
1474     switch (sa->sa_family)
1475     {
1476     case AF_INET:
1477       {
1478         struct sockaddr_in s4;
1479
1480         GNUNET_memcpy (&s4,
1481                        off,
1482                        sizeof (struct sockaddr_in));
1483         alen = sizeof (struct sockaddr_in);
1484         if (is_nat_v4 (&s4.sin_addr))
1485           is_nat = GNUNET_YES;
1486         port = ntohs (s4.sin_port);
1487       }
1488       break;
1489     case AF_INET6:
1490       {
1491         struct sockaddr_in6 s6;
1492
1493         GNUNET_memcpy (&s6,
1494                        off,
1495                        sizeof (struct sockaddr_in6));
1496         alen = sizeof (struct sockaddr_in6);
1497         if (is_nat_v6 (&s6.sin6_addr))
1498           is_nat = GNUNET_YES;
1499         port = ntohs (s6.sin6_port);
1500       }
1501       break;
1502 #if AF_UNIX
1503     case AF_UNIX:
1504       alen = sizeof (struct sockaddr_un);
1505       port = 0;
1506       break;
1507 #endif
1508     default:
1509       GNUNET_break (0);
1510       GNUNET_SERVICE_client_drop (ch->client);
1511       return;
1512     }
1513     /* store address */
1514     GNUNET_assert (alen <= left);
1515     GNUNET_assert (alen <= sizeof (struct sockaddr_storage));
1516     GNUNET_memcpy (&ch->caddrs[i].ss,
1517                    off,
1518                    alen);
1519
1520     /* If applicable, try UPNPC NAT punching */
1521     if ( (is_nat) &&
1522          (enable_upnp) &&
1523          ( (IPPROTO_TCP == ch->proto) ||
1524            (IPPROTO_UDP == ch->proto) ) )
1525     {
1526       ch->natted_address = GNUNET_YES;
1527       ch->caddrs[i].mh
1528         = GNUNET_NAT_mini_map_start (port,
1529                                      IPPROTO_TCP == ch->proto,
1530                                      &upnp_addr_change_cb,
1531                                      ch);
1532     }
1533
1534     off += alen;
1535   }
1536
1537   ch->section_name
1538     = GNUNET_strndup (off,
1539                       ntohs (message->str_len));
1540   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1541               "Received REGISTER message from client for subsystem `%s'\n",
1542               ch->section_name);
1543   if (GNUNET_OK ==
1544       GNUNET_CONFIGURATION_get_value_string (cfg,
1545                                              ch->section_name,
1546                                              "HOLE_EXTERNAL",
1547                                              &ch->hole_external))
1548     lookup_hole_external (ch);
1549
1550   /* Actually send IP address list to client */
1551   for (struct LocalAddressList *lal = lal_head;
1552        NULL != lal;
1553        lal = lal->next)
1554   {
1555     check_notify_client (lal,
1556                          ch,
1557                          GNUNET_YES);
1558   }
1559   /* Also consider IPv4 determined by `external-ip` */
1560   ch->external_monitor
1561     = GN_external_ipv4_monitor_start (&notify_client_external_ipv4_change,
1562                                       ch);
1563   GNUNET_SERVICE_client_continue (ch->client);
1564 }
1565
1566
1567 /**
1568  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1569  * client.
1570  *
1571  * @param cls client who sent the message
1572  * @param message the message received
1573  * @return #GNUNET_OK if message is well-formed
1574  */
1575 static int
1576 check_stun (void *cls,
1577             const struct GNUNET_NAT_HandleStunMessage *message)
1578 {
1579   size_t sa_len = ntohs (message->sender_addr_size);
1580   size_t expect = sa_len + ntohs (message->payload_size);
1581
1582   if (ntohs (message->header.size) - sizeof (*message) != expect)
1583   {
1584     GNUNET_break (0);
1585     return GNUNET_SYSERR;
1586   }
1587   if (sa_len < sizeof (sa_family_t))
1588   {
1589     GNUNET_break (0);
1590     return GNUNET_SYSERR;
1591   }
1592   return GNUNET_OK;
1593 }
1594
1595
1596 /**
1597  * Notify all clients about our external IP address
1598  * as reported by the STUN server.
1599  *
1600  * @param ip the external IP
1601  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
1602  */
1603 static void
1604 notify_clients_stun_change (const struct sockaddr_in *ip,
1605                             int add)
1606 {
1607   for (struct ClientHandle *ch = ch_head;
1608        NULL != ch;
1609        ch = ch->next)
1610   {
1611     struct sockaddr_in v4;
1612     struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
1613     struct GNUNET_MQ_Envelope *env;
1614
1615     if (! ch->natted_address)
1616       continue;
1617     v4 = *ip;
1618     v4.sin_port = htons (0);
1619     env = GNUNET_MQ_msg_extra (msg,
1620                                sizeof (v4),
1621                                GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
1622     msg->add_remove = htonl ((int32_t) add);
1623     msg->addr_class = htonl (GNUNET_NAT_AC_EXTERN |
1624                              GNUNET_NAT_AC_GLOBAL);
1625     GNUNET_memcpy (&msg[1],
1626                    &v4,
1627                    sizeof (v4));
1628     GNUNET_MQ_send (ch->mq,
1629                     env);
1630   }
1631 }
1632
1633
1634 /**
1635  * Function to be called when we decide that an
1636  * external IP address as told to us by a STUN
1637  * server has gone stale.
1638  *
1639  * @param cls the `struct StunExternalIP` to drop
1640  */
1641 static void
1642 stun_ip_timeout (void *cls)
1643 {
1644   struct StunExternalIP *se = cls;
1645
1646   se->timeout_task = NULL;
1647   notify_clients_stun_change (&se->external_addr,
1648                               GNUNET_NO);
1649   GNUNET_CONTAINER_DLL_remove (se_head,
1650                                se_tail,
1651                                se);
1652   GNUNET_free (se);
1653 }
1654
1655
1656 /**
1657  * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
1658  * client.
1659  *
1660  * @param cls client who sent the message
1661  * @param message the message received
1662  */
1663 static void
1664 handle_stun (void *cls,
1665              const struct GNUNET_NAT_HandleStunMessage *message)
1666 {
1667   struct ClientHandle *ch = cls;
1668   const char *buf = (const char *) &message[1];
1669   const struct sockaddr *sa;
1670   const void *payload;
1671   size_t sa_len;
1672   size_t payload_size;
1673   struct sockaddr_in external_addr;
1674
1675   sa_len = ntohs (message->sender_addr_size);
1676   payload_size = ntohs (message->payload_size);
1677   sa = (const struct sockaddr *) &buf[0];
1678   payload = (const struct sockaddr *) &buf[sa_len];
1679   switch (sa->sa_family)
1680   {
1681   case AF_INET:
1682     if (sa_len != sizeof (struct sockaddr_in))
1683     {
1684       GNUNET_break (0);
1685       GNUNET_SERVICE_client_drop (ch->client);
1686       return;
1687     }
1688     break;
1689   case AF_INET6:
1690     if (sa_len != sizeof (struct sockaddr_in6))
1691     {
1692       GNUNET_break (0);
1693       GNUNET_SERVICE_client_drop (ch->client);
1694       return;
1695     }
1696     break;
1697   }
1698   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1699               "Received HANDLE_STUN message from client\n");
1700   if (GNUNET_OK ==
1701       GNUNET_NAT_stun_handle_packet_ (payload,
1702                                       payload_size,
1703                                       &external_addr))
1704   {
1705     /* We now know that a server at "sa" claims that
1706        we are visible at IP "external_addr".
1707
1708        We should (for some fixed period of time) tell
1709        all of our clients that listen to a NAT'ed address
1710        that they might want to consider the given 'external_ip'
1711        as their public IP address (this includes TCP and UDP
1712        clients, even if only UDP sends STUN requests).
1713
1714        If we do not get a renewal, the "external_addr" should be
1715        removed again.  The timeout frequency should be configurable
1716        (with a sane default), so that the UDP plugin can tell how
1717        often to re-request STUN.
1718     */
1719     struct StunExternalIP *se;
1720
1721     /* Check if we had a prior response from this STUN server */
1722     for (se = se_head; NULL != se; se = se->next)
1723     {
1724       if ( (se->stun_server_addr_len != sa_len) ||
1725            (0 != memcmp (sa,
1726                          &se->stun_server_addr,
1727                          sa_len)) )
1728         continue; /* different STUN server */
1729       if (0 != memcmp (&external_addr,
1730                        &se->external_addr,
1731                        sizeof (struct sockaddr_in)))
1732       {
1733         /* external IP changed, update! */
1734         notify_clients_stun_change (&se->external_addr,
1735                                     GNUNET_NO);
1736         se->external_addr = external_addr;
1737         notify_clients_stun_change (&se->external_addr,
1738                                     GNUNET_YES);
1739       }
1740       /* update timeout */
1741       GNUNET_SCHEDULER_cancel (se->timeout_task);
1742       se->timeout_task
1743         = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1744                                         &stun_ip_timeout,
1745                                         se);
1746       return;
1747     }
1748     /* STUN server is completely new, create fresh entry */
1749     se = GNUNET_new (struct StunExternalIP);
1750     se->external_addr = external_addr;
1751     GNUNET_memcpy (&se->stun_server_addr,
1752                    sa,
1753                    sa_len);
1754     se->stun_server_addr_len = sa_len;
1755     se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
1756                                                      &stun_ip_timeout,
1757                                                      se);
1758     GNUNET_CONTAINER_DLL_insert (se_head,
1759                                  se_tail,
1760                                  se);
1761     notify_clients_stun_change (&se->external_addr,
1762                                 GNUNET_NO);
1763   }
1764   GNUNET_SERVICE_client_continue (ch->client);
1765 }
1766
1767
1768 /**
1769  * Check validity of
1770  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
1771  * client.
1772  *
1773  * @param cls client who sent the message
1774  * @param message the message received
1775  * @return #GNUNET_OK if message is well-formed
1776  */
1777 static int
1778 check_request_connection_reversal (void *cls,
1779                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1780 {
1781   size_t expect;
1782
1783   expect = ntohs (message->local_addr_size)
1784     + ntohs (message->remote_addr_size);
1785   if (ntohs (message->header.size) - sizeof (*message) != expect)
1786   {
1787     GNUNET_break (0);
1788     return GNUNET_SYSERR;
1789   }
1790   return GNUNET_OK;
1791 }
1792
1793
1794 /**
1795  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
1796  * message from client.
1797  *
1798  * @param cls client who sent the message
1799  * @param message the message received
1800  */
1801 static void
1802 handle_request_connection_reversal (void *cls,
1803                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
1804 {
1805   struct ClientHandle *ch = cls;
1806   const char *buf = (const char *) &message[1];
1807   size_t local_sa_len = ntohs (message->local_addr_size);
1808   size_t remote_sa_len = ntohs (message->remote_addr_size);
1809   struct sockaddr_in l4;
1810   struct sockaddr_in r4;
1811   int ret;
1812
1813   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1814               "Received REQUEST CONNECTION REVERSAL message from client\n");
1815   if (local_sa_len != sizeof (struct sockaddr_in))
1816   {
1817     GNUNET_break_op (0);
1818     GNUNET_SERVICE_client_drop (ch->client);
1819     return;
1820   }
1821   if (remote_sa_len != sizeof (struct sockaddr_in))
1822   {
1823     GNUNET_break_op (0);
1824     GNUNET_SERVICE_client_drop (ch->client);
1825     return;
1826   }
1827   GNUNET_memcpy (&l4,
1828                  buf,
1829                  sizeof (struct sockaddr_in));
1830   GNUNET_break_op (AF_INET == l4.sin_family);
1831   buf += sizeof (struct sockaddr_in);
1832   GNUNET_memcpy (&r4,
1833                  buf,
1834                  sizeof (struct sockaddr_in));
1835   GNUNET_break_op (AF_INET == r4.sin_family);
1836   ret = GN_request_connection_reversal (&l4.sin_addr,
1837                                         ntohs (l4.sin_port),
1838                                         &r4.sin_addr);
1839   if (GNUNET_OK != ret)
1840     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1841                 _("Connection reversal request failed\n"));
1842   GNUNET_SERVICE_client_continue (ch->client);
1843 }
1844
1845
1846 /**
1847  * Task run during shutdown.
1848  *
1849  * @param cls unused
1850  */
1851 static void
1852 shutdown_task (void *cls)
1853 {
1854   struct StunExternalIP *se;
1855
1856   while (NULL != (se = se_head))
1857   {
1858     GNUNET_CONTAINER_DLL_remove (se_head,
1859                                  se_tail,
1860                                  se);
1861     GNUNET_SCHEDULER_cancel (se->timeout_task);
1862     GNUNET_free (se);
1863   }
1864   GN_nat_status_changed (GNUNET_NO);
1865   if (NULL != scan_task)
1866   {
1867     GNUNET_SCHEDULER_cancel (scan_task);
1868     scan_task = NULL;
1869   }
1870   if (NULL != stats)
1871   {
1872     GNUNET_STATISTICS_destroy (stats,
1873                                GNUNET_NO);
1874     stats = NULL;
1875   }
1876   destroy_lal ();
1877 }
1878
1879
1880 /**
1881  * Setup NAT service.
1882  *
1883  * @param cls closure
1884  * @param c configuration to use
1885  * @param service the initialized service
1886  */
1887 static void
1888 run (void *cls,
1889      const struct GNUNET_CONFIGURATION_Handle *c,
1890      struct GNUNET_SERVICE_Handle *service)
1891 {
1892   cfg = c;
1893   if (GNUNET_OK !=
1894       GNUNET_CONFIGURATION_get_value_time (cfg,
1895                                            "NAT",
1896                                            "STUN_STALE",
1897                                            &stun_stale_timeout))
1898     stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1899
1900   /* Check for UPnP */
1901   enable_upnp
1902     = GNUNET_CONFIGURATION_get_value_yesno (cfg,
1903                                             "NAT",
1904                                             "ENABLE_UPNP");
1905   if (GNUNET_YES == enable_upnp)
1906   {
1907     /* check if it works */
1908     if (GNUNET_SYSERR ==
1909         GNUNET_OS_check_helper_binary ("upnpc",
1910                                        GNUNET_NO,
1911                                        NULL))
1912     {
1913       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1914                   _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP\n"));
1915       enable_upnp = GNUNET_SYSERR;
1916     }
1917   }
1918   if (GNUNET_OK !=
1919       GNUNET_CONFIGURATION_get_value_time (cfg,
1920                                            "nat",
1921                                            "DYNDNS_FREQUENCY",
1922                                            &dyndns_frequency))
1923     dyndns_frequency = DYNDNS_FREQUENCY;
1924
1925   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1926                                  NULL);
1927   stats = GNUNET_STATISTICS_create ("nat",
1928                                     cfg);
1929   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1930                                         NULL);
1931 }
1932
1933
1934 /**
1935  * Callback called when a client connects to the service.
1936  *
1937  * @param cls closure for the service
1938  * @param c the new client that connected to the service
1939  * @param mq the message queue used to send messages to the client
1940  * @return a `struct ClientHandle`
1941  */
1942 static void *
1943 client_connect_cb (void *cls,
1944                    struct GNUNET_SERVICE_Client *c,
1945                    struct GNUNET_MQ_Handle *mq)
1946 {
1947   struct ClientHandle *ch;
1948
1949   ch = GNUNET_new (struct ClientHandle);
1950   ch->mq = mq;
1951   ch->client = c;
1952   GNUNET_CONTAINER_DLL_insert (ch_head,
1953                                ch_tail,
1954                                ch);
1955   return ch;
1956 }
1957
1958
1959 /**
1960  * Callback called when a client disconnected from the service
1961  *
1962  * @param cls closure for the service
1963  * @param c the client that disconnected
1964  * @param internal_cls a `struct ClientHandle *`
1965  */
1966 static void
1967 client_disconnect_cb (void *cls,
1968                       struct GNUNET_SERVICE_Client *c,
1969                       void *internal_cls)
1970 {
1971   struct ClientHandle *ch = internal_cls;
1972   struct LocalAddressList *lal;
1973
1974   GNUNET_CONTAINER_DLL_remove (ch_head,
1975                                ch_tail,
1976                                ch);
1977   for (unsigned int i=0;i<ch->num_caddrs;i++)
1978   {
1979     if (NULL != ch->caddrs[i].mh)
1980     {
1981       GNUNET_NAT_mini_map_stop (ch->caddrs[i].mh);
1982       ch->caddrs[i].mh = NULL;
1983     }
1984   }
1985   GNUNET_free_non_null (ch->caddrs);
1986   while (NULL != (lal = ch->ext_addr_head))
1987   {
1988     GNUNET_CONTAINER_DLL_remove (ch->ext_addr_head,
1989                                  ch->ext_addr_tail,
1990                                  lal);
1991     GNUNET_free (lal);
1992   }
1993   if (NULL != ch->ext_dns_task)
1994   {
1995     GNUNET_SCHEDULER_cancel (ch->ext_dns_task);
1996     ch->ext_dns_task = NULL;
1997   }
1998   if (NULL != ch->external_monitor)
1999   {
2000     GN_external_ipv4_monitor_stop (ch->external_monitor);
2001     ch->external_monitor = NULL;
2002   }
2003   if (NULL != ch->ext_dns)
2004   {
2005     GNUNET_RESOLVER_request_cancel (ch->ext_dns);
2006     ch->ext_dns = NULL;
2007   }
2008   GNUNET_free_non_null (ch->hole_external);
2009   GNUNET_free_non_null (ch->section_name);
2010   GNUNET_free (ch);
2011 }
2012
2013
2014 /**
2015  * Define "main" method using service macro.
2016  */
2017 GNUNET_SERVICE_MAIN
2018 ("nat",
2019  GNUNET_SERVICE_OPTION_NONE,
2020  &run,
2021  &client_connect_cb,
2022  &client_disconnect_cb,
2023  NULL,
2024  GNUNET_MQ_hd_var_size (register,
2025                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
2026                         struct GNUNET_NAT_RegisterMessage,
2027                         NULL),
2028  GNUNET_MQ_hd_var_size (stun,
2029                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
2030                         struct GNUNET_NAT_HandleStunMessage,
2031                         NULL),
2032  GNUNET_MQ_hd_var_size (request_connection_reversal,
2033                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
2034                         struct GNUNET_NAT_RequestConnectionReversalMessage,
2035                         NULL),
2036  GNUNET_MQ_handler_end ());
2037
2038
2039 #if defined(LINUX) && defined(__GLIBC__)
2040 #include <malloc.h>
2041
2042 /**
2043  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
2044  */
2045 void __attribute__ ((constructor))
2046 GNUNET_ARM_memory_init ()
2047 {
2048   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
2049   mallopt (M_TOP_PAD, 1 * 1024);
2050   malloc_trim (0);
2051 }
2052 #endif
2053
2054 /* end of gnunet-service-nat.c */