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