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