-moving remaining checksum calculations to tun library, fixing #2066
[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_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_signatures.h"
31 #include "dns.h"
32 #include "gnunet_dns_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_tun_lib.h"
35
36
37 /**
38  * Phases each request goes through.
39  */
40 enum RequestPhase
41 {
42   /**
43    * Request has just been received.
44    */
45   RP_INIT,
46
47   /**
48    * Showing the request to all monitor clients.  If
49    * client list is empty, will enter QUERY phase.
50    */
51   RP_REQUEST_MONITOR,
52
53   /**
54    * Showing the request to PRE-RESOLUTION clients to find an answer.
55    * If client list is empty, will trigger global DNS request.
56    */
57   RP_QUERY,
58
59   /**
60    * Global Internet query is now pending.
61    */
62   RP_INTERNET_DNS,
63   
64   /**
65    * Client (or global DNS request) has resulted in a response.
66    * Forward to all POST-RESOLUTION clients.  If client list is empty,
67    * will enter RESPONSE_MONITOR phase.
68    */
69   RP_MODIFY,
70
71   /**
72    * Showing the request to all monitor clients.  If
73    * client list is empty, give the result to the hijacker (and be done).
74    */
75   RP_RESPONSE_MONITOR,
76
77   /**
78    * Some client has told us to drop the request.
79    */
80   RP_DROP
81 };
82
83
84 /**
85  * Entry we keep for each client.
86  */ 
87 struct ClientRecord
88 {
89   /**
90    * Kept in doubly-linked list.
91    */ 
92   struct ClientRecord *next;
93
94   /**
95    * Kept in doubly-linked list.
96    */ 
97   struct ClientRecord *prev;
98
99   /**
100    * Handle to the client.
101    */ 
102   struct GNUNET_SERVER_Client *client;
103
104   /**
105    * Flags for the client.
106    */
107   enum GNUNET_DNS_Flags flags;
108
109 };
110
111
112 /**
113  * Entry we keep for each active request.
114  */ 
115 struct RequestRecord
116 {
117
118   /**
119    * List of clients that still need to see this request (each entry
120    * is set to NULL when the client is done).
121    */
122   struct ClientRecord **client_wait_list;
123
124   /**
125    * Payload of the UDP packet (the UDP payload), can be either query
126    * or already the response.
127    */
128   char *payload;
129
130   /**
131    * Source address of the original request (for sending response).
132    */
133   struct sockaddr_storage src_addr;
134
135   /**
136    * Destination address of the original request (for potential use as exit).
137    */
138   struct sockaddr_storage dst_addr;
139
140   /**
141    * ID of this request, also basis for hashing.  Lowest 16 bit will
142    * be our message ID when doing a global DNS request and our index
143    * into the 'requests' array.
144    */
145   uint64_t request_id;
146
147   /**
148    * Number of bytes in payload.
149    */ 
150   size_t payload_length;
151
152   /**
153    * Length of the client wait list.
154    */
155   unsigned int client_wait_list_length;
156
157   /**
158    * In which phase this this request?
159    */
160   enum RequestPhase phase;
161
162 };
163
164
165 /**
166  * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
167  * sent through gnunet. The port of this socket will not be hijacked.
168  */
169 static struct GNUNET_NETWORK_Handle *dnsout4;
170
171 /**
172  * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
173  * sent through gnunet. The port of this socket will not be hijacked.
174  */
175 static struct GNUNET_NETWORK_Handle *dnsout6;
176
177 /**
178  * Task for reading from dnsout4.
179  */
180 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
181
182 /**
183  * Task for reading from dnsout6.
184  */
185 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
186
187 /**
188  * The port bound to the socket dnsout (and/or dnsout6).  We always (try) to bind
189  * both sockets to the same port.
190  */
191 static uint16_t dnsoutport;
192
193 /**
194  * The configuration to use
195  */
196 static const struct GNUNET_CONFIGURATION_Handle *cfg;
197
198 /**
199  * Statistics.
200  */
201 static struct GNUNET_STATISTICS_Handle *stats;
202
203 /**
204  * Handle to DNS hijacker helper process ("gnunet-helper-dns").
205  */
206 static struct GNUNET_HELPER_Handle *hijacker;
207
208 /**
209  * Command-line arguments we are giving to the hijacker process.
210  */
211 static char *helper_argv[8];
212
213 /**
214  * Head of DLL of clients we consult.
215  */
216 static struct ClientRecord *clients_head;
217
218 /**
219  * Tail of DLL of clients we consult.
220  */
221 static struct ClientRecord *clients_tail;
222
223 /**
224  * Our notification context.
225  */
226 static struct GNUNET_SERVER_NotificationContext *nc;
227
228 /**
229  * Array of all open requests.
230  */
231 static struct RequestRecord requests[UINT16_MAX + 1];
232
233 /**
234  * Generator for unique request IDs.
235  */
236 static uint64_t request_id_gen;
237
238
239 /**
240  * We're done processing a DNS request, free associated memory.
241  *
242  * @param rr request to clean up
243  */
244 static void
245 cleanup_rr (struct RequestRecord *rr)
246 {
247   GNUNET_free_non_null (rr->payload);
248   rr->payload = NULL;
249   rr->payload_length = 0;
250   GNUNET_array_grow (rr->client_wait_list,
251                      rr->client_wait_list_length,
252                      0);
253 }
254
255
256 /**
257  * Task run during shutdown.
258  *
259  * @param cls unused
260  * @param tc unused
261  */
262 static void
263 cleanup_task (void *cls GNUNET_UNUSED,
264               const struct GNUNET_SCHEDULER_TaskContext *tc)
265 {
266   unsigned int i;
267
268   GNUNET_HELPER_stop (hijacker);
269   hijacker = NULL;
270   for (i=0;i<8;i++)
271     GNUNET_free_non_null (helper_argv[i]);
272   if (NULL != dnsout4)
273   {
274     GNUNET_NETWORK_socket_close (dnsout4);
275     dnsout4 = NULL;
276   }
277   if (GNUNET_SCHEDULER_NO_TASK != read4_task)
278   {
279     GNUNET_SCHEDULER_cancel (read4_task);
280     read4_task = GNUNET_SCHEDULER_NO_TASK;
281   }
282   if (NULL != dnsout6)
283   {
284     GNUNET_NETWORK_socket_close (dnsout6);
285     dnsout6 = NULL;
286   }
287   if (GNUNET_SCHEDULER_NO_TASK != read6_task)
288   {
289     GNUNET_SCHEDULER_cancel (read6_task);
290     read6_task = GNUNET_SCHEDULER_NO_TASK;
291   }
292   for (i=0;i<65536;i++)
293     cleanup_rr (&requests[i]);
294   GNUNET_SERVER_notification_context_destroy (nc);
295   nc = NULL;
296   if (stats != NULL)
297   {
298     GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
299     stats = NULL;
300   }
301 }
302
303
304 /**
305  * We're done with some request, finish processing.
306  *
307  * @param rr request send to the network or just clean up.
308  */
309 static void
310 request_done (struct RequestRecord *rr)
311 {
312   struct GNUNET_MessageHeader *hdr;
313   size_t reply_len;
314   uint16_t spt;
315   uint16_t dpt;
316
317   GNUNET_array_grow (rr->client_wait_list,
318                      rr->client_wait_list_length,
319                      0); 
320   if (RP_RESPONSE_MONITOR != rr->phase)
321   {
322     /* no response, drop */
323     cleanup_rr (rr);
324     return;
325   }
326   
327   /* send response via hijacker */
328   reply_len = sizeof (struct GNUNET_MessageHeader);
329   reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
330   switch (rr->src_addr.ss_family)
331   {
332   case AF_INET:
333     reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
334     break;
335   case AF_INET6:
336     reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
337     break;
338   default:
339     GNUNET_break (0);
340     cleanup_rr (rr);
341     return;   
342   }
343   reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
344   reply_len += rr->payload_length;
345   if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
346   {
347     /* response too big, drop */
348     GNUNET_break (0); /* how can this be? */
349     cleanup_rr(rr);
350     return;    
351   }
352   {
353     char buf[reply_len];
354     size_t off;
355     struct GNUNET_TUN_IPv4Header ip4;
356     struct GNUNET_TUN_IPv6Header ip6;
357
358     /* first, GNUnet message header */
359     hdr = (struct GNUNET_MessageHeader*) buf;
360     hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
361     hdr->size = htons ((uint16_t) reply_len);
362     off = sizeof (struct GNUNET_MessageHeader);
363
364     /* first, TUN header */
365     {
366       struct GNUNET_TUN_Layer2PacketHeader tun;
367
368       tun.flags = htons (0);
369       if (rr->src_addr.ss_family == AF_INET)
370         tun.proto = htons (ETH_P_IPV4); 
371       else
372         tun.proto = htons (ETH_P_IPV6);
373       memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
374       off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
375     }
376
377     /* now IP header */
378     switch (rr->src_addr.ss_family)
379     {
380     case AF_INET:
381       {
382         struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
383         struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
384         
385         spt = dst->sin_port;
386         dpt = src->sin_port;
387         GNUNET_TUN_initialize_ipv4_header (&ip4,
388                                            IPPROTO_UDP,
389                                            reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
390                                            &dst->sin_addr,
391                                            &src->sin_addr);
392         memcpy (&buf[off], &ip4, sizeof (ip4));
393         off += sizeof (ip4);
394       }
395       break;
396     case AF_INET6:
397       {
398         struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
399         struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
400
401         spt = dst->sin6_port;
402         dpt = src->sin6_port;
403         GNUNET_TUN_initialize_ipv6_header (&ip6,
404                                            IPPROTO_UDP,
405                                            reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
406                                            &dst->sin6_addr,
407                                            &src->sin6_addr);
408         memcpy (&buf[off], &ip6, sizeof (ip6));
409         off += sizeof (ip6);
410       }
411       break;
412     default:
413       GNUNET_assert (0);
414     }
415
416     /* now UDP header */
417     {
418       struct GNUNET_TUN_UdpHeader udp;
419
420       udp.spt = spt;
421       udp.dpt = dpt;
422       udp.len = htons (reply_len - off);
423       if (AF_INET == rr->src_addr.ss_family)
424         GNUNET_TUN_calculate_udp4_checksum (&ip4,
425                                             &udp,
426                                             rr->payload,
427                                             rr->payload_length);
428       else
429         GNUNET_TUN_calculate_udp6_checksum (&ip6,
430                                             &udp,
431                                             rr->payload,
432                                             rr->payload_length);
433       memcpy (&buf[off], &udp, sizeof (udp));
434       off += sizeof (udp);
435     }
436
437     /* now DNS payload */
438     {
439       memcpy (&buf[off], rr->payload, rr->payload_length);
440       off += rr->payload_length;
441     }
442     /* final checks & sending */
443     GNUNET_assert (off == reply_len);
444     GNUNET_HELPER_send (hijacker,
445                         hdr,
446                         GNUNET_YES,
447                         NULL, NULL);
448     GNUNET_STATISTICS_update (stats,
449                               gettext_noop ("# DNS requests answered via TUN interface"),
450                               1, GNUNET_NO);
451   }
452   /* clean up, we're done */
453   cleanup_rr (rr);
454 }
455
456
457 /**
458  * Show the payload of the given request record to the client
459  * (and wait for a response).
460  *
461  * @param rr request to send to client
462  * @param client client to send the response to
463  */
464 static void
465 send_request_to_client (struct RequestRecord *rr,
466                         struct GNUNET_SERVER_Client *client)
467 {
468   char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
469   struct GNUNET_DNS_Request *req;
470
471   if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
472   {
473     GNUNET_break (0);
474     cleanup_rr (rr);
475     return;
476   }
477   req = (struct GNUNET_DNS_Request*) buf;
478   req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
479   req->header.size = htons (sizeof (buf));
480   req->reserved = htonl (0);
481   req->request_id = rr->request_id;
482   memcpy (&req[1], rr->payload, rr->payload_length);
483   GNUNET_SERVER_notification_context_unicast (nc, 
484                                               client,
485                                               &req->header,
486                                               GNUNET_NO);
487 }
488
489
490 /**
491  * A client has completed its processing for this
492  * request.  Move on.
493  *
494  * @param rr request to process further
495  */
496 static void
497 next_phase (struct RequestRecord *rr)
498 {
499   struct ClientRecord *cr;
500   int nz;
501   unsigned int j;
502   struct GNUNET_NETWORK_Handle *dnsout;
503   socklen_t salen;
504
505   if (rr->phase == RP_DROP)
506   {
507     cleanup_rr (rr);
508     return;
509   }
510   nz = -1;
511   for (j=0;j<rr->client_wait_list_length;j++)
512   {
513     if (NULL != rr->client_wait_list[j])
514     {
515       nz = (int) j;
516       break;
517     }
518   }  
519   if (-1 != nz) 
520   {
521     send_request_to_client (rr, rr->client_wait_list[nz]->client);
522     return;
523   }
524   /* done with current phase, advance! */
525   switch (rr->phase)
526   {
527   case RP_INIT:
528     rr->phase = RP_REQUEST_MONITOR;
529     for (cr = clients_head; NULL != cr; cr = cr->next)
530     {
531       if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
532         GNUNET_array_append (rr->client_wait_list,
533                              rr->client_wait_list_length,
534                              cr);
535     }
536     next_phase (rr);
537     return;
538   case RP_REQUEST_MONITOR:
539     rr->phase = RP_QUERY;
540     for (cr = clients_head; NULL != cr; cr = cr->next)
541     {
542       if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
543         GNUNET_array_append (rr->client_wait_list,
544                              rr->client_wait_list_length,
545                              cr);
546     }
547     next_phase (rr);
548     return;
549   case RP_QUERY:
550     rr->phase = RP_INTERNET_DNS;
551     switch (rr->dst_addr.ss_family)
552     {
553     case AF_INET:
554       dnsout = dnsout4;
555       salen = sizeof (struct GNUNET_TUN_IPv4Header);
556       break;
557     case AF_INET6:
558       dnsout = dnsout6;
559       salen = sizeof (struct GNUNET_TUN_IPv6Header);
560       break;
561     default:
562       GNUNET_break (0);
563       cleanup_rr (rr);
564       return;   
565     }
566     if (NULL == dnsout)
567     {
568       GNUNET_STATISTICS_update (stats,
569                                 gettext_noop ("# DNS exit failed (address family not supported)"),
570                                 1, GNUNET_NO);
571       cleanup_rr (rr);
572       return;
573     }
574     GNUNET_NETWORK_socket_sendto (dnsout,
575                                   rr->payload,
576                                   rr->payload_length,
577                                   (struct sockaddr*) &rr->dst_addr,
578                                   salen);
579     return;
580   case RP_INTERNET_DNS:
581     rr->phase = RP_MODIFY;
582     for (cr = clients_head; NULL != cr; cr = cr->next)
583     {
584       if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
585         GNUNET_array_append (rr->client_wait_list,
586                              rr->client_wait_list_length,
587                              cr);
588     }
589     next_phase (rr);
590     return;
591   case RP_MODIFY:
592     rr->phase = RP_RESPONSE_MONITOR;
593     for (cr = clients_head; NULL != cr; cr = cr->next)
594     {
595       if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
596         GNUNET_array_append (rr->client_wait_list,
597                              rr->client_wait_list_length,
598                              cr);
599     }
600     next_phase (rr);
601     return;
602  case RP_RESPONSE_MONITOR:
603     request_done (rr);
604     break;
605   case RP_DROP:
606     cleanup_rr (rr);
607     break;
608   default:
609     GNUNET_break (0);
610     cleanup_rr (rr);
611     break;
612   }
613 }
614
615
616 /**
617  * A client disconnected, clean up after it.
618  *
619  * @param cls unused
620  * @param client handle of client that disconnected
621  */ 
622 static void
623 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
624 {
625   struct ClientRecord *cr;
626   struct RequestRecord *rr;
627   unsigned int i;
628   unsigned int j;
629
630   for (cr = clients_head; NULL != cr; cr = cr->next)
631   {
632     if (cr->client == client)
633     {
634       GNUNET_SERVER_client_drop (client);
635       GNUNET_CONTAINER_DLL_remove (clients_head,
636                                    clients_tail,
637                                    cr);
638       for (i=0;i<UINT16_MAX;i++)
639       {
640         rr = &requests[i];
641         if (0 == rr->client_wait_list_length)
642           continue; /* not in use */
643         for (j=0;j<rr->client_wait_list_length;j++)
644         {
645           if (rr->client_wait_list[j] == cr)
646           {
647             rr->client_wait_list[j] = NULL;
648             next_phase (rr); 
649           }
650         }
651       }
652       GNUNET_free (cr);
653       return;
654     }
655   }
656 }
657
658
659 /**
660  * Read a DNS response from the (unhindered) UDP-Socket
661  *
662  * @param cls socket to read from
663  * @param tc scheduler context (must be shutdown or read ready)
664  */
665 static void
666 read_response (void *cls,
667                const struct GNUNET_SCHEDULER_TaskContext *tc)
668 {
669   struct GNUNET_NETWORK_Handle *dnsout = cls;
670   struct sockaddr_in addr4;
671   struct sockaddr_in6 addr6;
672   struct sockaddr *addr;
673   struct GNUNET_TUN_DnsHeader *dns;
674   socklen_t addrlen;
675   struct RequestRecord *rr;
676   ssize_t r;
677   int len;
678
679   if (dnsout == dnsout4)
680   {
681     addrlen = sizeof (struct sockaddr_in);
682     addr = (struct sockaddr* ) &addr4;
683     read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
684                                                 dnsout,
685                                                 &read_response, 
686                                                 dnsout);
687   }
688   else
689   {
690     addrlen = sizeof (struct sockaddr_in6);
691     addr = (struct sockaddr* ) &addr6;
692     read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
693                                                 dnsout,
694                                                 &read_response, 
695                                                 dnsout);
696   }
697   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
698     return;
699
700 #ifndef MINGW
701   if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
702   {
703     /* conservative choice: */
704     len = 65536;
705   }
706 #else
707   /* port the code above? */
708   len = 65536;
709 #endif
710
711   {
712     unsigned char buf[len];
713
714     memset (addr, 0, addrlen);  
715     r = GNUNET_NETWORK_socket_recvfrom (dnsout, 
716                                         buf, sizeof (buf),
717                                         addr, &addrlen);
718     if (-1 == r)
719     {
720       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
721       return;
722     }
723     if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
724     {
725       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
726                   _("Received DNS response that is too small (%u bytes)"),
727                   r);
728       return;
729     }
730     dns = (struct GNUNET_TUN_DnsHeader *) buf;
731     rr = &requests[dns->id];
732     if (rr->phase != RP_INTERNET_DNS) 
733     {
734       /* unexpected / bogus reply */
735       GNUNET_STATISTICS_update (stats,
736                                 gettext_noop ("# External DNS response discarded (no matching request)"),
737                                 1, GNUNET_NO);
738       return; 
739     }
740     GNUNET_free_non_null (rr->payload);
741     rr->payload = GNUNET_malloc (len);
742     memcpy (rr->payload, buf, len);
743     rr->payload_length = len;
744     next_phase (rr);
745   }  
746 }
747
748
749 /**
750  * Open source port for sending DNS request on IPv4.
751  *
752  * @return GNUNET_OK on success
753  */ 
754 static int
755 open_port4 ()
756 {
757   struct sockaddr_in addr;
758   socklen_t addrlen;
759
760   dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
761   if (dnsout4 == NULL)
762     return GNUNET_SYSERR;
763
764   memset (&addr, 0, sizeof (struct sockaddr_in));
765   addr.sin_family = AF_INET;
766   int err = GNUNET_NETWORK_socket_bind (dnsout4,
767                                         (struct sockaddr *) &addr,
768                                         sizeof (struct sockaddr_in));
769
770   if (err != GNUNET_OK)
771   {
772     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
773                 _("Could not bind to any port: %s\n"),
774                 STRERROR (errno));
775     GNUNET_NETWORK_socket_close (dnsout4);
776     dnsout4 = NULL;
777     return GNUNET_SYSERR;
778   }
779
780   /* Read the port we bound to */
781   addrlen = sizeof (struct sockaddr_in);
782   if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), 
783                         (struct sockaddr *) &addr,
784                         &addrlen))
785   {
786     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
787                 _("Could not determine port I got: %s\n"),
788                 STRERROR (errno));
789     GNUNET_NETWORK_socket_close (dnsout4);
790     dnsout4 = NULL;
791     return GNUNET_SYSERR;
792   }
793   dnsoutport = htons (addr.sin_port);
794
795   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
796               _("GNUnet DNS will exit on source port %u\n"),
797               (unsigned int) dnsoutport);
798   read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
799                                               dnsout4,
800                                               &read_response, dnsout4);
801   return GNUNET_OK;
802 }
803
804
805 /**
806  * Open source port for sending DNS request on IPv6.  Should be 
807  * called AFTER open_port4.
808  *
809  * @return GNUNET_OK on success
810  */ 
811 static int
812 open_port6 ()
813 {
814   struct sockaddr_in6 addr;
815   socklen_t addrlen;
816
817   dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
818   if (dnsout6 == NULL)
819   {
820     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
821                 _("Could not create IPv6 socket: %s\n"),
822                 STRERROR (errno));
823     return GNUNET_SYSERR;
824   }
825   memset (&addr, 0, sizeof (struct sockaddr_in6));
826   addr.sin6_family = AF_INET6;
827   addr.sin6_port = htons (dnsoutport);
828   int err = GNUNET_NETWORK_socket_bind (dnsout6,
829                                         (struct sockaddr *) &addr,
830                                         sizeof (struct sockaddr_in6));
831
832   if (err != GNUNET_OK)
833   {
834     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835                 _("Could not bind to port %u: %s\n"),
836                 (unsigned int) dnsoutport,
837                 STRERROR (errno));
838     GNUNET_NETWORK_socket_close (dnsout6);
839     dnsout6 = NULL;
840     return GNUNET_SYSERR;
841   }
842   if (0 == dnsoutport)
843   {
844     addrlen = sizeof (struct sockaddr_in6);
845     if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), 
846                           (struct sockaddr *) &addr,
847                           &addrlen))
848     {
849       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
850                   _("Could not determine port I got: %s\n"),
851                   STRERROR (errno));
852       GNUNET_NETWORK_socket_close (dnsout6);
853       dnsout6 = NULL;
854       return GNUNET_SYSERR;
855     }
856   }
857   dnsoutport = htons (addr.sin6_port);
858   read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
859                                               dnsout6,
860                                               &read_response, dnsout6);
861   return GNUNET_YES;
862 }
863
864
865 /**
866  * We got a new client.  Make sure all new DNS requests pass by its desk.
867  *
868  * @param cls unused
869  * @param client the new client
870  * @param message the init message (unused)
871  */
872 static void
873 handle_client_init (void *cls GNUNET_UNUSED, 
874                     struct GNUNET_SERVER_Client *client,
875                     const struct GNUNET_MessageHeader *message)
876 {
877   struct ClientRecord *cr;
878   const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
879
880   cr = GNUNET_malloc (sizeof (struct ClientRecord));
881   cr->client = client;
882   cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);  
883   GNUNET_SERVER_client_keep (client);
884   GNUNET_CONTAINER_DLL_insert (clients_head,
885                                clients_tail,
886                                cr);
887   GNUNET_SERVER_notification_context_add (nc, client);
888   GNUNET_SERVER_receive_done (client, GNUNET_OK);
889 }
890
891
892 /**
893  * We got a response from a client.
894  *
895  * @param cls unused
896  * @param client the client
897  * @param message the response
898  */
899 static void
900 handle_client_response (void *cls GNUNET_UNUSED, 
901                         struct GNUNET_SERVER_Client *client,
902                         const struct GNUNET_MessageHeader *message)
903 {
904   const struct GNUNET_DNS_Response *resp;
905   struct RequestRecord *rr;
906   unsigned int i;
907   uint16_t msize;
908   uint16_t off;
909
910   msize = ntohs (message->size);
911   if (msize < sizeof (struct GNUNET_DNS_Response))
912   {
913     GNUNET_break (0);
914     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
915     return;
916   }
917   resp = (const struct GNUNET_DNS_Response*) message;
918   off = (uint16_t) resp->request_id;
919   rr = &requests[off];
920   if (rr->request_id != resp->request_id)
921   {
922     GNUNET_STATISTICS_update (stats,
923                               gettext_noop ("# Client response discarded (no matching request)"),
924                               1, GNUNET_NO);
925     GNUNET_SERVER_receive_done (client, GNUNET_OK);
926     return;
927   }
928   for (i=0;i<rr->client_wait_list_length;i++)
929   {
930     if (NULL == rr->client_wait_list[i])
931       continue;
932     if (rr->client_wait_list[i]->client != client)
933       continue;
934     rr->client_wait_list[i] = NULL;
935     switch (ntohl (resp->drop_flag))
936     {
937     case 0: /* drop */
938       rr->phase = RP_DROP;
939       break;
940     case 1: /* no change */
941       break;
942     case 2: /* update */
943       msize -= sizeof (struct GNUNET_DNS_Response);
944       if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
945            (RP_REQUEST_MONITOR == rr->phase) ||
946            (RP_RESPONSE_MONITOR == rr->phase) )
947       {
948         GNUNET_break (0);
949         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
950         next_phase (rr); 
951         return;
952       }
953       GNUNET_free_non_null (rr->payload);
954 #if DEBUG_DNS
955       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956                   _("Changing DNS reply according to client specifications\n"));
957 #endif
958       rr->payload = GNUNET_malloc (msize);
959       rr->payload_length = msize;
960       memcpy (rr->payload, &resp[1], msize);
961       if (rr->phase == RP_QUERY)
962       {
963         /* clear wait list, we're moving to MODIFY phase next */
964         GNUNET_array_grow (rr->client_wait_list,
965                            rr->client_wait_list_length,
966                            0);
967       }
968       break;
969     }
970     next_phase (rr); 
971     GNUNET_SERVER_receive_done (client, GNUNET_OK);
972     return;      
973   }
974   /* odd, client was not on our list for the request, that ought
975      to be an error */
976   GNUNET_break (0);
977   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
978 }
979
980
981 /**
982  * Functions with this signature are called whenever a complete
983  * message is received by the tokenizer from the DNS hijack process.
984  *
985  * @param cls closure
986  * @param client identification of the client
987  * @param message the actual message, a DNS request we should handle
988  */
989 static void
990 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
991                          const struct GNUNET_MessageHeader *message)
992 {
993   uint16_t msize;
994   const struct GNUNET_TUN_Layer2PacketHeader *tun;
995   const struct GNUNET_TUN_IPv4Header *ip4;
996   const struct GNUNET_TUN_IPv6Header *ip6;
997   const struct GNUNET_TUN_UdpHeader *udp;
998   const struct GNUNET_TUN_DnsHeader *dns;
999   struct RequestRecord *rr;
1000   struct sockaddr_in *srca4;
1001   struct sockaddr_in6 *srca6;
1002   struct sockaddr_in *dsta4;
1003   struct sockaddr_in6 *dsta6;
1004
1005   msize = ntohs (message->size);
1006   if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1007   {
1008     /* non-IP packet received on TUN!? */
1009     GNUNET_break (0);
1010     return;
1011   }
1012   msize -= sizeof (struct GNUNET_MessageHeader);
1013   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1014   msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1015   switch (ntohs (tun->proto))
1016   {
1017   case ETH_P_IPV4:
1018     ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1019     if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1020          (ip4->version != 4) ||
1021          (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1022          (ntohs(ip4->total_length) != msize) ||
1023          (ip4->protocol != IPPROTO_UDP) )
1024     {
1025       /* non-IP/UDP packet received on TUN (or with options) */
1026       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1027                   _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1028       return;
1029     }
1030     udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1031     msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1032     break;
1033   case ETH_P_IPV6:
1034     ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1035     if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1036          (ip6->version != 6) ||
1037          (ntohs (ip6->payload_length) != msize) ||
1038          (ip6->next_header != IPPROTO_UDP) )
1039     {
1040       /* non-IP/UDP packet received on TUN (or with extensions) */
1041       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1042                   _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1043       return;
1044     }
1045     udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1046     msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1047     break;
1048   default:
1049     /* non-IP packet received on TUN!? */
1050     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1051                 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1052                 (unsigned int) msize,
1053                 ntohs (tun->proto));
1054     return;
1055   }
1056   if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1057   {    
1058     /* non-DNS packet received on TUN, ignore */
1059     GNUNET_STATISTICS_update (stats,
1060                               gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1061                               1, GNUNET_NO);
1062     return;
1063   }
1064   msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1065   dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1066   rr = &requests[dns->id];
1067
1068   /* clean up from previous request */
1069   GNUNET_free_non_null (rr->payload);
1070   rr->payload = NULL;
1071   GNUNET_array_grow (rr->client_wait_list,
1072                      rr->client_wait_list_length,
1073                      0);
1074
1075   /* setup new request */
1076   rr->phase = RP_INIT;
1077   if (ip4->version == 4)
1078   {
1079     srca4 = (struct sockaddr_in*) &rr->src_addr;
1080     dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1081     memset (srca4, 0, sizeof (struct sockaddr_in));
1082     memset (dsta4, 0, sizeof (struct sockaddr_in));
1083     srca4->sin_family = AF_INET;
1084     dsta4->sin_family = AF_INET;
1085     srca4->sin_addr = ip4->source_address;
1086     dsta4->sin_addr = ip4->destination_address;
1087     srca4->sin_port = udp->spt;
1088     dsta4->sin_port = udp->dpt;
1089 #if HAVE_SOCKADDR_IN_SIN_LEN
1090     srca4->sin_len = sizeof (sizeof (struct sockaddr_in));
1091     dsta4->sin_len = sizeof (sizeof (struct sockaddr_in));
1092 #endif
1093   }
1094   else /* ipv6 */
1095   {
1096     srca6 = (struct sockaddr_in6*) &rr->src_addr;
1097     dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1098     memset (srca6, 0, sizeof (struct sockaddr_in6));
1099     memset (dsta6, 0, sizeof (struct sockaddr_in6));
1100     srca6->sin6_family = AF_INET6;
1101     dsta6->sin6_family = AF_INET6;
1102     srca6->sin6_addr = ip6->source_address;
1103     dsta6->sin6_addr = ip6->destination_address;
1104     srca6->sin6_port = udp->spt;
1105     dsta6->sin6_port = udp->dpt;
1106 #if HAVE_SOCKADDR_IN_SIN_LEN
1107     srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1108     dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1109 #endif
1110   }
1111   rr->payload = GNUNET_malloc (msize);
1112   rr->payload_length = msize;
1113   memcpy (rr->payload, dns, msize);
1114   rr->request_id = dns->id | (request_id_gen << 16);
1115   request_id_gen++;
1116
1117   GNUNET_STATISTICS_update (stats,
1118                             gettext_noop ("# DNS requests received via TUN interface"),
1119                             1, GNUNET_NO);
1120   /* start request processing state machine */
1121   next_phase (rr);
1122 }
1123
1124
1125 /**
1126  * @param cls closure
1127  * @param server the initialized server
1128  * @param cfg_ configuration to use
1129  */
1130 static void
1131 run (void *cls, struct GNUNET_SERVER_Handle *server,
1132      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1133 {
1134   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1135     /* callback, cls, type, size */
1136     {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, 
1137      sizeof (struct GNUNET_DNS_Register)},
1138     {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1139     {NULL, NULL, 0, 0}
1140   };
1141   char port_s[6];
1142   char *ifc_name;
1143   char *ipv4addr;
1144   char *ipv4mask;
1145   char *ipv6addr;
1146   char *ipv6prefix;
1147
1148   cfg = cfg_;
1149   stats = GNUNET_STATISTICS_create ("dns", cfg);
1150   nc = GNUNET_SERVER_notification_context_create (server, 1);
1151   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1152                                 cls);
1153   if (GNUNET_YES ==
1154       GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1155   {
1156     if ( (GNUNET_OK != open_port4 ()) &&
1157          (GNUNET_OK != open_port6 ()) )
1158     {
1159       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1160                   _("Failed to open any port to provide DNS exit\n"));
1161       GNUNET_SCHEDULER_shutdown ();
1162       return;
1163     }
1164   }
1165
1166   helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1167   if (GNUNET_SYSERR ==
1168       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1169   {
1170     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1171                 "No entry 'IFNAME' in configuration!\n");
1172     GNUNET_SCHEDULER_shutdown ();
1173     return;
1174   }
1175   helper_argv[1] = ifc_name;
1176   if ( (GNUNET_SYSERR ==
1177         GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1178                                                &ipv6addr)) )
1179   {
1180     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1181                 "No entry 'IPV6ADDR' in configuration!\n");
1182     GNUNET_SCHEDULER_shutdown ();
1183     return;
1184   }
1185   helper_argv[2] = ipv6addr;
1186   if (GNUNET_SYSERR ==
1187       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1188                                              &ipv6prefix))
1189   {
1190     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1191                 "No entry 'IPV6PREFIX' in configuration!\n");
1192     GNUNET_SCHEDULER_shutdown ();
1193     return;
1194   }
1195   helper_argv[3] = ipv6prefix;
1196
1197   if (GNUNET_SYSERR ==
1198       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1199                                              &ipv4addr))
1200   {
1201     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1202                 "No entry 'IPV4ADDR' in configuration!\n");
1203     GNUNET_SCHEDULER_shutdown ();
1204     return;
1205   }
1206   helper_argv[4] = ipv4addr;
1207   if (GNUNET_SYSERR ==
1208       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1209                                              &ipv4mask))
1210   {
1211     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1212                 "No entry 'IPV4MASK' in configuration!\n");
1213     GNUNET_SCHEDULER_shutdown ();
1214     return;
1215   }
1216   helper_argv[5] = ipv4mask;
1217   GNUNET_snprintf (port_s, 
1218                    sizeof (port_s), 
1219                    "%u", 
1220                    (unsigned int) dnsoutport);
1221   helper_argv[6] = GNUNET_strdup (port_s);
1222   helper_argv[7] = NULL;
1223   hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1224                                   helper_argv,
1225                                   &process_helper_messages,
1226                                   NULL);
1227   GNUNET_SERVER_add_handlers (server, handlers);
1228   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1229 }
1230
1231
1232 /**
1233  * The main function for the dns service.
1234  *
1235  * @param argc number of arguments from the command line
1236  * @param argv command line arguments
1237  * @return 0 ok, 1 on error
1238  */
1239 int
1240 main (int argc, char *const *argv)
1241 {
1242   return (GNUNET_OK ==
1243           GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1244                               &run, NULL)) ? 0 : 1;
1245 }
1246
1247
1248 /* end of gnunet-service-dns.c */