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