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