- adding return value to mst callback
[oweals/gnunet.git] / src / dns / gnunet-service-dns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 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 dns/gnunet-service-dns.c
23  * @brief service to intercept and modify DNS queries (and replies) of this system
24  * @author Christian Grothoff
25  *
26  * For "secure" interaction with the legacy DNS system, we permit
27  * replies only to arrive within a 5s window (and they must match
28  * ports, IPs and request IDs).  Furthermore, we let the OS pick a
29  * source port, opening up to 128 sockets per address family (IPv4 or
30  * IPv6).  Those sockets are closed if they are not in use for 5s
31  * (which means they will be freshly randomized afterwards).  For new
32  * requests, we pick a random slot in the array with 128 socket slots
33  * (and re-use an existing socket if the slot is still in use).  Thus
34  * each request will be given one of 128 random source ports, and the
35  * 128 random source ports will also change "often" (less often if the
36  * system is very busy, each time if we are mostly idle).  At the same
37  * time, the system will never use more than 256 UDP sockets.  
38  */
39 #include "platform.h"
40 #include "gnunet_util_lib.h"
41 #include "gnunet_applications.h"
42 #include "gnunet_constants.h"
43 #include "gnunet_protocols.h"
44 #include "gnunet_signatures.h"
45 #include "dns.h"
46 #include "gnunet_dns_service.h"
47 #include "gnunet_dnsparser_lib.h"
48 #include "gnunet_mesh_service.h"
49 #include "gnunet_statistics_service.h"
50 #include "gnunet_tun_lib.h"
51
52
53 /**
54  * Timeout for an external (Internet-DNS) DNS resolution
55  */
56 #define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
57
58 /**
59  * How many DNS sockets do we open at most at the same time?
60  * (technical socket maximum is this number x2 for IPv4+IPv6)
61  */
62 #define DNS_SOCKET_MAX 128
63
64 /**
65  * Phases each request goes through.
66  */
67 enum RequestPhase
68 {
69   /**
70    * Request has just been received.
71    */
72   RP_INIT,
73
74   /**
75    * Showing the request to all monitor clients.  If
76    * client list is empty, will enter QUERY phase.
77    */
78   RP_REQUEST_MONITOR,
79
80   /**
81    * Showing the request to PRE-RESOLUTION clients to find an answer.
82    * If client list is empty, will trigger global DNS request.
83    */
84   RP_QUERY,
85
86   /**
87    * Global Internet query is now pending.
88    */
89   RP_INTERNET_DNS,
90   
91   /**
92    * Client (or global DNS request) has resulted in a response.
93    * Forward to all POST-RESOLUTION clients.  If client list is empty,
94    * will enter RESPONSE_MONITOR phase.
95    */
96   RP_MODIFY,
97
98   /**
99    * Showing the request to all monitor clients.  If
100    * client list is empty, give the result to the hijacker (and be done).
101    */
102   RP_RESPONSE_MONITOR,
103
104   /**
105    * Some client has told us to drop the request.
106    */
107   RP_DROP
108 };
109
110
111 /**
112  * Entry we keep for each client.
113  */ 
114 struct ClientRecord
115 {
116   /**
117    * Kept in doubly-linked list.
118    */ 
119   struct ClientRecord *next;
120
121   /**
122    * Kept in doubly-linked list.
123    */ 
124   struct ClientRecord *prev;
125
126   /**
127    * Handle to the client.
128    */ 
129   struct GNUNET_SERVER_Client *client;
130
131   /**
132    * Flags for the client.
133    */
134   enum GNUNET_DNS_Flags flags;
135
136 };
137
138
139 /**
140  * UDP socket we are using for sending DNS requests to the Internet.
141  */
142 struct RequestSocket
143 {
144   
145   /**
146    * UDP socket we use for this request for IPv4
147    */
148   struct GNUNET_NETWORK_Handle *dnsout4;
149
150   /**
151    * UDP socket we use for this request for IPv6
152    */
153   struct GNUNET_NETWORK_Handle *dnsout6;
154
155   /**
156    * Task for reading from dnsout4 and dnsout6.
157    */
158   GNUNET_SCHEDULER_TaskIdentifier read_task;
159
160   /**
161    * When should this socket be closed?
162    */
163   struct GNUNET_TIME_Absolute timeout;
164 };
165
166
167 /**
168  * Entry we keep for each active request.
169  */ 
170 struct RequestRecord
171 {
172
173   /**
174    * List of clients that still need to see this request (each entry
175    * is set to NULL when the client is done).
176    */
177   struct ClientRecord **client_wait_list;
178
179   /**
180    * Payload of the UDP packet (the UDP payload), can be either query
181    * or already the response.
182    */
183   char *payload;
184
185   /**
186    * Socket we are using to transmit this request (must match if we receive
187    * a response).  Must NOT be freed as part of this request record (as it
188    * might be shared with other requests).
189    */
190   struct GNUNET_NETWORK_Handle *dnsout;
191
192   /**
193    * Source address of the original request (for sending response).
194    */
195   struct sockaddr_storage src_addr;
196
197   /**
198    * Destination address of the original request (for potential use as exit).
199    */
200   struct sockaddr_storage dst_addr;
201
202   /**
203    * When should this request time out?
204    */
205   struct GNUNET_TIME_Absolute timeout;
206
207   /**
208    * ID of this request, also basis for hashing.  Lowest 16 bit will
209    * be our message ID when doing a global DNS request and our index
210    * into the 'requests' array.
211    */
212   uint64_t request_id;
213
214   /**
215    * Number of bytes in payload.
216    */ 
217   size_t payload_length;
218
219   /**
220    * Length of the client wait list.
221    */
222   unsigned int client_wait_list_length;
223
224   /**
225    * In which phase this this request?
226    */
227   enum RequestPhase phase;
228
229 };
230
231
232 /**
233  * State we keep for each DNS tunnel that terminates at this node.
234  */
235 struct TunnelState
236 {
237
238   /**
239    * Associated MESH tunnel.
240    */
241   struct GNUNET_MESH_Tunnel *tunnel;
242
243   /**
244    * Active request for sending a reply.
245    */
246   struct GNUNET_MESH_TransmitHandle *th;
247
248   /**
249    * DNS reply ready for transmission.
250    */
251   char *reply;
252
253   /**
254    * Socket we are using to transmit this request (must match if we receive
255    * a response).  Must NOT be freed as part of this request record (as it
256    * might be shared with other requests).
257    */
258   struct GNUNET_NETWORK_Handle *dnsout;
259
260   /**
261    * Address we sent the DNS request to.
262    */
263   struct sockaddr_storage addr;
264
265   /**
266    * When should this request time out?
267    */
268   struct GNUNET_TIME_Absolute timeout;
269
270   /**
271    * Number of bytes in 'addr'.
272    */
273   socklen_t addrlen;
274
275   /**
276    * Number of bytes in 'reply'.
277    */
278   size_t reply_length;
279
280   /**
281    * Original DNS request ID as used by the client.
282    */
283   uint16_t original_id;
284
285   /**
286    * DNS request ID that we used for forwarding.
287    */
288   uint16_t my_id;
289 };
290
291
292 /**
293  * Global return value from 'main'.
294  */
295 static int global_ret;
296
297 /**
298  * The configuration to use
299  */
300 static const struct GNUNET_CONFIGURATION_Handle *cfg;
301
302 /**
303  * Statistics.
304  */
305 static struct GNUNET_STATISTICS_Handle *stats;
306
307 /**
308  * Handle to DNS hijacker helper process ("gnunet-helper-dns").
309  */
310 static struct GNUNET_HELPER_Handle *hijacker;
311
312 /**
313  * Command-line arguments we are giving to the hijacker process.
314  */
315 static char *helper_argv[7];
316
317 /**
318  * Head of DLL of clients we consult.
319  */
320 static struct ClientRecord *clients_head;
321
322 /**
323  * Tail of DLL of clients we consult.
324  */
325 static struct ClientRecord *clients_tail;
326
327 /**
328  * Our notification context.
329  */
330 static struct GNUNET_SERVER_NotificationContext *nc;
331
332 /**
333  * Array of all open requests.
334  */
335 static struct RequestRecord requests[UINT16_MAX + 1];
336
337 /**
338  * Array of all open requests from tunnels.
339  */
340 static struct TunnelState *tunnels[UINT16_MAX + 1];
341
342 /**
343  * Array of all open sockets for DNS requests. 
344  */
345 static struct RequestSocket sockets[DNS_SOCKET_MAX];
346
347 /**
348  * Generator for unique request IDs.
349  */
350 static uint64_t request_id_gen;
351
352 /**
353  * IP address to use for the DNS server if we are a DNS exit service
354  * (for VPN via mesh); otherwise NULL.
355  */
356 static char *dns_exit;
357
358 /**
359  * Handle to the MESH service (for receiving DNS queries), or NULL 
360  * if we are not a DNS exit.
361  */
362 static struct GNUNET_MESH_Handle *mesh;
363
364
365 /**
366  * We're done with a RequestSocket, close it for now.
367  *
368  * @param rs request socket to clean up
369  */
370 static void
371 cleanup_rs (struct RequestSocket *rs)
372 {
373   if (NULL != rs->dnsout4)
374   {
375     GNUNET_NETWORK_socket_close (rs->dnsout4);
376     rs->dnsout4 = NULL;
377   }
378   if (NULL != rs->dnsout6)
379   {
380     GNUNET_NETWORK_socket_close (rs->dnsout6);
381     rs->dnsout6 = NULL;
382   }
383   if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
384   {
385     GNUNET_SCHEDULER_cancel (rs->read_task);
386     rs->read_task = GNUNET_SCHEDULER_NO_TASK;
387   }
388 }
389
390
391 /**
392  * We're done processing a DNS request, free associated memory.
393  *
394  * @param rr request to clean up
395  */
396 static void
397 cleanup_rr (struct RequestRecord *rr)
398 {
399   GNUNET_free_non_null (rr->payload);
400   rr->payload = NULL;
401   rr->payload_length = 0;
402   GNUNET_array_grow (rr->client_wait_list,
403                      rr->client_wait_list_length,
404                      0);
405 }
406
407
408 /**
409  * Task run during shutdown.
410  *
411  * @param cls unused
412  * @param tc unused
413  */
414 static void
415 cleanup_task (void *cls GNUNET_UNUSED,
416               const struct GNUNET_SCHEDULER_TaskContext *tc)
417 {
418   unsigned int i;
419
420   GNUNET_HELPER_stop (hijacker);
421   hijacker = NULL;
422   for (i=0;i<7;i++)
423     GNUNET_free_non_null (helper_argv[i]);
424   for (i=0;i<=UINT16_MAX;i++)
425     cleanup_rr (&requests[i]);
426   GNUNET_SERVER_notification_context_destroy (nc);
427   nc = NULL;
428   if (stats != NULL)
429   {
430     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
431     stats = NULL;
432   }
433   if (NULL != dns_exit)
434   {
435     GNUNET_free (dns_exit);
436     dns_exit = NULL;
437   }
438   if (NULL != mesh)
439   {
440     GNUNET_MESH_disconnect(mesh);
441     mesh = NULL;
442   }
443 }
444
445
446 /**
447  * Open source port for sending DNS requests
448  *
449  * @param af AF_INET or AF_INET6
450  * @return GNUNET_OK on success
451  */ 
452 static struct GNUNET_NETWORK_Handle *
453 open_socket (int af)
454 {
455   struct sockaddr_in a4;
456   struct sockaddr_in6 a6;
457   struct sockaddr *sa;
458   socklen_t alen;
459   struct GNUNET_NETWORK_Handle *ret;
460
461   ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
462   if (NULL == ret)
463     return NULL;
464   switch (af)
465   {
466   case AF_INET:
467     memset (&a4, 0, alen = sizeof (struct sockaddr_in));
468     sa = (struct sockaddr *) &a4;
469     break;
470   case AF_INET6:
471     memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
472     sa = (struct sockaddr *) &a6;
473     break;
474   default:
475     GNUNET_break (0);
476     GNUNET_NETWORK_socket_close (ret);
477     return NULL;
478   }
479   sa->sa_family = af;
480   if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
481                                                sa, 
482                                                alen))
483   {
484     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
485                 _("Could not bind to any port: %s\n"),
486                 STRERROR (errno));
487     GNUNET_NETWORK_socket_close (ret);
488     return NULL;
489   }
490   return ret;
491 }
492
493
494 /**
495  * We're done with some request, finish processing.
496  *
497  * @param rr request send to the network or just clean up.
498  */
499 static void
500 request_done (struct RequestRecord *rr)
501 {
502   struct GNUNET_MessageHeader *hdr;
503   size_t reply_len;
504   uint16_t source_port;
505   uint16_t destination_port;
506
507   GNUNET_array_grow (rr->client_wait_list,
508                      rr->client_wait_list_length,
509                      0); 
510   if (RP_RESPONSE_MONITOR != rr->phase)
511   {
512     /* no response, drop */
513     cleanup_rr (rr);
514     return;
515   }
516   
517   /* send response via hijacker */
518   reply_len = sizeof (struct GNUNET_MessageHeader);
519   reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
520   switch (rr->src_addr.ss_family)
521   {
522   case AF_INET:
523     reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
524     break;
525   case AF_INET6:
526     reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
527     break;
528   default:
529     GNUNET_break (0);
530     cleanup_rr (rr);
531     return;   
532   }
533   reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
534   reply_len += rr->payload_length;
535   if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
536   {
537     /* response too big, drop */
538     GNUNET_break (0); /* how can this be? */
539     cleanup_rr(rr);
540     return;    
541   }
542   {
543     char buf[reply_len] GNUNET_ALIGN;
544     size_t off;
545     struct GNUNET_TUN_IPv4Header ip4;
546     struct GNUNET_TUN_IPv6Header ip6;
547
548     /* first, GNUnet message header */
549     hdr = (struct GNUNET_MessageHeader*) buf;
550     hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
551     hdr->size = htons ((uint16_t) reply_len);
552     off = sizeof (struct GNUNET_MessageHeader);
553
554     /* first, TUN header */
555     {
556       struct GNUNET_TUN_Layer2PacketHeader tun;
557
558       tun.flags = htons (0);
559       if (rr->src_addr.ss_family == AF_INET)
560         tun.proto = htons (ETH_P_IPV4); 
561       else
562         tun.proto = htons (ETH_P_IPV6);
563       memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
564       off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
565     }
566
567     /* now IP header */
568     switch (rr->src_addr.ss_family)
569     {
570     case AF_INET:
571       {
572         struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
573         struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
574         
575         source_port = dst->sin_port;
576         destination_port = src->sin_port;
577         GNUNET_TUN_initialize_ipv4_header (&ip4,
578                                            IPPROTO_UDP,
579                                            reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
580                                            &dst->sin_addr,
581                                            &src->sin_addr);
582         memcpy (&buf[off], &ip4, sizeof (ip4));
583         off += sizeof (ip4);
584       }
585       break;
586     case AF_INET6:
587       {
588         struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
589         struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
590
591         source_port = dst->sin6_port;
592         destination_port = src->sin6_port;
593         GNUNET_TUN_initialize_ipv6_header (&ip6,
594                                            IPPROTO_UDP,
595                                            reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
596                                            &dst->sin6_addr,
597                                            &src->sin6_addr);
598         memcpy (&buf[off], &ip6, sizeof (ip6));
599         off += sizeof (ip6);
600       }
601       break;
602     default:
603       GNUNET_assert (0);
604     }
605
606     /* now UDP header */
607     {
608       struct GNUNET_TUN_UdpHeader udp;
609
610       udp.source_port = source_port;
611       udp.destination_port = destination_port;
612       udp.len = htons (reply_len - off);
613       if (AF_INET == rr->src_addr.ss_family)
614         GNUNET_TUN_calculate_udp4_checksum (&ip4,
615                                             &udp,
616                                             rr->payload,
617                                             rr->payload_length);
618       else
619         GNUNET_TUN_calculate_udp6_checksum (&ip6,
620                                             &udp,
621                                             rr->payload,
622                                             rr->payload_length);
623       memcpy (&buf[off], &udp, sizeof (udp));
624       off += sizeof (udp);
625     }
626
627     /* now DNS payload */
628     {
629       memcpy (&buf[off], rr->payload, rr->payload_length);
630       off += rr->payload_length;
631     }
632     /* final checks & sending */
633     GNUNET_assert (off == reply_len);
634     (void) GNUNET_HELPER_send (hijacker,
635                                hdr,
636                                GNUNET_YES,
637                                NULL, NULL);
638     GNUNET_STATISTICS_update (stats,
639                               gettext_noop ("# DNS requests answered via TUN interface"),
640                               1, GNUNET_NO);
641   }
642   /* clean up, we're done */
643   cleanup_rr (rr);
644 }
645
646
647 /**
648  * Show the payload of the given request record to the client
649  * (and wait for a response).
650  *
651  * @param rr request to send to client
652  * @param client client to send the response to
653  */
654 static void
655 send_request_to_client (struct RequestRecord *rr,
656                         struct GNUNET_SERVER_Client *client)
657 {
658   char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length] GNUNET_ALIGN;
659   struct GNUNET_DNS_Request *req;
660
661   if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
662   {
663     GNUNET_break (0);
664     cleanup_rr (rr);
665     return;
666   }
667   req = (struct GNUNET_DNS_Request*) buf;
668   req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
669   req->header.size = htons (sizeof (buf));
670   req->reserved = htonl (0);
671   req->request_id = rr->request_id;
672   memcpy (&req[1], rr->payload, rr->payload_length);
673   GNUNET_SERVER_notification_context_unicast (nc, 
674                                               client,
675                                               &req->header,
676                                               GNUNET_NO);
677 }
678
679
680 /**
681  * Read a DNS response from the (unhindered) UDP-Socket
682  *
683  * @param cls socket to read from
684  * @param tc scheduler context (must be shutdown or read ready)
685  */
686 static void
687 read_response (void *cls,
688                const struct GNUNET_SCHEDULER_TaskContext *tc);
689
690
691 /**
692  * Get a socket of the specified address family to send out a
693  * UDP DNS request to the Internet.  
694  *
695  * @param af desired address family
696  * @return NULL on error (given AF not "supported")
697  */
698 static struct GNUNET_NETWORK_Handle *
699 get_request_socket (int af)
700 {
701   struct RequestSocket *rs;
702   struct GNUNET_NETWORK_FDSet *rset;
703   static struct GNUNET_NETWORK_Handle *ret;
704
705   rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 
706                                           DNS_SOCKET_MAX)];
707   rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
708   switch (af)
709   {
710   case AF_INET:
711     if (NULL == rs->dnsout4)
712       rs->dnsout4 = open_socket (AF_INET);
713     ret = rs->dnsout4;
714     break;
715   case AF_INET6:
716     if (NULL == rs->dnsout6)
717       rs->dnsout6 = open_socket (AF_INET6);
718     ret = rs->dnsout6;
719     break;
720   default:
721     return NULL;
722   }  
723   if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
724   {
725     GNUNET_SCHEDULER_cancel (rs->read_task);
726     rs->read_task = GNUNET_SCHEDULER_NO_TASK;
727   }
728   if ( (NULL == rs->dnsout4) &&
729        (NULL == rs->dnsout6) )
730     return NULL;
731   rset = GNUNET_NETWORK_fdset_create ();
732   if (NULL != rs->dnsout4)
733     GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
734   if (NULL != rs->dnsout6)
735     GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
736   rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
737                                                REQUEST_TIMEOUT,
738                                                rset,
739                                                NULL,
740                                                &read_response, rs);
741   GNUNET_NETWORK_fdset_destroy (rset);
742   return ret;
743 }
744
745
746 /**
747  * A client has completed its processing for this
748  * request.  Move on.
749  *
750  * @param rr request to process further
751  */
752 static void
753 next_phase (struct RequestRecord *rr)
754 {
755   struct ClientRecord *cr;
756   int nz;
757   unsigned int j;
758   socklen_t salen;
759
760   if (rr->phase == RP_DROP)
761   {
762     cleanup_rr (rr);
763     return;
764   }
765   nz = -1;
766   for (j=0;j<rr->client_wait_list_length;j++)
767   {
768     if (NULL != rr->client_wait_list[j])
769     {
770       nz = (int) j;
771       break;
772     }
773   }  
774   if (-1 != nz) 
775   {
776     send_request_to_client (rr, rr->client_wait_list[nz]->client);
777     return;
778   }
779   /* done with current phase, advance! */
780   switch (rr->phase)
781   {
782   case RP_INIT:
783     rr->phase = RP_REQUEST_MONITOR;
784     for (cr = clients_head; NULL != cr; cr = cr->next)
785     {
786       if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
787         GNUNET_array_append (rr->client_wait_list,
788                              rr->client_wait_list_length,
789                              cr);
790     }
791     next_phase (rr);
792     return;
793   case RP_REQUEST_MONITOR:
794     rr->phase = RP_QUERY;
795     for (cr = clients_head; NULL != cr; cr = cr->next)
796     {
797       if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
798         GNUNET_array_append (rr->client_wait_list,
799                              rr->client_wait_list_length,
800                              cr);
801     }
802     next_phase (rr);
803     return;
804   case RP_QUERY:
805     switch (rr->dst_addr.ss_family)
806     {
807     case AF_INET:
808       salen = sizeof (struct sockaddr_in);
809       break;
810     case AF_INET6:
811       salen = sizeof (struct sockaddr_in6);
812       break;
813     default:
814       GNUNET_assert (0);
815     }
816
817     rr->phase = RP_INTERNET_DNS;
818     rr->dnsout = get_request_socket (rr->dst_addr.ss_family);
819     if (NULL == rr->dnsout)
820     {
821       GNUNET_STATISTICS_update (stats,
822                                 gettext_noop ("# DNS exit failed (failed to open socket)"),
823                                 1, GNUNET_NO);
824       cleanup_rr (rr);
825       return;
826     }
827     GNUNET_NETWORK_socket_sendto (rr->dnsout,
828                                   rr->payload,
829                                   rr->payload_length,
830                                   (struct sockaddr*) &rr->dst_addr,
831                                   salen);
832     rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
833     return;
834   case RP_INTERNET_DNS:
835     rr->phase = RP_MODIFY;
836     for (cr = clients_head; NULL != cr; cr = cr->next)
837     {
838       if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
839         GNUNET_array_append (rr->client_wait_list,
840                              rr->client_wait_list_length,
841                              cr);
842     }
843     next_phase (rr);
844     return;
845   case RP_MODIFY:
846     rr->phase = RP_RESPONSE_MONITOR;
847     for (cr = clients_head; NULL != cr; cr = cr->next)
848     {
849       if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
850         GNUNET_array_append (rr->client_wait_list,
851                              rr->client_wait_list_length,
852                              cr);
853     }
854     next_phase (rr);
855     return;
856  case RP_RESPONSE_MONITOR:
857     request_done (rr);
858     break;
859   case RP_DROP:
860     cleanup_rr (rr);
861     break;
862   default:
863     GNUNET_break (0);
864     cleanup_rr (rr);
865     break;
866   }
867 }
868
869
870 /**
871  * A client disconnected, clean up after it.
872  *
873  * @param cls unused
874  * @param client handle of client that disconnected
875  */ 
876 static void
877 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
878 {
879   struct ClientRecord *cr;
880   struct RequestRecord *rr;
881   unsigned int i;
882   unsigned int j;
883
884   for (cr = clients_head; NULL != cr; cr = cr->next)
885   {
886     if (cr->client == client)
887     {
888       GNUNET_SERVER_client_drop (client);
889       GNUNET_CONTAINER_DLL_remove (clients_head,
890                                    clients_tail,
891                                    cr);
892       for (i=0;i<UINT16_MAX;i++)
893       {
894         rr = &requests[i];
895         if (0 == rr->client_wait_list_length)
896           continue; /* not in use */
897         for (j=0;j<rr->client_wait_list_length;j++)
898         {
899           if (rr->client_wait_list[j] == cr)
900           {
901             rr->client_wait_list[j] = NULL;
902             next_phase (rr); 
903           }
904         }
905       }
906       GNUNET_free (cr);
907       return;
908     }
909   }
910 }
911
912
913 /**
914  * We got a reply from DNS for a request of a MESH tunnel.  Send it
915  * via the tunnel (after changing the request ID back).
916  *
917  * @param cls the 'struct TunnelState'
918  * @param size number of bytes available in buf
919  * @param buf where to copy the reply
920  * @return number of bytes written to buf
921  */
922 static size_t
923 transmit_reply_to_mesh (void *cls,
924                         size_t size,
925                         void *buf)
926 {
927   struct TunnelState *ts = cls;
928   size_t off;
929   size_t ret;
930   char *cbuf = buf;
931   struct GNUNET_MessageHeader hdr;
932   struct GNUNET_TUN_DnsHeader dns;
933
934   ts->th = NULL;
935   GNUNET_assert (ts->reply != NULL);
936   if (size == 0)
937     return 0;
938   ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length; 
939   GNUNET_assert (ret <= size);
940   hdr.size = htons (ret);
941   hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
942   memcpy (&dns, ts->reply, sizeof (dns));
943   dns.id = ts->original_id;
944   off = 0;
945   memcpy (&cbuf[off], &hdr, sizeof (hdr));
946   off += sizeof (hdr);
947   memcpy (&cbuf[off], &dns, sizeof (dns));
948   off += sizeof (dns);
949   memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
950   off += ts->reply_length - sizeof (dns);
951   GNUNET_free (ts->reply);
952   ts->reply = NULL;
953   ts->reply_length = 0;  
954   GNUNET_assert (ret == off);
955   return ret;
956 }
957
958
959 /**
960  * Actually do the reading of a DNS packet from our UDP socket and see
961  * if we have a valid, matching, pending request.
962  *
963  * @param dnsout socket to read from
964  * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
965  */
966 static int
967 do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
968 {
969   struct sockaddr_storage addr;
970   socklen_t addrlen;
971   struct GNUNET_TUN_DnsHeader *dns;
972   struct RequestRecord *rr;
973   struct TunnelState *ts;
974   ssize_t r;
975   int len;
976
977 #ifndef MINGW
978   if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
979   {
980     /* conservative choice: */
981     len = UINT16_MAX;
982   }
983 #else
984   /* port the code above? */
985   len = UINT16_MAX;
986 #endif
987
988   {
989     unsigned char buf[len] GNUNET_ALIGN;
990
991     addrlen = sizeof (addr);
992     memset (&addr, 0, sizeof (addr));  
993     r = GNUNET_NETWORK_socket_recvfrom (dnsout, 
994                                         buf, sizeof (buf),
995                                         (struct sockaddr*) &addr, &addrlen);
996     if (-1 == r)
997     {
998       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
999       GNUNET_NETWORK_socket_close (dnsout);
1000       return GNUNET_SYSERR;
1001     }
1002     if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
1003     {
1004       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
1005                   _("Received DNS response that is too small (%u bytes)"),
1006                   r);
1007       return GNUNET_NO;
1008     }
1009     dns = (struct GNUNET_TUN_DnsHeader *) buf;
1010     /* Handle case that this is a reply to a request from a MESH DNS tunnel */
1011     ts = tunnels[dns->id];
1012     if ( (NULL == ts) ||
1013          (ts->dnsout != dnsout) ||
1014          (addrlen != ts->addrlen) ||
1015          (0 != memcmp (&ts->addr,
1016                        &addr,
1017                        addrlen)) ||      
1018          (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) )
1019       ts = NULL; /* DNS responder address missmatch */
1020     if (NULL != ts)
1021     {
1022       tunnels[dns->id] = NULL;
1023       GNUNET_free_non_null (ts->reply);
1024       ts->reply = GNUNET_malloc (r);
1025       ts->reply_length = r;
1026       memcpy (ts->reply, dns, r);
1027       if (ts->th != NULL)
1028         GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1029       ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
1030                                                   GNUNET_NO, 0,
1031                                                   GNUNET_TIME_UNIT_FOREVER_REL,
1032                                                   NULL,
1033                                                   sizeof (struct GNUNET_MessageHeader) + r,
1034                                                   &transmit_reply_to_mesh,
1035                                                   ts);
1036     }
1037     /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
1038     rr = &requests[dns->id];
1039     if ( (rr->phase != RP_INTERNET_DNS) ||
1040          (rr->dnsout != dnsout) ||
1041          (0 != memcmp (&rr->dst_addr,
1042                        &addr,
1043                        addrlen)) ||
1044          (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) )
1045     {
1046       if (NULL == ts)
1047       {
1048         /* unexpected / bogus reply */
1049         GNUNET_STATISTICS_update (stats,
1050                                   gettext_noop ("# External DNS response discarded (no matching request)"),
1051                                   1, GNUNET_NO);
1052       }
1053       return GNUNET_NO; 
1054     }
1055     GNUNET_free_non_null (rr->payload);
1056     rr->payload = GNUNET_malloc (r);
1057     memcpy (rr->payload, buf, r);
1058     rr->payload_length = r;
1059     next_phase (rr);
1060   }  
1061   return GNUNET_OK;
1062 }
1063
1064
1065 /**
1066  * Read a DNS response from the (unhindered) UDP-Socket
1067  *
1068  * @param cls socket to read from
1069  * @param tc scheduler context (must be shutdown or read ready)
1070  */
1071 static void
1072 read_response (void *cls,
1073                const struct GNUNET_SCHEDULER_TaskContext *tc)
1074 {
1075   struct RequestSocket *rs = cls;
1076   struct GNUNET_NETWORK_FDSet *rset;
1077
1078   rs->read_task = GNUNET_SCHEDULER_NO_TASK;
1079   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1080   {
1081     /* timeout or shutdown */
1082     cleanup_rs (rs);
1083     return;
1084   }
1085   /* read and process ready sockets */
1086   if ((NULL != rs->dnsout4) &&
1087       (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
1088       (GNUNET_SYSERR == do_dns_read (rs->dnsout4)))
1089     rs->dnsout4 = NULL;
1090   if ((NULL != rs->dnsout6) &&
1091       (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
1092       (GNUNET_SYSERR == do_dns_read (rs->dnsout6)))
1093     rs->dnsout6 = NULL;
1094
1095   /* re-schedule read task */
1096   rset = GNUNET_NETWORK_fdset_create ();
1097   if (NULL != rs->dnsout4)
1098     GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
1099   if (NULL != rs->dnsout6)
1100     GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
1101   rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1102                                                GNUNET_TIME_absolute_get_remaining (rs->timeout),
1103                                                rset,
1104                                                NULL,
1105                                                &read_response, rs);
1106   GNUNET_NETWORK_fdset_destroy (rset);
1107 }
1108
1109
1110 /**
1111  * We got a new client.  Make sure all new DNS requests pass by its desk.
1112  *
1113  * @param cls unused
1114  * @param client the new client
1115  * @param message the init message (unused)
1116  */
1117 static void
1118 handle_client_init (void *cls GNUNET_UNUSED, 
1119                     struct GNUNET_SERVER_Client *client,
1120                     const struct GNUNET_MessageHeader *message)
1121 {
1122   struct ClientRecord *cr;
1123   const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
1124
1125   cr = GNUNET_malloc (sizeof (struct ClientRecord));
1126   cr->client = client;
1127   cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);  
1128   GNUNET_SERVER_client_keep (client);
1129   GNUNET_CONTAINER_DLL_insert (clients_head,
1130                                clients_tail,
1131                                cr);
1132   GNUNET_SERVER_notification_context_add (nc, client);
1133   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1134 }
1135
1136
1137 /**
1138  * We got a response from a client.
1139  *
1140  * @param cls unused
1141  * @param client the client
1142  * @param message the response
1143  */
1144 static void
1145 handle_client_response (void *cls GNUNET_UNUSED, 
1146                         struct GNUNET_SERVER_Client *client,
1147                         const struct GNUNET_MessageHeader *message)
1148 {
1149   const struct GNUNET_DNS_Response *resp;
1150   struct RequestRecord *rr;
1151   unsigned int i;
1152   uint16_t msize;
1153   uint16_t off;
1154
1155   msize = ntohs (message->size);
1156   if (msize < sizeof (struct GNUNET_DNS_Response))
1157   {
1158     GNUNET_break (0);
1159     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1160     return;
1161   }
1162   resp = (const struct GNUNET_DNS_Response*) message;
1163   off = (uint16_t) resp->request_id;
1164   rr = &requests[off];
1165   if (rr->request_id != resp->request_id)
1166   {
1167     GNUNET_STATISTICS_update (stats,
1168                               gettext_noop ("# Client response discarded (no matching request)"),
1169                               1, GNUNET_NO);
1170     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1171     return;
1172   }
1173   for (i=0;i<rr->client_wait_list_length;i++)
1174   {
1175     if (NULL == rr->client_wait_list[i])
1176       continue;
1177     if (rr->client_wait_list[i]->client != client)
1178       continue;
1179     rr->client_wait_list[i] = NULL;
1180     switch (ntohl (resp->drop_flag))
1181     {
1182     case 0: /* drop */
1183       rr->phase = RP_DROP;
1184       break;
1185     case 1: /* no change */
1186       break;
1187     case 2: /* update */
1188       msize -= sizeof (struct GNUNET_DNS_Response);
1189       if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
1190            (RP_REQUEST_MONITOR == rr->phase) ||
1191            (RP_RESPONSE_MONITOR == rr->phase) )
1192       {
1193         GNUNET_break (0);
1194         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1195         next_phase (rr); 
1196         return;
1197       }
1198       GNUNET_free_non_null (rr->payload);
1199       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1200                   "Changing DNS reply according to client specifications\n");
1201       rr->payload = GNUNET_malloc (msize);
1202       rr->payload_length = msize;
1203       memcpy (rr->payload, &resp[1], msize);
1204       if (rr->phase == RP_QUERY)
1205       {
1206         /* clear wait list, we're moving to MODIFY phase next */
1207         GNUNET_array_grow (rr->client_wait_list,
1208                            rr->client_wait_list_length,
1209                            0);
1210       }
1211       /* if query changed to answer, move past DNS resolution phase... */
1212       if ( (RP_QUERY == rr->phase) &&
1213            (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
1214            ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
1215       {
1216         rr->phase = RP_INTERNET_DNS;
1217         GNUNET_array_grow (rr->client_wait_list,
1218                            rr->client_wait_list_length,
1219                            0);
1220       }
1221       break;
1222     }
1223     next_phase (rr); 
1224     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1225     return;      
1226   }
1227   /* odd, client was not on our list for the request, that ought
1228      to be an error */
1229   GNUNET_break (0);
1230   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1231 }
1232
1233
1234 /**
1235  * Functions with this signature are called whenever a complete
1236  * message is received by the tokenizer from the DNS hijack process.
1237  *
1238  * @param cls closure
1239  * @param client identification of the client
1240  * @param message the actual message, a DNS request we should handle
1241  */
1242 static int
1243 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1244                          const struct GNUNET_MessageHeader *message)
1245 {
1246   uint16_t msize;
1247   const struct GNUNET_TUN_Layer2PacketHeader *tun;
1248   const struct GNUNET_TUN_IPv4Header *ip4;
1249   const struct GNUNET_TUN_IPv6Header *ip6;
1250   const struct GNUNET_TUN_UdpHeader *udp;
1251   const struct GNUNET_TUN_DnsHeader *dns;
1252   struct RequestRecord *rr;
1253   struct sockaddr_in *srca4;
1254   struct sockaddr_in6 *srca6;
1255   struct sockaddr_in *dsta4;
1256   struct sockaddr_in6 *dsta6;
1257
1258   msize = ntohs (message->size);
1259   if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1260   {
1261     /* non-IP packet received on TUN!? */
1262     GNUNET_break (0);
1263     return GNUNET_OK;
1264   }
1265   msize -= sizeof (struct GNUNET_MessageHeader);
1266   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1267   msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1268   switch (ntohs (tun->proto))
1269   {
1270   case ETH_P_IPV4:
1271     ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1272     ip6 = NULL; /* make compiler happy */
1273     if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1274          (ip4->version != 4) ||
1275          (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1276          (ntohs(ip4->total_length) != msize) ||
1277          (ip4->protocol != IPPROTO_UDP) )
1278     {
1279       /* non-IP/UDP packet received on TUN (or with options) */
1280       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1281                   _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1282       return GNUNET_OK;
1283     }
1284     udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1285     msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1286     break;
1287   case ETH_P_IPV6:
1288     ip4 = NULL; /* make compiler happy */
1289     ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1290     if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1291          (ip6->version != 6) ||
1292          (ntohs (ip6->payload_length) != msize) ||
1293          (ip6->next_header != IPPROTO_UDP) )
1294     {
1295       /* non-IP/UDP packet received on TUN (or with extensions) */
1296       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1297                   _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1298       return GNUNET_OK;
1299     }
1300     udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1301     msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1302     break;
1303   default:
1304     /* non-IP packet received on TUN!? */
1305     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1306                 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1307                 (unsigned int) msize,
1308                 ntohs (tun->proto));
1309     return GNUNET_OK;
1310   }
1311   if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1312   {    
1313     /* non-DNS packet received on TUN, ignore */
1314     GNUNET_STATISTICS_update (stats,
1315                               gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1316                               1, GNUNET_NO);
1317     return GNUNET_OK;
1318   }
1319   msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1320   dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1321   rr = &requests[dns->id];
1322
1323   /* clean up from previous request */
1324   GNUNET_free_non_null (rr->payload);
1325   rr->payload = NULL;
1326   GNUNET_array_grow (rr->client_wait_list,
1327                      rr->client_wait_list_length,
1328                      0);
1329
1330   /* setup new request */
1331   rr->phase = RP_INIT;
1332   switch (ntohs (tun->proto))
1333   {
1334   case ETH_P_IPV4:
1335     {
1336       srca4 = (struct sockaddr_in*) &rr->src_addr;
1337       dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1338       memset (srca4, 0, sizeof (struct sockaddr_in));
1339       memset (dsta4, 0, sizeof (struct sockaddr_in));
1340       srca4->sin_family = AF_INET;
1341       dsta4->sin_family = AF_INET;
1342       srca4->sin_addr = ip4->source_address;
1343       dsta4->sin_addr = ip4->destination_address;
1344       srca4->sin_port = udp->source_port;
1345       dsta4->sin_port = udp->destination_port;
1346 #if HAVE_SOCKADDR_IN_SIN_LEN
1347       srca4->sin_len = sizeof (struct sockaddr_in);
1348       dsta4->sin_len = sizeof (struct sockaddr_in);
1349 #endif
1350     }
1351     break;
1352   case ETH_P_IPV6:
1353     {
1354       srca6 = (struct sockaddr_in6*) &rr->src_addr;
1355       dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1356       memset (srca6, 0, sizeof (struct sockaddr_in6));
1357       memset (dsta6, 0, sizeof (struct sockaddr_in6));
1358       srca6->sin6_family = AF_INET6;
1359       dsta6->sin6_family = AF_INET6;
1360       srca6->sin6_addr = ip6->source_address;
1361       dsta6->sin6_addr = ip6->destination_address;
1362       srca6->sin6_port = udp->source_port;
1363       dsta6->sin6_port = udp->destination_port;
1364 #if HAVE_SOCKADDR_IN_SIN_LEN
1365       srca6->sin6_len = sizeof (struct sockaddr_in6);
1366       dsta6->sin6_len = sizeof (struct sockaddr_in6);
1367 #endif
1368     }
1369   break;
1370   default:
1371     GNUNET_assert (0);
1372   }
1373   rr->payload = GNUNET_malloc (msize);
1374   rr->payload_length = msize;
1375   memcpy (rr->payload, dns, msize);
1376   rr->request_id = dns->id | (request_id_gen << 16);
1377   request_id_gen++;
1378
1379   GNUNET_STATISTICS_update (stats,
1380                             gettext_noop ("# DNS requests received via TUN interface"),
1381                             1, GNUNET_NO);
1382   /* start request processing state machine */
1383   next_phase (rr);
1384   return GNUNET_OK;
1385 }
1386
1387
1388 /**
1389  * Process a request via mesh to perform a DNS query.
1390  *
1391  * @param cls closure, NULL
1392  * @param tunnel connection to the other end
1393  * @param tunnel_ctx pointer to our 'struct TunnelState *'
1394  * @param sender who sent the message
1395  * @param message the actual message
1396  * @param atsi performance data for the connection
1397  * @return GNUNET_OK to keep the connection open,
1398  *         GNUNET_SYSERR to close it (signal serious error)
1399  */
1400 static int
1401 receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1402                      void **tunnel_ctx,
1403                      const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1404                      const struct GNUNET_MessageHeader *message,
1405                      const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1406 {
1407   struct TunnelState *ts = *tunnel_ctx;
1408   const struct GNUNET_TUN_DnsHeader *dns;
1409   size_t mlen = ntohs (message->size);
1410   size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1411   char buf[dlen] GNUNET_ALIGN;
1412   struct GNUNET_TUN_DnsHeader *dout;
1413   struct sockaddr_in v4;
1414   struct sockaddr_in6 v6;
1415   struct sockaddr *so;
1416   socklen_t salen;
1417   
1418   if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1419   {
1420     GNUNET_break_op (0);
1421     return GNUNET_SYSERR;
1422   }
1423   dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1424   ts->original_id = dns->id;
1425   if (tunnels[ts->my_id] == ts)
1426     tunnels[ts->my_id] = NULL;
1427   ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 
1428                                                    UINT16_MAX + 1);
1429   tunnels[ts->my_id] = ts;
1430   memcpy (buf, dns, dlen);
1431   dout = (struct GNUNET_TUN_DnsHeader*) buf;
1432   dout->id = ts->my_id;
1433   memset (&v4, 0, sizeof (v4));
1434   memset (&v6, 0, sizeof (v6));
1435   if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
1436   {
1437     salen = sizeof (v4);
1438     v4.sin_family = AF_INET;
1439     v4.sin_port = htons (53);
1440 #if HAVE_SOCKADDR_IN_SIN_LEN
1441     v4.sin_len = (u_char) salen;
1442 #endif
1443     so = (struct sockaddr *) &v4;
1444     ts->dnsout = get_request_socket (AF_INET);
1445   }
1446   else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1447   {
1448     salen = sizeof (v6);
1449     v6.sin6_family = AF_INET6;
1450     v6.sin6_port = htons (53);
1451 #if HAVE_SOCKADDR_IN_SIN_LEN
1452     v6.sin6_len = (u_char) salen;
1453 #endif
1454     so = (struct sockaddr *) &v6;
1455     ts->dnsout = get_request_socket (AF_INET6);
1456   }  
1457   else
1458   {
1459     GNUNET_break (0);
1460     return GNUNET_SYSERR;
1461   }
1462   if (NULL == ts->dnsout)
1463   {
1464     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1465                 _("Configured DNS exit `%s' is not working / valid.\n"),
1466                 dns_exit);
1467     return GNUNET_SYSERR;
1468   }
1469   memcpy (&ts->addr,
1470           so,
1471           salen);
1472   ts->addrlen = salen;
1473   GNUNET_NETWORK_socket_sendto (ts->dnsout,
1474                                 buf, dlen, so, salen); 
1475   ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
1476   return GNUNET_OK;
1477 }
1478
1479
1480 /**
1481  * Callback from GNUNET_MESH for new tunnels.
1482  *
1483  * @param cls closure
1484  * @param tunnel new handle to the tunnel
1485  * @param initiator peer that started the tunnel
1486  * @param ats performance information for the tunnel
1487  * @return initial tunnel context for the tunnel
1488  */
1489 static void *
1490 accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1491                    const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1492                    const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1493 {
1494   struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1495
1496   GNUNET_STATISTICS_update (stats,
1497                             gettext_noop ("# Inbound MESH tunnels created"),
1498                             1, GNUNET_NO);
1499   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1500               "Received inbound tunnel from `%s'\n",
1501               GNUNET_i2s (initiator));
1502   ts->tunnel = tunnel;
1503   return ts;
1504 }
1505
1506
1507 /**
1508  * Function called by mesh whenever an inbound tunnel is destroyed.
1509  * Should clean up any associated state.
1510  *
1511  * @param cls closure (set from GNUNET_MESH_connect)
1512  * @param tunnel connection to the other end (henceforth invalid)
1513  * @param tunnel_ctx place where local state associated
1514  *                   with the tunnel is stored
1515  */
1516 static void
1517 destroy_dns_tunnel (void *cls GNUNET_UNUSED, 
1518                     const struct GNUNET_MESH_Tunnel *tunnel,
1519                     void *tunnel_ctx)
1520 {
1521   struct TunnelState *ts = tunnel_ctx;
1522
1523   if (tunnels[ts->my_id] == ts)
1524     tunnels[ts->my_id] = NULL;
1525   if (NULL != ts->th)
1526     GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1527   GNUNET_free_non_null (ts->reply);
1528   GNUNET_free (ts);
1529 }
1530
1531
1532 /**
1533  * @param cls closure
1534  * @param server the initialized server
1535  * @param cfg_ configuration to use
1536  */
1537 static void
1538 run (void *cls, struct GNUNET_SERVER_Handle *server,
1539      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1540 {
1541   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1542     /* callback, cls, type, size */
1543     {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, 
1544      sizeof (struct GNUNET_DNS_Register)},
1545     {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1546     {NULL, NULL, 0, 0}
1547   };
1548   char *ifc_name;
1549   char *ipv4addr;
1550   char *ipv4mask;
1551   char *ipv6addr;
1552   char *ipv6prefix;
1553   struct in_addr dns_exit4;
1554   struct in6_addr dns_exit6;
1555
1556   cfg = cfg_;
1557   if (GNUNET_YES !=
1558       GNUNET_OS_check_helper_binary ("gnunet-helper-dns"))
1559   {
1560     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1561                 _("`%s' must be installed SUID, refusing to run\n"),
1562                 "gnunet-helper-dns");
1563     global_ret = 1;
1564     return;
1565   }
1566
1567   stats = GNUNET_STATISTICS_create ("dns", cfg);
1568   nc = GNUNET_SERVER_notification_context_create (server, 1);
1569   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1570                                 cls);
1571   if ( (GNUNET_YES ==
1572         GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) &&
1573        ( (GNUNET_OK !=
1574           GNUNET_CONFIGURATION_get_value_string (cfg, "dns", 
1575                                                  "DNS_EXIT",
1576                                                  &dns_exit)) ||
1577          ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1578            (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1579   {
1580     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1581                 _("Configured to provide DNS exit, but no valid DNS server configured!\n"));
1582     GNUNET_free_non_null (dns_exit);
1583     dns_exit = NULL;
1584   }
1585
1586   helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1587   if (GNUNET_SYSERR ==
1588       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1589   {
1590     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1591                 "No entry 'IFNAME' in configuration!\n");
1592     GNUNET_SCHEDULER_shutdown ();
1593     return;
1594   }
1595   helper_argv[1] = ifc_name;
1596   if ( (GNUNET_SYSERR ==
1597         GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1598                                                &ipv6addr)) )
1599   {
1600     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1601                 "No entry 'IPV6ADDR' in configuration!\n");
1602     GNUNET_SCHEDULER_shutdown ();
1603     return;
1604   }
1605   helper_argv[2] = ipv6addr;
1606   if (GNUNET_SYSERR ==
1607       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1608                                              &ipv6prefix))
1609   {
1610     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1611                 "No entry 'IPV6PREFIX' in configuration!\n");
1612     GNUNET_SCHEDULER_shutdown ();
1613     return;
1614   }
1615   helper_argv[3] = ipv6prefix;
1616
1617   if (GNUNET_SYSERR ==
1618       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1619                                              &ipv4addr))
1620   {
1621     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1622                 "No entry 'IPV4ADDR' in configuration!\n");
1623     GNUNET_SCHEDULER_shutdown ();
1624     return;
1625   }
1626   helper_argv[4] = ipv4addr;
1627   if (GNUNET_SYSERR ==
1628       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1629                                              &ipv4mask))
1630   {
1631     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1632                 "No entry 'IPV4MASK' in configuration!\n");
1633     GNUNET_SCHEDULER_shutdown ();
1634     return;
1635   }
1636   helper_argv[5] = ipv4mask;
1637   helper_argv[6] = NULL;
1638
1639   if (NULL != dns_exit)
1640   {
1641     static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1642       {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1643       {NULL, 0, 0}
1644     };
1645     static GNUNET_MESH_ApplicationType mesh_types[] = {
1646       GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1647       GNUNET_APPLICATION_TYPE_END
1648     };
1649     mesh = GNUNET_MESH_connect (cfg,
1650                                 1, NULL,
1651                                 &accept_dns_tunnel, 
1652                                 &destroy_dns_tunnel,
1653                                 mesh_handlers,
1654                                 mesh_types);
1655   }
1656   hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1657                                   helper_argv,
1658                                   &process_helper_messages,
1659                                   NULL);
1660   GNUNET_SERVER_add_handlers (server, handlers);
1661   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1662 }
1663
1664
1665 /**
1666  * The main function for the dns service.
1667  *
1668  * @param argc number of arguments from the command line
1669  * @param argv command line arguments
1670  * @return 0 ok, 1 on error
1671  */
1672 int
1673 main (int argc, char *const *argv)
1674 {
1675   return (GNUNET_OK ==
1676           GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1677                               &run, NULL)) ? global_ret : 1;
1678 }
1679
1680
1681 /* end of gnunet-service-dns.c */