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