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