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