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