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