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