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