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