do not add our virtual interfaces to our HELLO
[oweals/gnunet.git] / src / nat / nat.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file nat/nat.c
23  * @brief Library handling UPnP and NAT-PMP port forwarding and
24  *     external IP address retrieval
25  * @author Milan Bouchet-Valat
26  * @author Christian Grothoff
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_resolver_service.h"
31 #include "gnunet_nat_lib.h"
32 #include "nat.h"
33
34 #define LOG(kind,...) GNUNET_log_from (kind, "nat", __VA_ARGS__)
35
36 /**
37  * How often do we scan for changes in our IP address from our local
38  * interfaces?
39  */
40 #define IFC_SCAN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
41
42 /**
43  * How often do we scan for changes in how our hostname resolves?
44  */
45 #define HOSTNAME_DNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 20)
46
47
48 /**
49  * How often do we scan for changes in how our external (dyndns) hostname resolves?
50  */
51 #define DYNDNS_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 7)
52
53 /**
54  * How long until we give up trying to resolve our own hostname?
55  */
56 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
57
58
59 /**
60  * Where did the given local address originate from?
61  * To be used for debugging as well as in the future
62  * to remove all addresses from a certain source when
63  * we reevaluate the source.
64  */
65 enum LocalAddressSource
66 {
67   /**
68    * Address was obtained by DNS resolution of the external hostname
69    * given in the configuration (i.e. hole-punched DynDNS setup).
70    */
71   LAL_EXTERNAL_IP,
72
73    /**
74    * Address was obtained by an external STUN server
75    */
76   LAL_EXTERNAL_STUN_IP,
77
78   /**
79    * Address was obtained by DNS resolution of the external hostname
80    * given in the configuration (i.e. hole-punched DynDNS setup)
81    * during the previous iteration (see #3213).
82    */
83   LAL_EXTERNAL_IP_OLD,
84
85   /**
86    * Address was obtained by looking up our own hostname in DNS.
87    */
88   LAL_HOSTNAME_DNS,
89
90   /**
91    * Address was obtained by scanning our hosts's network interfaces
92    * and taking their address (no DNS involved).
93    */
94   LAL_INTERFACE_ADDRESS,
95
96   /**
97    * Addresses we were explicitly bound to.
98    */
99   LAL_BINDTO_ADDRESS,
100
101   /**
102    * Addresses from UPnP or PMP
103    */
104   LAL_UPNP,
105
106   /**
107    * End of the list.
108    */
109   LAL_END
110 };
111
112
113 /**
114  * List of local addresses that we currently deem valid.  Actual
115  * struct is followed by the 'struct sockaddr'.  Note that the code
116  * intentionally makes no attempt to ensure that a particular address
117  * is only listed once (especially since it may come from different
118  * sources, and the source is an "internal" construct).
119  */
120 struct LocalAddressList
121 {
122   /**
123    * This is a linked list.
124    */
125   struct LocalAddressList *next;
126
127   /**
128    * Previous entry.
129    */
130   struct LocalAddressList *prev;
131
132   /**
133    * Number of bytes of address that follow.
134    */
135   socklen_t addrlen;
136
137   /**
138    * Origin of the local address.
139    */
140   enum LocalAddressSource source;
141 };
142
143
144 /**
145  * Handle for miniupnp-based NAT traversal actions.
146  */
147 struct MiniList
148 {
149
150   /**
151    * Doubly-linked list.
152    */
153   struct MiniList *next;
154
155   /**
156    * Doubly-linked list.
157    */
158   struct MiniList *prev;
159
160   /**
161    * Handle to mini-action.
162    */
163   struct GNUNET_NAT_MiniHandle *mini;
164
165   /**
166    * Local port number that was mapped.
167    */
168   uint16_t port;
169
170 };
171
172
173 /**
174  * Handle for active NAT registrations.
175  */
176 struct GNUNET_NAT_Handle
177 {
178
179   /**
180    * Configuration to use.
181    */
182   const struct GNUNET_CONFIGURATION_Handle *cfg;
183
184   /**
185    * Function to call when we learn about a new address.
186    */
187   GNUNET_NAT_AddressCallback address_callback;
188
189   /**
190    * Function to call when we notice another peer asking for
191    * connection reversal.
192    */
193   GNUNET_NAT_ReversalCallback reversal_callback;
194
195   /**
196    * Closure for callbacks (@e address_callback and @e reversal_callback)
197    */
198   void *callback_cls;
199
200   /**
201    * Handle for (DYN)DNS lookup of our external IP.
202    */
203   struct GNUNET_RESOLVER_RequestHandle *ext_dns;
204
205   /**
206    * Handle for request of hostname resolution, non-NULL if pending.
207    */
208   struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
209
210   /**
211    * stdout pipe handle for the gnunet-helper-nat-server process
212    */
213   struct GNUNET_DISK_PipeHandle *server_stdout;
214
215   /**
216    * stdout file handle (for reading) for the gnunet-helper-nat-server process
217    */
218   const struct GNUNET_DISK_FileHandle *server_stdout_handle;
219
220   /**
221    * Linked list of currently valid addresses (head).
222    */
223   struct LocalAddressList *lal_head;
224
225   /**
226    * Linked list of currently valid addresses (tail).
227    */
228   struct LocalAddressList *lal_tail;
229
230   /**
231    * How long do we wait for restarting a crashed gnunet-helper-nat-server?
232    */
233   struct GNUNET_TIME_Relative server_retry_delay;
234
235   /**
236    * ID of select gnunet-helper-nat-server stdout read task
237    */
238   struct GNUNET_SCHEDULER_Task * server_read_task;
239
240   /**
241    * ID of interface IP-scan task
242    */
243   struct GNUNET_SCHEDULER_Task * ifc_task;
244
245   /**
246    * ID of hostname DNS lookup task
247    */
248   struct GNUNET_SCHEDULER_Task * hostname_task;
249
250   /**
251    * ID of DynDNS lookup task
252    */
253   struct GNUNET_SCHEDULER_Task *dns_task;
254
255   /**
256    * How often do we scan for changes in our IP address from our local
257    * interfaces?
258    */
259   struct GNUNET_TIME_Relative ifc_scan_frequency;
260
261   /**
262    * How often do we scan for changes in how our hostname resolves?
263    */
264   struct GNUNET_TIME_Relative hostname_dns_frequency;
265
266   /**
267    * How often do we scan for changes in how our external (dyndns) hostname resolves?
268    */
269   struct GNUNET_TIME_Relative dyndns_frequency;
270
271   /**
272    * The process id of the server process (if behind NAT)
273    */
274   struct GNUNET_OS_Process *server_proc;
275
276   /**
277    * LAN address as passed by the caller (array).
278    */
279   struct sockaddr **local_addrs;
280
281   /**
282    * Length of the @e local_addrs.
283    */
284   socklen_t *local_addrlens;
285
286   /**
287    * List of handles for UPnP-traversal, one per local port (if
288    * not IPv6-only).
289    */
290   struct MiniList *mini_head;
291
292   /**
293    * List of handles for UPnP-traversal, one per local port (if
294    * not IPv6-only).
295    */
296   struct MiniList *mini_tail;
297
298   /**
299    * Number of entries in 'local_addrs' array.
300    */
301   unsigned int num_local_addrs;
302
303   /**
304    * Our external address (according to config, UPnP may disagree...),
305    * in dotted decimal notation, IPv4-only. Or NULL if not known.
306    */
307   char *external_address;
308
309   /**
310    * Presumably our internal address (according to config)
311    */
312   char *internal_address;
313
314   /**
315    * Is this transport configured to be behind a NAT?
316    */
317   int behind_nat;
318
319   /**
320    * Has the NAT been punched? (according to config)
321    */
322   int nat_punched;
323
324   /**
325    * Is this transport configured to allow connections to NAT'd peers?
326    */
327   int enable_nat_client;
328
329   /**
330    * Should we run the gnunet-helper-nat-server?
331    */
332   int enable_nat_server;
333
334   /**
335    * Are we allowed to try UPnP/PMP for NAT traversal?
336    */
337   int enable_upnp;
338
339   /**
340    * Should we use local addresses (loopback)? (according to config)
341    */
342   int use_localaddresses;
343
344   /**
345    * Should we return local addresses to clients
346    */
347   int return_localaddress;
348
349   /**
350    * Should we do a DNS lookup of our hostname to find out our own IP?
351    */
352   int use_hostname;
353
354   /**
355    * Is using IPv6 disabled?
356    */
357   int disable_ipv6;
358
359   /**
360    * Is this TCP or UDP?
361    */
362   int is_tcp;
363
364   /**
365    * Port we advertise to the outside.
366    */
367   uint16_t adv_port;
368
369 };
370
371
372 /**
373  * Try to start the gnunet-helper-nat-server (if it is not
374  * already running).
375  *
376  * @param h handle to NAT
377  */
378 static void
379 start_gnunet_nat_server (struct GNUNET_NAT_Handle *h);
380
381
382 /**
383  * Remove all addresses from the list of 'local' addresses
384  * that originated from the given source.
385  *
386  * @param h handle to NAT
387  * @param src source that identifies addresses to remove
388  */
389 static void
390 remove_from_address_list_by_source (struct GNUNET_NAT_Handle *h,
391                                     enum LocalAddressSource src)
392 {
393   struct LocalAddressList *pos;
394   struct LocalAddressList *next;
395
396   next = h->lal_head;
397   while (NULL != (pos = next))
398   {
399     next = pos->next;
400     if (pos->source != src)
401       continue;
402     GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos);
403     if (NULL != h->address_callback)
404       h->address_callback (h->callback_cls, GNUNET_NO,
405                            (const struct sockaddr *) &pos[1], pos->addrlen);
406     GNUNET_free (pos);
407   }
408 }
409
410
411 /**
412  * Add the given address to the list of 'local' addresses, thereby
413  * making it a 'legal' address for this peer to have.
414  *
415  * @param h handle to NAT
416  * @param src where did the local address originate from?
417  * @param arg the address, some `struct sockaddr`
418  * @param arg_size number of bytes in @a arg
419  */
420 static void
421 add_to_address_list_as_is (struct GNUNET_NAT_Handle *h,
422                            enum LocalAddressSource src,
423                            const struct sockaddr *arg, socklen_t arg_size)
424 {
425   struct LocalAddressList *lal;
426
427   lal = GNUNET_malloc (sizeof (struct LocalAddressList) + arg_size);
428   memcpy (&lal[1], arg, arg_size);
429   lal->addrlen = arg_size;
430   lal->source = src;
431   GNUNET_CONTAINER_DLL_insert (h->lal_head, h->lal_tail, lal);
432   LOG (GNUNET_ERROR_TYPE_DEBUG,
433        "Adding address `%s' from source %d\n",
434        GNUNET_a2s (arg, arg_size),
435        src);
436   if (NULL != h->address_callback)
437     h->address_callback (h->callback_cls, GNUNET_YES, arg, arg_size);
438 }
439
440
441 /**
442  * Add the given address to the list of 'local' addresses, thereby
443  * making it a 'legal' address for this peer to have.   Set the
444  * port number in the process to the advertised port and possibly
445  * also to zero (if we have the gnunet-helper-nat-server).
446  *
447  * @param h handle to NAT
448  * @param src where did the local address originate from?
449  * @param arg the address, some `struct sockaddr`
450  * @param arg_size number of bytes in @a arg
451  */
452 static void
453 add_to_address_list (struct GNUNET_NAT_Handle *h,
454                      enum LocalAddressSource src,
455                      const struct sockaddr *arg,
456                      socklen_t arg_size)
457 {
458   struct sockaddr_in s4;
459   const struct sockaddr_in *in4;
460   struct sockaddr_in6 s6;
461   const struct sockaddr_in6 *in6;
462
463   if (arg_size == sizeof (struct sockaddr_in))
464   {
465     in4 = (const struct sockaddr_in *) arg;
466     s4 = *in4;
467     s4.sin_port = htons (h->adv_port);
468     add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4,
469                                sizeof (struct sockaddr_in));
470     if (GNUNET_YES == h->enable_nat_server)
471     {
472       /* also add with PORT = 0 to indicate NAT server is enabled */
473       s4.sin_port = htons (0);
474       add_to_address_list_as_is (h, src, (const struct sockaddr *) &s4,
475                                  sizeof (struct sockaddr_in));
476     }
477   }
478   else if (arg_size == sizeof (struct sockaddr_in6))
479   {
480     if (GNUNET_YES != h->disable_ipv6)
481     {
482       in6 = (const struct sockaddr_in6 *) arg;
483       s6 = *in6;
484       s6.sin6_port = htons (h->adv_port);
485       add_to_address_list_as_is (h, src, (const struct sockaddr *) &s6,
486                                  sizeof (struct sockaddr_in6));
487     }
488   }
489   else
490   {
491     GNUNET_assert (0);
492   }
493 }
494
495
496 /**
497  * Add the given IP address to the list of 'local' addresses, thereby
498  * making it a 'legal' address for this peer to have.
499  *
500  * @param h handle to NAT
501  * @param src where did the local address originate from?
502  * @param addr the address, some `struct in_addr` or `struct in6_addr`
503  * @param addrlen number of bytes in addr
504  */
505 static void
506 add_ip_to_address_list (struct GNUNET_NAT_Handle *h,
507                         enum LocalAddressSource src, const void *addr,
508                         socklen_t addrlen)
509 {
510   struct sockaddr_in s4;
511   const struct in_addr *in4;
512   struct sockaddr_in6 s6;
513   const struct in6_addr *in6;
514
515   if (addrlen == sizeof (struct in_addr))
516   {
517     in4 = (const struct in_addr *) addr;
518     memset (&s4, 0, sizeof (s4));
519     s4.sin_family = AF_INET;
520     s4.sin_port = 0;
521 #if HAVE_SOCKADDR_IN_SIN_LEN
522     s4.sin_len = (u_char) sizeof (struct sockaddr_in);
523 #endif
524     s4.sin_addr = *in4;
525     add_to_address_list (h, src, (const struct sockaddr *) &s4,
526                          sizeof (struct sockaddr_in));
527     if (GNUNET_YES == h->enable_nat_server)
528     {
529       /* also add with PORT = 0 to indicate NAT server is enabled */
530       s4.sin_port = htons (0);
531       add_to_address_list (h, src, (const struct sockaddr *) &s4,
532                            sizeof (struct sockaddr_in));
533
534     }
535   }
536   else if (addrlen == sizeof (struct in6_addr))
537   {
538     if (GNUNET_YES != h->disable_ipv6)
539     {
540       in6 = (const struct in6_addr *) addr;
541       memset (&s6, 0, sizeof (s6));
542       s6.sin6_family = AF_INET6;
543       s6.sin6_port = htons (h->adv_port);
544 #if HAVE_SOCKADDR_IN_SIN_LEN
545       s6.sin6_len = (u_char) sizeof (struct sockaddr_in6);
546 #endif
547       s6.sin6_addr = *in6;
548       add_to_address_list (h, src, (const struct sockaddr *) &s6,
549                            sizeof (struct sockaddr_in6));
550     }
551   }
552   else
553   {
554     GNUNET_assert (0);
555   }
556 }
557
558
559 /**
560  * Task to do DNS lookup on our external hostname to
561  * get DynDNS-IP addresses.
562  *
563  * @param cls the NAT handle
564  * @param tc scheduler context
565  */
566 static void
567 resolve_dns (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
568
569
570 /**
571  * Our (external) hostname was resolved and the configuration says that
572  * the NAT was hole-punched.
573  *
574  * @param cls the `struct GNUNET_NAT_Handle`
575  * @param addr NULL on error, otherwise result of DNS lookup
576  * @param addrlen number of bytes in @a addr
577  */
578 static void
579 process_external_ip (void *cls,
580                      const struct sockaddr *addr,
581                      socklen_t addrlen)
582 {
583   struct GNUNET_NAT_Handle *h = cls;
584   struct in_addr dummy;
585
586   if (NULL == addr)
587   {
588     h->ext_dns = NULL;
589     /* Current iteration is over, remove 'old' IPs now */
590     LOG (GNUNET_ERROR_TYPE_DEBUG,
591          "Purging old IPs for external address\n");
592     remove_from_address_list_by_source (h, LAL_EXTERNAL_IP_OLD);
593     if (1 == inet_pton (AF_INET,
594                         h->external_address,
595                         &dummy))
596     {
597       LOG (GNUNET_ERROR_TYPE_DEBUG,
598            "Got numeric IP for external address, not repeating lookup\n");
599       return;                   /* repated lookup pointless: was numeric! */
600     }
601     h->dns_task =
602       GNUNET_SCHEDULER_add_delayed (h->dyndns_frequency,
603                                     &resolve_dns, h);
604     return;
605   }
606   LOG (GNUNET_ERROR_TYPE_DEBUG,
607        "Got IP `%s' for external address `%s'\n",
608        GNUNET_a2s (addr, addrlen),
609        h->external_address);
610   add_to_address_list (h, LAL_EXTERNAL_IP, addr, addrlen);
611 }
612
613
614 /**
615  * Task to do a lookup on our hostname for IP addresses.
616  *
617  * @param cls the NAT handle
618  * @param tc scheduler context
619  */
620 static void
621 resolve_hostname (void *cls,
622                   const struct GNUNET_SCHEDULER_TaskContext *tc);
623
624
625 /**
626  * Function called by the resolver for each address obtained from DNS
627  * for our own hostname.  Add the addresses to the list of our IP
628  * addresses.
629  *
630  * @param cls closure
631  * @param addr one of the addresses of the host, NULL for the last address
632  * @param addrlen length of the @a addr
633  */
634 static void
635 process_hostname_ip (void *cls,
636                      const struct sockaddr *addr,
637                      socklen_t addrlen)
638 {
639   struct GNUNET_NAT_Handle *h = cls;
640
641   if (NULL == addr)
642   {
643     h->hostname_dns = NULL;
644     h->hostname_task =
645         GNUNET_SCHEDULER_add_delayed (h->hostname_dns_frequency,
646                                       &resolve_hostname, h);
647     return;
648   }
649   add_to_address_list (h, LAL_HOSTNAME_DNS, addr, addrlen);
650 }
651
652
653 /**
654  * Add the IP of our network interface to the list of
655  * our IP addresses.
656  *
657  * @param cls the `struct GNUNET_NAT_Handle`
658  * @param name name of the interface
659  * @param isDefault do we think this may be our default interface
660  * @param addr address of the interface
661  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
662  * @param netmask the network mask (can be NULL for unknown or unassigned))
663  * @param addrlen number of bytes in @a addr and @a broadcast_addr
664  * @return #GNUNET_OK to continue iterating
665  */
666 static int
667 process_interfaces (void *cls,
668                     const char *name,
669                     int isDefault,
670                     const struct sockaddr *addr,
671                     const struct sockaddr *broadcast_addr,
672                     const struct sockaddr *netmask,
673                     socklen_t addrlen)
674 {
675   const static struct in6_addr any6 = IN6ADDR_ANY_INIT;
676   struct GNUNET_NAT_Handle *h = cls;
677   const struct sockaddr_in *s4;
678   const struct sockaddr_in6 *s6;
679   const void *ip;
680   char buf[INET6_ADDRSTRLEN];
681   unsigned int i;
682   int have_any;
683   char *tun_if;
684
685   /* skip virtual interfaces created by GNUnet-vpn */
686   if (GNUNET_OK ==
687       GNUNET_CONFIGURATION_get_value_string (h->cfg,
688                                              "vpn",
689                                              "IFNAME",
690                                              &tun_if))
691   {
692     if (0 == strcmp (name,
693                      tun_if))
694     {
695       GNUNET_free (tun_if);
696       return GNUNET_OK;
697     }
698   }
699   /* skip virtual interfaces created by GNUnet-dns */
700   if (GNUNET_OK ==
701       GNUNET_CONFIGURATION_get_value_string (h->cfg,
702                                              "dns",
703                                              "IFNAME",
704                                              &tun_if))
705   {
706     if (0 == strcmp (name,
707                      tun_if))
708     {
709       GNUNET_free (tun_if);
710       return GNUNET_OK;
711     }
712   }
713   /* skip virtual interfaces created by GNUnet-exit */
714   if (GNUNET_OK ==
715       GNUNET_CONFIGURATION_get_value_string (h->cfg,
716                                              "exit",
717                                              "EXIT_IFNAME",
718                                              &tun_if))
719   {
720     if (0 == strcmp (name,
721                      tun_if))
722     {
723       GNUNET_free (tun_if);
724       return GNUNET_OK;
725     }
726   }
727
728
729   switch (addr->sa_family)
730   {
731   case AF_INET:
732     /* check if we're bound to the "ANY" IP address */
733     have_any = GNUNET_NO;
734     for (i=0;i<h->num_local_addrs;i++)
735       {
736         if (h->local_addrs[i]->sa_family != AF_INET)
737           continue;
738 #ifndef INADDR_ANY
739 #define INADDR_ANY 0
740 #endif
741         if (INADDR_ANY == ((struct sockaddr_in*) h->local_addrs[i])->sin_addr.s_addr)
742           {
743             have_any = GNUNET_YES;
744             break;
745           }
746       }
747     if (GNUNET_NO == have_any)
748       return GNUNET_OK; /* not bound to IP 0.0.0.0 but to specific IP addresses,
749                            do not use those from interfaces */
750     s4 = (struct sockaddr_in *) addr;
751     ip = &s4->sin_addr;
752
753     /* Check if address is in 127.0.0.0/8 */
754     uint32_t address = ntohl ((uint32_t) (s4->sin_addr.s_addr));
755     uint32_t value = (address & 0xFF000000) ^ 0x7F000000;
756
757     if ((h->return_localaddress == GNUNET_NO) && (value == 0))
758     {
759       return GNUNET_OK;
760     }
761     if ((GNUNET_YES == h->use_localaddresses) || (value != 0))
762     {
763       add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s4->sin_addr,
764                               sizeof (struct in_addr));
765     }
766     break;
767   case AF_INET6:
768     /* check if we're bound to the "ANY" IP address */
769     have_any = GNUNET_NO;
770     for (i=0;i<h->num_local_addrs;i++)
771       {
772         if (h->local_addrs[i]->sa_family != AF_INET6)
773           continue;
774         if (0 == memcmp (&any6,
775                          &((struct sockaddr_in6*) h->local_addrs[i])->sin6_addr,
776                          sizeof (struct in6_addr)))
777           {
778             have_any = GNUNET_YES;
779             break;
780           }
781       }
782     if (GNUNET_NO == have_any)
783       return GNUNET_OK; /* not bound to "ANY" IP (::0) but to specific IP addresses,
784                            do not use those from interfaces */
785
786     s6 = (struct sockaddr_in6 *) addr;
787     if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
788     {
789       /* skip link local addresses */
790       return GNUNET_OK;
791     }
792     if ((h->return_localaddress == GNUNET_NO) &&
793         (IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *) addr)->sin6_addr)))
794     {
795       return GNUNET_OK;
796     }
797     ip = &s6->sin6_addr;
798     if (GNUNET_YES == h->use_localaddresses)
799     {
800       add_ip_to_address_list (h, LAL_INTERFACE_ADDRESS, &s6->sin6_addr,
801                               sizeof (struct in6_addr));
802     }
803     break;
804   default:
805     GNUNET_break (0);
806     return GNUNET_OK;
807   }
808   if ((h->internal_address == NULL) && (h->server_proc == NULL) &&
809       (h->server_read_task == NULL) &&
810       (GNUNET_YES == isDefault) && ((addr->sa_family == AF_INET) ||
811                                     (addr->sa_family == AF_INET6)))
812   {
813     /* no internal address configured, but we found a "default"
814      * interface, try using that as our 'internal' address */
815     h->internal_address =
816         GNUNET_strdup (inet_ntop (addr->sa_family, ip, buf, sizeof (buf)));
817     start_gnunet_nat_server (h);
818   }
819   return GNUNET_OK;
820 }
821
822
823 /**
824  * Task that restarts the gnunet-helper-nat-server process after a crash
825  * after a certain delay.
826  *
827  * @param cls the `struct GNUNET_NAT_Handle`
828  * @param tc scheduler context
829  */
830 static void
831 restart_nat_server (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
832 {
833   struct GNUNET_NAT_Handle *h = cls;
834
835   h->server_read_task = NULL;
836   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
837     return;
838   start_gnunet_nat_server (h);
839 }
840
841
842 /**
843  * We have been notified that gnunet-helper-nat-server has written
844  * something to stdout.  Handle the output, then reschedule this
845  * function to be called again once more is available.
846  *
847  * @param cls the NAT handle
848  * @param tc the scheduling context
849  */
850 static void
851 nat_server_read (void *cls,
852                  const struct GNUNET_SCHEDULER_TaskContext *tc)
853 {
854   struct GNUNET_NAT_Handle *h = cls;
855   char mybuf[40];
856   ssize_t bytes;
857   size_t i;
858   int port;
859   const char *port_start;
860   struct sockaddr_in sin_addr;
861
862   h->server_read_task = NULL;
863   if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
864     return;
865   memset (mybuf, 0, sizeof (mybuf));
866   bytes =
867     GNUNET_DISK_file_read (h->server_stdout_handle, mybuf, sizeof (mybuf));
868   if (bytes < 1)
869   {
870     LOG (GNUNET_ERROR_TYPE_DEBUG,
871          "Finished reading from server stdout with code: %d\n",
872          bytes);
873     if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG))
874       GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill");
875     GNUNET_OS_process_wait (h->server_proc);
876     GNUNET_OS_process_destroy (h->server_proc);
877     h->server_proc = NULL;
878     GNUNET_DISK_pipe_close (h->server_stdout);
879     h->server_stdout = NULL;
880     h->server_stdout_handle = NULL;
881     /* now try to restart it */
882     h->server_retry_delay = GNUNET_TIME_STD_BACKOFF (h->server_retry_delay);
883     h->server_read_task =
884         GNUNET_SCHEDULER_add_delayed (h->server_retry_delay,
885                                       &restart_nat_server, h);
886     return;
887   }
888
889   port_start = NULL;
890   for (i = 0; i < sizeof (mybuf); i++)
891   {
892     if (mybuf[i] == '\n')
893     {
894       mybuf[i] = '\0';
895       break;
896     }
897     if ((mybuf[i] == ':') && (i + 1 < sizeof (mybuf)))
898     {
899       mybuf[i] = '\0';
900       port_start = &mybuf[i + 1];
901     }
902   }
903
904   /* construct socket address of sender */
905   memset (&sin_addr, 0, sizeof (sin_addr));
906   sin_addr.sin_family = AF_INET;
907 #if HAVE_SOCKADDR_IN_SIN_LEN
908   sin_addr.sin_len = sizeof (sin_addr);
909 #endif
910   if ((NULL == port_start) || (1 != SSCANF (port_start, "%d", &port)) ||
911       (-1 == inet_pton (AF_INET, mybuf, &sin_addr.sin_addr)))
912   {
913     /* should we restart gnunet-helper-nat-server? */
914     LOG (GNUNET_ERROR_TYPE_WARNING, "nat",
915          _("gnunet-helper-nat-server generated malformed address `%s'\n"),
916          mybuf);
917     h->server_read_task =
918         GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
919                                         h->server_stdout_handle,
920                                         &nat_server_read, h);
921     return;
922   }
923   sin_addr.sin_port = htons ((uint16_t) port);
924   LOG (GNUNET_ERROR_TYPE_DEBUG, "gnunet-helper-nat-server read: %s:%d\n", mybuf,
925        port);
926   h->reversal_callback (h->callback_cls, (const struct sockaddr *) &sin_addr,
927                         sizeof (sin_addr));
928   h->server_read_task =
929       GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
930                                       h->server_stdout_handle, &nat_server_read,
931                                       h);
932 }
933
934
935 /**
936  * Try to start the gnunet-helper-nat-server (if it is not
937  * already running).
938  *
939  * @param h handle to NAT
940  */
941 static void
942 start_gnunet_nat_server (struct GNUNET_NAT_Handle *h)
943 {
944   char *binary;
945
946   if ((h->behind_nat == GNUNET_YES) && (h->enable_nat_server == GNUNET_YES) &&
947       (h->internal_address != NULL) &&
948       (NULL !=
949        (h->server_stdout =
950         GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES))))
951   {
952     LOG (GNUNET_ERROR_TYPE_DEBUG,
953          "Starting `%s' at `%s'\n",
954          "gnunet-helper-nat-server", h->internal_address);
955     /* Start the server process */
956     binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
957     h->server_proc =
958         GNUNET_OS_start_process (GNUNET_NO, 0, NULL, h->server_stdout, NULL,
959                                  binary,
960                                  "gnunet-helper-nat-server",
961                                  h->internal_address, NULL);
962     GNUNET_free (binary);
963     if (h->server_proc == NULL)
964     {
965       LOG (GNUNET_ERROR_TYPE_WARNING, "nat", _("Failed to start %s\n"),
966            "gnunet-helper-nat-server");
967       GNUNET_DISK_pipe_close (h->server_stdout);
968       h->server_stdout = NULL;
969     }
970     else
971     {
972       /* Close the write end of the read pipe */
973       GNUNET_DISK_pipe_close_end (h->server_stdout, GNUNET_DISK_PIPE_END_WRITE);
974       h->server_stdout_handle =
975           GNUNET_DISK_pipe_handle (h->server_stdout, GNUNET_DISK_PIPE_END_READ);
976       h->server_read_task =
977           GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
978                                           h->server_stdout_handle,
979                                           &nat_server_read, h);
980     }
981   }
982 }
983
984
985 /**
986  * Task to scan the local network interfaces for IP addresses.
987  *
988  * @param cls the NAT handle
989  * @param tc scheduler context
990  */
991 static void
992 list_interfaces (void *cls,
993                  const struct GNUNET_SCHEDULER_TaskContext *tc)
994 {
995   struct GNUNET_NAT_Handle *h = cls;
996
997   h->ifc_task = NULL;
998   remove_from_address_list_by_source (h, LAL_INTERFACE_ADDRESS);
999   GNUNET_OS_network_interfaces_list (&process_interfaces, h);
1000   h->ifc_task =
1001     GNUNET_SCHEDULER_add_delayed (h->ifc_scan_frequency,
1002                                   &list_interfaces, h);
1003 }
1004
1005
1006 /**
1007  * Task to do a lookup on our hostname for IP addresses.
1008  *
1009  * @param cls the NAT handle
1010  * @param tc scheduler context
1011  */
1012 static void
1013 resolve_hostname (void *cls,
1014                   const struct GNUNET_SCHEDULER_TaskContext *tc)
1015 {
1016   struct GNUNET_NAT_Handle *h = cls;
1017
1018   h->hostname_task = NULL;
1019   remove_from_address_list_by_source (h, LAL_HOSTNAME_DNS);
1020   h->hostname_dns =
1021       GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, HOSTNAME_RESOLVE_TIMEOUT,
1022                                         &process_hostname_ip, h);
1023 }
1024
1025
1026 /**
1027  * Task to do DNS lookup on our external hostname to
1028  * get DynDNS-IP addresses.
1029  *
1030  * @param cls the NAT handle
1031  * @param tc scheduler context
1032  */
1033 static void
1034 resolve_dns (void *cls,
1035              const struct GNUNET_SCHEDULER_TaskContext *tc)
1036 {
1037   struct GNUNET_NAT_Handle *h = cls;
1038   struct LocalAddressList *pos;
1039
1040   h->dns_task = NULL;
1041   for (pos = h->lal_head; NULL != pos; pos = pos->next)
1042     if (pos->source == LAL_EXTERNAL_IP)
1043       pos->source = LAL_EXTERNAL_IP_OLD;
1044   LOG (GNUNET_ERROR_TYPE_DEBUG,
1045        "Resolving external address `%s'\n",
1046        h->external_address);
1047   h->ext_dns =
1048       GNUNET_RESOLVER_ip_get (h->external_address, AF_INET,
1049                               GNUNET_TIME_UNIT_MINUTES,
1050                               &process_external_ip, h);
1051 }
1052
1053
1054 /**
1055  * Add or remove UPnP-mapped addresses.
1056  *
1057  * @param cls the `struct GNUNET_NAT_Handle`
1058  * @param add_remove #GNUNET_YES to mean the new public IP address, #GNUNET_NO to mean
1059  *     the previous (now invalid) one
1060  * @param addr either the previous or the new public IP address
1061  * @param addrlen actual lenght of @a addr
1062  * @param ret GNUNET_NAT_ERROR_SUCCESS on success, otherwise an error code
1063  */
1064 static void
1065 upnp_add (void *cls,
1066           int add_remove,
1067           const struct sockaddr *addr,
1068           socklen_t addrlen,
1069           enum GNUNET_NAT_StatusCode ret)
1070 {
1071   struct GNUNET_NAT_Handle *h = cls;
1072   struct LocalAddressList *pos;
1073   struct LocalAddressList *next;
1074
1075
1076   if (GNUNET_NAT_ERROR_SUCCESS != ret)
1077   {
1078     /* Error while running upnp client */
1079     LOG (GNUNET_ERROR_TYPE_ERROR,
1080           _("Error while running upnp client:\n"));
1081
1082     //FIXME: convert error code to string
1083
1084     return;
1085   }
1086
1087   if (GNUNET_YES == add_remove)
1088   {
1089     add_to_address_list (h, LAL_UPNP, addr, addrlen);
1090     return;
1091   }
1092   else if (GNUNET_NO == add_remove)
1093   {
1094     /* remove address */
1095     next = h->lal_head;
1096     while (NULL != (pos = next))
1097     {
1098       next = pos->next;
1099       if ((pos->source != LAL_UPNP) || (pos->addrlen != addrlen) ||
1100           (0 != memcmp (&pos[1], addr, addrlen)))
1101         continue;
1102       GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, pos);
1103       if (NULL != h->address_callback)
1104         h->address_callback (h->callback_cls, GNUNET_NO,
1105                              (const struct sockaddr *) &pos[1], pos->addrlen);
1106       GNUNET_free (pos);
1107       return;                     /* only remove once */
1108     }
1109     /* asked to remove address that does not exist */
1110     LOG (GNUNET_ERROR_TYPE_ERROR,
1111          "Asked to remove unkown address `%s'\n",
1112          GNUNET_a2s(addr, addrlen));
1113     GNUNET_break (0);
1114   }
1115   else
1116   {
1117
1118     GNUNET_break (0);
1119   }
1120 }
1121
1122
1123 /**
1124  * Try to add a port mapping using UPnP.
1125  *
1126  * @param h overall NAT handle
1127  * @param port port to map with UPnP
1128  */
1129 static void
1130 add_minis (struct GNUNET_NAT_Handle *h,
1131            uint16_t port)
1132 {
1133   struct MiniList *ml;
1134
1135   ml = h->mini_head;
1136   while (NULL != ml)
1137   {
1138     if (port == ml->port)
1139       return;                   /* already got this port */
1140     ml = ml->next;
1141   }
1142
1143   ml = GNUNET_new (struct MiniList);
1144   ml->port = port;
1145   ml->mini = GNUNET_NAT_mini_map_start (port, h->is_tcp, &upnp_add, h);
1146
1147   if (NULL == ml->mini)
1148   {
1149     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1150         _("Failed to run upnp client for port %u\n"), ml->port);
1151     GNUNET_free (ml);
1152     return;
1153   }
1154
1155   GNUNET_CONTAINER_DLL_insert (h->mini_head, h->mini_tail, ml);
1156 }
1157
1158
1159 /**
1160  * Task to add addresses from original bind to set of valid addrs.
1161  *
1162  * @param h the NAT handle
1163  */
1164 static void
1165 add_from_bind (struct GNUNET_NAT_Handle *h)
1166 {
1167   static struct in6_addr any = IN6ADDR_ANY_INIT;
1168
1169   unsigned int i;
1170   struct sockaddr *sa;
1171   const struct sockaddr_in *v4;
1172
1173   for (i = 0; i < h->num_local_addrs; i++)
1174   {
1175     sa = h->local_addrs[i];
1176     switch (sa->sa_family)
1177     {
1178     case AF_INET:
1179       if (sizeof (struct sockaddr_in) != h->local_addrlens[i])
1180       {
1181         GNUNET_break (0);
1182         break;
1183       }
1184       v4 = (const struct sockaddr_in *) sa;
1185       if (0 != v4->sin_addr.s_addr)
1186         add_to_address_list (h,
1187                              LAL_BINDTO_ADDRESS, sa,
1188                              sizeof (struct sockaddr_in));
1189       if (h->enable_upnp)
1190       {
1191         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1192                     "Running upnp client for address `%s'\n",
1193                     GNUNET_a2s (sa,sizeof (struct sockaddr_in)));
1194         add_minis (h, ntohs (v4->sin_port));
1195       }
1196       break;
1197     case AF_INET6:
1198       if (sizeof (struct sockaddr_in6) != h->local_addrlens[i])
1199       {
1200         GNUNET_break (0);
1201         break;
1202       }
1203       if (0 !=
1204           memcmp (&((const struct sockaddr_in6 *) sa)->sin6_addr,
1205                   &any,
1206                   sizeof (struct in6_addr)))
1207         add_to_address_list (h,
1208                              LAL_BINDTO_ADDRESS,
1209                              sa,
1210                              sizeof (struct sockaddr_in6));
1211       break;
1212     default:
1213       break;
1214     }
1215   }
1216 }
1217
1218
1219 /**
1220  * Attempt to enable port redirection and detect public IP address contacting
1221  * UPnP or NAT-PMP routers on the local network. Use addr to specify to which
1222  * of the local host's addresses should the external port be mapped. The port
1223  * is taken from the corresponding sockaddr_in[6] field.
1224  *
1225  * @param cfg configuration to use
1226  * @param is_tcp #GNUNET_YES for TCP, #GNUNET_NO for UDP
1227  * @param adv_port advertised port (port we are either bound to or that our OS
1228  *                 locally performs redirection from to our bound port).
1229  * @param num_addrs number of addresses in @a addrs
1230  * @param addrs the local addresses packets should be redirected to
1231  * @param addrlens actual lengths of the addresses
1232  * @param address_callback function to call everytime the public IP address changes
1233  * @param reversal_callback function to call if someone wants connection reversal from us
1234  * @param callback_cls closure for callbacks
1235  * @return NULL on error, otherwise handle that can be used to unregister
1236  */
1237 struct GNUNET_NAT_Handle *
1238 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
1239                      int is_tcp,
1240                      uint16_t adv_port,
1241                      unsigned int num_addrs,
1242                      const struct sockaddr **addrs,
1243                      const socklen_t *addrlens,
1244                      GNUNET_NAT_AddressCallback address_callback,
1245                      GNUNET_NAT_ReversalCallback reversal_callback,
1246                      void *callback_cls)
1247 {
1248   struct GNUNET_NAT_Handle *h;
1249   struct in_addr in_addr;
1250   unsigned int i;
1251   char *binary;
1252
1253   LOG (GNUNET_ERROR_TYPE_DEBUG,
1254        "Registered with NAT service at port %u with %u IP bound local addresses\n",
1255        (unsigned int) adv_port, num_addrs);
1256   h = GNUNET_new (struct GNUNET_NAT_Handle);
1257   h->server_retry_delay = GNUNET_TIME_UNIT_SECONDS;
1258   h->cfg = cfg;
1259   h->is_tcp = is_tcp;
1260   h->address_callback = address_callback;
1261   h->reversal_callback = reversal_callback;
1262   h->callback_cls = callback_cls;
1263   h->num_local_addrs = num_addrs;
1264   h->adv_port = adv_port;
1265   if (num_addrs != 0)
1266   {
1267     h->local_addrs = GNUNET_malloc (num_addrs * sizeof (struct sockaddr *));
1268     h->local_addrlens = GNUNET_malloc (num_addrs * sizeof (socklen_t));
1269     for (i = 0; i < num_addrs; i++)
1270     {
1271       GNUNET_assert (addrlens[i] > 0);
1272       GNUNET_assert (addrs[i] != NULL);
1273       h->local_addrlens[i] = addrlens[i];
1274       h->local_addrs[i] = GNUNET_malloc (addrlens[i]);
1275       memcpy (h->local_addrs[i], addrs[i], addrlens[i]);
1276     }
1277   }
1278   if (GNUNET_OK ==
1279       GNUNET_CONFIGURATION_have_value (cfg, "nat", "INTERNAL_ADDRESS"))
1280   {
1281     (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat",
1282                                                   "INTERNAL_ADDRESS",
1283                                                   &h->internal_address);
1284   }
1285   if ((h->internal_address != NULL) &&
1286       (inet_pton (AF_INET, h->internal_address, &in_addr) != 1))
1287   {
1288     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
1289                                "nat", "INTERNAL_ADDRESS",
1290                                _("malformed"));
1291     GNUNET_free (h->internal_address);
1292     h->internal_address = NULL;
1293   }
1294
1295   if (GNUNET_OK ==
1296       GNUNET_CONFIGURATION_have_value (cfg, "nat", "EXTERNAL_ADDRESS"))
1297   {
1298     (void) GNUNET_CONFIGURATION_get_value_string (cfg, "nat",
1299                                                   "EXTERNAL_ADDRESS",
1300                                                   &h->external_address);
1301   }
1302   h->behind_nat =
1303       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "BEHIND_NAT");
1304   h->nat_punched =
1305       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "PUNCHED_NAT");
1306   h->enable_nat_client =
1307       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_CLIENT");
1308   h->enable_nat_server =
1309       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_ICMP_SERVER");
1310   h->enable_upnp =
1311       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "ENABLE_UPNP");
1312   h->use_localaddresses =
1313       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_LOCALADDR");
1314   h->return_localaddress =
1315       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat",
1316                                             "RETURN_LOCAL_ADDRESSES");
1317
1318   h->use_hostname =
1319       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "USE_HOSTNAME");
1320   h->disable_ipv6 =
1321       GNUNET_CONFIGURATION_get_value_yesno (cfg, "nat", "DISABLEV6");
1322   if (GNUNET_OK !=
1323       GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "DYNDNS_FREQUENCY",
1324                                            &h->dyndns_frequency))
1325     h->dyndns_frequency = DYNDNS_FREQUENCY;
1326   if (GNUNET_OK !=
1327       GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "IFC_SCAN_FREQUENCY",
1328                                            &h->ifc_scan_frequency))
1329     h->ifc_scan_frequency = IFC_SCAN_FREQUENCY;
1330   if (GNUNET_OK !=
1331       GNUNET_CONFIGURATION_get_value_time (cfg, "nat", "HOSTNAME_DNS_FREQUENCY",
1332                                            &h->hostname_dns_frequency))
1333     h->hostname_dns_frequency = HOSTNAME_DNS_FREQUENCY;
1334
1335   if (NULL == reversal_callback)
1336     h->enable_nat_server = GNUNET_NO;
1337
1338   /* Check for UPnP client, disable immediately if not available */
1339   if ( (GNUNET_YES == h->enable_upnp) &&
1340        (GNUNET_SYSERR ==
1341         GNUNET_OS_check_helper_binary ("upnpc", GNUNET_NO, NULL)) )
1342   {
1343     LOG (GNUNET_ERROR_TYPE_ERROR,
1344         _("UPnP enabled in configuration, but UPnP client `upnpc` command not found, disabling UPnP \n"));
1345     h->enable_upnp = GNUNET_NO;
1346   }
1347
1348   /* Check if NAT was hole-punched */
1349   if ((NULL != h->address_callback) &&
1350       (NULL != h->external_address) &&
1351       (GNUNET_YES == h->nat_punched))
1352   {
1353     h->dns_task = GNUNET_SCHEDULER_add_now (&resolve_dns, h);
1354     h->enable_nat_server = GNUNET_NO;
1355     h->enable_upnp = GNUNET_NO;
1356   }
1357   else
1358   {
1359     LOG (GNUNET_ERROR_TYPE_DEBUG,
1360          "No external IP address given to add to our list of addresses\n");
1361   }
1362
1363   /* Test for SUID binaries */
1364   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-server");
1365   if ((h->behind_nat == GNUNET_YES) && (GNUNET_YES == h->enable_nat_server) &&
1366       (GNUNET_YES !=
1367        GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d 127.0.0.1" ))) // use localhost as source for that one udp-port, ok for testing
1368   {
1369     h->enable_nat_server = GNUNET_NO;
1370     LOG (GNUNET_ERROR_TYPE_WARNING,
1371          _("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
1372          "gnunet-helper-nat-server");
1373   }
1374   GNUNET_free (binary);
1375   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
1376   if ((GNUNET_YES == h->enable_nat_client) &&
1377       (GNUNET_YES !=
1378        GNUNET_OS_check_helper_binary (binary, GNUNET_YES, "-d 127.0.0.1 127.0.0.2 42"))) // none of these parameters are actually used in privilege testing mode
1379   {
1380     h->enable_nat_client = GNUNET_NO;
1381     LOG (GNUNET_ERROR_TYPE_WARNING,
1382          _
1383          ("Configuration requires `%s', but binary is not installed properly (SUID bit not set).  Option disabled.\n"),
1384          "gnunet-helper-nat-client");
1385   }
1386   GNUNET_free (binary);
1387   start_gnunet_nat_server (h);
1388
1389   /* FIXME: add support for UPnP, etc */
1390
1391   if (NULL != h->address_callback)
1392   {
1393     h->ifc_task = GNUNET_SCHEDULER_add_now (&list_interfaces,
1394                                             h);
1395     if (GNUNET_YES == h->use_hostname)
1396       h->hostname_task = GNUNET_SCHEDULER_add_now (&resolve_hostname,
1397                                                    h);
1398   }
1399   add_from_bind (h);
1400
1401   return h;
1402 }
1403
1404
1405 /**
1406  * Stop port redirection and public IP address detection for the given handle.
1407  * This frees the handle, after having sent the needed commands to close open ports.
1408  *
1409  * @param h the handle to stop
1410  */
1411 void
1412 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *h)
1413 {
1414   unsigned int i;
1415   struct LocalAddressList *lal;
1416   struct MiniList *ml;
1417
1418   LOG (GNUNET_ERROR_TYPE_DEBUG,
1419        "NAT unregister called\n");
1420   while (NULL != (ml = h->mini_head))
1421   {
1422     GNUNET_CONTAINER_DLL_remove (h->mini_head,
1423                                  h->mini_tail,
1424                                  ml);
1425     if (NULL != ml->mini)
1426       GNUNET_NAT_mini_map_stop (ml->mini);
1427     GNUNET_free (ml);
1428   }
1429   if (NULL != h->ext_dns)
1430   {
1431     GNUNET_RESOLVER_request_cancel (h->ext_dns);
1432     h->ext_dns = NULL;
1433   }
1434   if (NULL != h->hostname_dns)
1435   {
1436     GNUNET_RESOLVER_request_cancel (h->hostname_dns);
1437     h->hostname_dns = NULL;
1438   }
1439   if (NULL != h->server_read_task)
1440   {
1441     GNUNET_SCHEDULER_cancel (h->server_read_task);
1442     h->server_read_task = NULL;
1443   }
1444   if (NULL != h->ifc_task)
1445   {
1446     GNUNET_SCHEDULER_cancel (h->ifc_task);
1447     h->ifc_task = NULL;
1448   }
1449   if (NULL != h->hostname_task)
1450   {
1451     GNUNET_SCHEDULER_cancel (h->hostname_task);
1452     h->hostname_task = NULL;
1453   }
1454   if (NULL != h->dns_task)
1455   {
1456     GNUNET_SCHEDULER_cancel (h->dns_task);
1457     h->dns_task = NULL;
1458   }
1459   if (NULL != h->server_proc)
1460   {
1461     if (0 != GNUNET_OS_process_kill (h->server_proc, GNUNET_TERM_SIG))
1462       GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING, "nat", "kill");
1463     GNUNET_OS_process_wait (h->server_proc);
1464     GNUNET_OS_process_destroy (h->server_proc);
1465     h->server_proc = NULL;
1466     GNUNET_DISK_pipe_close (h->server_stdout);
1467     h->server_stdout = NULL;
1468     h->server_stdout_handle = NULL;
1469   }
1470   if (NULL != h->server_stdout)
1471   {
1472     GNUNET_DISK_pipe_close (h->server_stdout);
1473     h->server_stdout = NULL;
1474     h->server_stdout_handle = NULL;
1475   }
1476   while (NULL != (lal = h->lal_head))
1477   {
1478     GNUNET_CONTAINER_DLL_remove (h->lal_head, h->lal_tail, lal);
1479     if (NULL != h->address_callback)
1480       h->address_callback (h->callback_cls, GNUNET_NO,
1481                            (const struct sockaddr *) &lal[1], lal->addrlen);
1482     GNUNET_free (lal);
1483   }
1484   for (i = 0; i < h->num_local_addrs; i++)
1485     GNUNET_free (h->local_addrs[i]);
1486   GNUNET_free_non_null (h->local_addrs);
1487   GNUNET_free_non_null (h->local_addrlens);
1488   GNUNET_free_non_null (h->external_address);
1489   GNUNET_free_non_null (h->internal_address);
1490   GNUNET_free (h);
1491 }
1492
1493
1494 /**
1495  * We learned about a peer (possibly behind NAT) so run the
1496  * gnunet-helper-nat-client to send dummy ICMP responses to cause
1497  * that peer to connect to us (connection reversal).
1498  *
1499  * @param h handle (used for configuration)
1500  * @param sa the address of the peer (IPv4-only)
1501  * @return #GNUNET_SYSERR on error, #GNUNET_NO if nat client is disabled,
1502  *         #GNUNET_OK otherwise
1503  */
1504 int
1505 GNUNET_NAT_run_client (struct GNUNET_NAT_Handle *h,
1506                        const struct sockaddr_in *sa)
1507
1508
1509 {
1510   char inet4[INET_ADDRSTRLEN];
1511   char port_as_string[6];
1512   struct GNUNET_OS_Process *proc;
1513   char *binary;
1514
1515   if (GNUNET_YES != h->enable_nat_client)
1516     return GNUNET_NO;                     /* not permitted / possible */
1517
1518   if (h->internal_address == NULL)
1519   {
1520     LOG (GNUNET_ERROR_TYPE_WARNING, "nat",
1521          _("Internal IP address not known, cannot use ICMP NAT traversal method\n"));
1522     return GNUNET_SYSERR;
1523   }
1524   GNUNET_assert (sa->sin_family == AF_INET);
1525   if (NULL == inet_ntop (AF_INET, &sa->sin_addr, inet4, INET_ADDRSTRLEN))
1526   {
1527     GNUNET_log_from_strerror (GNUNET_ERROR_TYPE_WARNING,
1528                               "nat",
1529                               "inet_ntop");
1530     return GNUNET_SYSERR;
1531   }
1532   GNUNET_snprintf (port_as_string,
1533                    sizeof (port_as_string),
1534                    "%d",
1535                    h->adv_port);
1536   LOG (GNUNET_ERROR_TYPE_DEBUG,
1537        _("Running gnunet-helper-nat-client %s %s %u\n"),
1538        h->internal_address,
1539        inet4,
1540        (unsigned int) h->adv_port);
1541   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-nat-client");
1542   proc =
1543       GNUNET_OS_start_process (GNUNET_NO, 0, NULL, NULL, NULL,
1544                                binary,
1545                                "gnunet-helper-nat-client",
1546                                h->internal_address,
1547                                inet4, port_as_string, NULL);
1548   GNUNET_free (binary);
1549   if (NULL == proc)
1550     return GNUNET_SYSERR;
1551   /* we know that the gnunet-helper-nat-client will terminate virtually
1552    * instantly */
1553   GNUNET_OS_process_wait (proc);
1554   GNUNET_OS_process_destroy (proc);
1555   return GNUNET_OK;
1556 }
1557
1558
1559 /**
1560  * Test if the given address is (currently) a plausible IP address for this peer.
1561  *
1562  * @param h the handle returned by register
1563  * @param addr IP address to test (IPv4 or IPv6)
1564  * @param addrlen number of bytes in @a addr
1565  * @return #GNUNET_YES if the address is plausible,
1566  *         #GNUNET_NO if the address is not plausible,
1567  *         #GNUNET_SYSERR if the address is malformed
1568  */
1569 int
1570 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *h,
1571                          const void *addr,
1572                          socklen_t addrlen)
1573 {
1574   struct LocalAddressList *pos;
1575   const struct sockaddr_in *in4;
1576   const struct sockaddr_in6 *in6;
1577
1578   if ((addrlen != sizeof (struct in_addr)) &&
1579       (addrlen != sizeof (struct in6_addr)))
1580   {
1581     GNUNET_break (0);
1582     return GNUNET_SYSERR;
1583   }
1584   for (pos = h->lal_head; NULL != pos; pos = pos->next)
1585   {
1586     if (pos->addrlen == sizeof (struct sockaddr_in))
1587     {
1588       in4 = (struct sockaddr_in *) &pos[1];
1589       if ((addrlen == sizeof (struct in_addr)) &&
1590           (0 == memcmp (&in4->sin_addr, addr, sizeof (struct in_addr))))
1591         return GNUNET_YES;
1592     }
1593     else if (pos->addrlen == sizeof (struct sockaddr_in6))
1594     {
1595       in6 = (struct sockaddr_in6 *) &pos[1];
1596       if ((addrlen == sizeof (struct in6_addr)) &&
1597           (0 == memcmp (&in6->sin6_addr, addr, sizeof (struct in6_addr))))
1598         return GNUNET_YES;
1599     }
1600     else
1601     {
1602       GNUNET_assert (0);
1603     }
1604   }
1605   LOG (GNUNET_ERROR_TYPE_WARNING,
1606        "Asked to validate one of my addresses and validation failed!\n");
1607   return GNUNET_NO;
1608 }
1609
1610 /**
1611  * Converts enum GNUNET_NAT_StatusCode to a string
1612  *
1613  * @param err error code to resolve to a string
1614  * @return pointer to a static string containing the error code
1615  */
1616 const char *
1617 GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
1618 {
1619   switch (err)
1620   {
1621   case GNUNET_NAT_ERROR_SUCCESS:
1622     return _ ("Operation Successful");
1623   case GNUNET_NAT_ERROR_IPC_FAILURE:
1624     return _ ("Internal Failure (IPC, ...)");
1625   case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
1626     return _ ("Failure in network subsystem, check permissions.");
1627   case GNUNET_NAT_ERROR_TIMEOUT:
1628     return _ ("Encountered timeout while performing operation");
1629   case GNUNET_NAT_ERROR_NOT_ONLINE:
1630     return _ ("detected that we are offline");
1631   case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
1632     return _ ("`upnpc` command not found");
1633   case GNUNET_NAT_ERROR_UPNPC_FAILED:
1634     return _ ("Failed to run `upnpc` command");
1635   case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
1636     return _ ("`upnpc' command took too long, process killed");
1637   case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
1638     return _ ("`upnpc' command failed to establish port mapping");
1639   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
1640     return _ ("`external-ip' command not found");
1641   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
1642     return _ ("Failed to run `external-ip` command");
1643   case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
1644     return _ ("`external-ip' command output invalid");
1645   case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
1646     return _ ("no valid address was returned by `external-ip'");
1647   case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
1648     return _ ("Could not determine interface with internal/local network address");
1649   case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
1650     return _ ("No functioning gnunet-helper-nat-server installation found");
1651   case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
1652     return _ ("NAT test could not be initialized");
1653   case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
1654     return _ ("NAT test timeout reached");
1655   case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
1656     return _ ("could not register NAT");
1657   case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
1658     return _ ("No working gnunet-helper-nat-client installation found");
1659 /*  case:
1660     return _ ("");*/
1661   default:
1662     return "unknown status code";
1663   }
1664 }
1665
1666 /* end of nat.c */