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