5dc6641e74d7c3758137230ee42c32baae01b064
[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         ip.traffic_class_h = 0;
423         ip.version  = 6; /* is there a named constant? I couldn't find one */
424         ip.traffic_class_l = 0;
425         ip.flow_label = 0;
426         ip.payload_length = htons ((uint16_t) reply_len);
427         ip.next_header = IPPROTO_UDP;
428         ip.hop_limit = 255; /* or lower? */
429         ip.source_address = dst->sin6_addr;
430         ip.destination_address = src->sin6_addr;
431         udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
432                                                 &ip.source_address, 
433                                                 sizeof (struct in6_addr) * 2);
434         {
435           uint32_t tmp;
436           
437           tmp = htons (rr->payload_length + sizeof (struct GNUNET_TUN_UdpHeader));
438           udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, 
439                                                   &tmp, 
440                                                   sizeof (uint32_t));
441           tmp = htons (IPPROTO_UDP);
442           udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, 
443                                                   &tmp, 
444                                                   sizeof (uint32_t));
445         }
446         memcpy (&buf[off], &ip, sizeof (ip));
447         off += sizeof (ip);
448       }
449       break;
450     default:
451       GNUNET_assert (0);
452     }
453
454     /* now UDP header */
455     {
456       struct GNUNET_TUN_UdpHeader udp;
457
458       udp.spt = spt;
459       udp.dpt = dpt;
460       udp.len = htons (reply_len - off);
461       udp.crc = 0; 
462       udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, 
463                                               &udp, 
464                                               sizeof (udp));
465       udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum, 
466                                               rr->payload,
467                                               rr->payload_length);
468       udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum);
469       memcpy (&buf[off], &udp, sizeof (udp));
470       off += sizeof (udp);
471     }
472     /* now DNS payload */
473     {
474       memcpy (&buf[off], rr->payload, rr->payload_length);
475       off += rr->payload_length;
476     }
477     /* final checks & sending */
478     GNUNET_assert (off == reply_len);
479     GNUNET_HELPER_send (hijacker,
480                         hdr,
481                         GNUNET_YES,
482                         NULL, NULL);
483     GNUNET_STATISTICS_update (stats,
484                               gettext_noop ("# DNS requests answered via TUN interface"),
485                               1, GNUNET_NO);
486   }
487   /* clean up, we're done */
488   cleanup_rr (rr);
489 }
490
491
492 /**
493  * Show the payload of the given request record to the client
494  * (and wait for a response).
495  *
496  * @param rr request to send to client
497  * @param client client to send the response to
498  */
499 static void
500 send_request_to_client (struct RequestRecord *rr,
501                         struct GNUNET_SERVER_Client *client)
502 {
503   char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
504   struct GNUNET_DNS_Request *req;
505
506   if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
507   {
508     GNUNET_break (0);
509     cleanup_rr (rr);
510     return;
511   }
512   req = (struct GNUNET_DNS_Request*) buf;
513   req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
514   req->header.size = htons (sizeof (buf));
515   req->reserved = htonl (0);
516   req->request_id = rr->request_id;
517   memcpy (&req[1], rr->payload, rr->payload_length);
518   GNUNET_SERVER_notification_context_unicast (nc, 
519                                               client,
520                                               &req->header,
521                                               GNUNET_NO);
522 }
523
524
525 /**
526  * A client has completed its processing for this
527  * request.  Move on.
528  *
529  * @param rr request to process further
530  */
531 static void
532 next_phase (struct RequestRecord *rr)
533 {
534   struct ClientRecord *cr;
535   int nz;
536   unsigned int j;
537   struct GNUNET_NETWORK_Handle *dnsout;
538   socklen_t salen;
539
540   if (rr->phase == RP_DROP)
541   {
542     cleanup_rr (rr);
543     return;
544   }
545   nz = -1;
546   for (j=0;j<rr->client_wait_list_length;j++)
547   {
548     if (NULL != rr->client_wait_list[j])
549     {
550       nz = (int) j;
551       break;
552     }
553   }  
554   if (-1 != nz) 
555   {
556     send_request_to_client (rr, rr->client_wait_list[nz]->client);
557     return;
558   }
559   /* done with current phase, advance! */
560   switch (rr->phase)
561   {
562   case RP_INIT:
563     rr->phase = RP_REQUEST_MONITOR;
564     for (cr = clients_head; NULL != cr; cr = cr->next)
565     {
566       if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
567         GNUNET_array_append (rr->client_wait_list,
568                              rr->client_wait_list_length,
569                              cr);
570     }
571     next_phase (rr);
572     return;
573   case RP_REQUEST_MONITOR:
574     rr->phase = RP_QUERY;
575     for (cr = clients_head; NULL != cr; cr = cr->next)
576     {
577       if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
578         GNUNET_array_append (rr->client_wait_list,
579                              rr->client_wait_list_length,
580                              cr);
581     }
582     next_phase (rr);
583     return;
584   case RP_QUERY:
585     rr->phase = RP_INTERNET_DNS;
586     switch (rr->dst_addr.ss_family)
587     {
588     case AF_INET:
589       dnsout = dnsout4;
590       salen = sizeof (struct GNUNET_TUN_IPv4Header);
591       break;
592     case AF_INET6:
593       dnsout = dnsout6;
594       salen = sizeof (struct GNUNET_TUN_IPv6Header);
595       break;
596     default:
597       GNUNET_break (0);
598       cleanup_rr (rr);
599       return;   
600     }
601     if (NULL == dnsout)
602     {
603       GNUNET_STATISTICS_update (stats,
604                                 gettext_noop ("# DNS exit failed (address family not supported)"),
605                                 1, GNUNET_NO);
606       cleanup_rr (rr);
607       return;
608     }
609     GNUNET_NETWORK_socket_sendto (dnsout,
610                                   rr->payload,
611                                   rr->payload_length,
612                                   (struct sockaddr*) &rr->dst_addr,
613                                   salen);
614     return;
615   case RP_INTERNET_DNS:
616     rr->phase = RP_MODIFY;
617     for (cr = clients_head; NULL != cr; cr = cr->next)
618     {
619       if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
620         GNUNET_array_append (rr->client_wait_list,
621                              rr->client_wait_list_length,
622                              cr);
623     }
624     next_phase (rr);
625     return;
626   case RP_MODIFY:
627     rr->phase = RP_RESPONSE_MONITOR;
628     for (cr = clients_head; NULL != cr; cr = cr->next)
629     {
630       if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
631         GNUNET_array_append (rr->client_wait_list,
632                              rr->client_wait_list_length,
633                              cr);
634     }
635     next_phase (rr);
636     return;
637  case RP_RESPONSE_MONITOR:
638     request_done (rr);
639     break;
640   case RP_DROP:
641     cleanup_rr (rr);
642     break;
643   default:
644     GNUNET_break (0);
645     cleanup_rr (rr);
646     break;
647   }
648 }
649
650
651 /**
652  * A client disconnected, clean up after it.
653  *
654  * @param cls unused
655  * @param client handle of client that disconnected
656  */ 
657 static void
658 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
659 {
660   struct ClientRecord *cr;
661   struct RequestRecord *rr;
662   unsigned int i;
663   unsigned int j;
664
665   for (cr = clients_head; NULL != cr; cr = cr->next)
666   {
667     if (cr->client == client)
668     {
669       GNUNET_SERVER_client_drop (client);
670       GNUNET_CONTAINER_DLL_remove (clients_head,
671                                    clients_tail,
672                                    cr);
673       for (i=0;i<UINT16_MAX;i++)
674       {
675         rr = &requests[i];
676         if (0 == rr->client_wait_list_length)
677           continue; /* not in use */
678         for (j=0;j<rr->client_wait_list_length;j++)
679         {
680           if (rr->client_wait_list[j] == cr)
681           {
682             rr->client_wait_list[j] = NULL;
683             next_phase (rr); 
684           }
685         }
686       }
687       GNUNET_free (cr);
688       return;
689     }
690   }
691 }
692
693
694 /**
695  * Read a DNS response from the (unhindered) UDP-Socket
696  *
697  * @param cls socket to read from
698  * @param tc scheduler context (must be shutdown or read ready)
699  */
700 static void
701 read_response (void *cls,
702                const struct GNUNET_SCHEDULER_TaskContext *tc)
703 {
704   struct GNUNET_NETWORK_Handle *dnsout = cls;
705   struct sockaddr_in addr4;
706   struct sockaddr_in6 addr6;
707   struct sockaddr *addr;
708   struct GNUNET_TUN_DnsHeader *dns;
709   socklen_t addrlen;
710   struct RequestRecord *rr;
711   ssize_t r;
712   int len;
713
714   if (dnsout == dnsout4)
715   {
716     addrlen = sizeof (struct sockaddr_in);
717     addr = (struct sockaddr* ) &addr4;
718     read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
719                                                 dnsout,
720                                                 &read_response, 
721                                                 dnsout);
722   }
723   else
724   {
725     addrlen = sizeof (struct sockaddr_in6);
726     addr = (struct sockaddr* ) &addr6;
727     read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
728                                                 dnsout,
729                                                 &read_response, 
730                                                 dnsout);
731   }
732   if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
733     return;
734
735 #ifndef MINGW
736   if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
737   {
738     /* conservative choice: */
739     len = 65536;
740   }
741 #else
742   /* port the code above? */
743   len = 65536;
744 #endif
745
746   {
747     unsigned char buf[len];
748
749     memset (addr, 0, addrlen);  
750     r = GNUNET_NETWORK_socket_recvfrom (dnsout, 
751                                         buf, sizeof (buf),
752                                         addr, &addrlen);
753     if (-1 == r)
754     {
755       GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
756       return;
757     }
758     if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
759     {
760       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
761                   _("Received DNS response that is too small (%u bytes)"),
762                   r);
763       return;
764     }
765     dns = (struct GNUNET_TUN_DnsHeader *) buf;
766     rr = &requests[dns->id];
767     if (rr->phase != RP_INTERNET_DNS) 
768     {
769       /* unexpected / bogus reply */
770       GNUNET_STATISTICS_update (stats,
771                                 gettext_noop ("# External DNS response discarded (no matching request)"),
772                                 1, GNUNET_NO);
773       return; 
774     }
775     GNUNET_free_non_null (rr->payload);
776     rr->payload = GNUNET_malloc (len);
777     memcpy (rr->payload, buf, len);
778     rr->payload_length = len;
779     next_phase (rr);
780   }  
781 }
782
783
784 /**
785  * Open source port for sending DNS request on IPv4.
786  *
787  * @return GNUNET_OK on success
788  */ 
789 static int
790 open_port4 ()
791 {
792   struct sockaddr_in addr;
793   socklen_t addrlen;
794
795   dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
796   if (dnsout4 == NULL)
797     return GNUNET_SYSERR;
798
799   memset (&addr, 0, sizeof (struct sockaddr_in));
800   addr.sin_family = AF_INET;
801   int err = GNUNET_NETWORK_socket_bind (dnsout4,
802                                         (struct sockaddr *) &addr,
803                                         sizeof (struct sockaddr_in));
804
805   if (err != GNUNET_OK)
806   {
807     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
808                 _("Could not bind to any port: %s\n"),
809                 STRERROR (errno));
810     GNUNET_NETWORK_socket_close (dnsout4);
811     dnsout4 = NULL;
812     return GNUNET_SYSERR;
813   }
814
815   /* Read the port we bound to */
816   addrlen = sizeof (struct sockaddr_in);
817   if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4), 
818                         (struct sockaddr *) &addr,
819                         &addrlen))
820   {
821     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
822                 _("Could not determine port I got: %s\n"),
823                 STRERROR (errno));
824     GNUNET_NETWORK_socket_close (dnsout4);
825     dnsout4 = NULL;
826     return GNUNET_SYSERR;
827   }
828   dnsoutport = htons (addr.sin_port);
829
830   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
831               _("GNUnet DNS will exit on source port %u\n"),
832               (unsigned int) dnsoutport);
833   read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, 
834                                               dnsout4,
835                                               &read_response, dnsout4);
836   return GNUNET_OK;
837 }
838
839
840 /**
841  * Open source port for sending DNS request on IPv6.  Should be 
842  * called AFTER open_port4.
843  *
844  * @return GNUNET_OK on success
845  */ 
846 static int
847 open_port6 ()
848 {
849   struct sockaddr_in6 addr;
850   socklen_t addrlen;
851
852   dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
853   if (dnsout6 == NULL)
854   {
855     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
856                 _("Could not create IPv6 socket: %s\n"),
857                 STRERROR (errno));
858     return GNUNET_SYSERR;
859   }
860   memset (&addr, 0, sizeof (struct sockaddr_in6));
861   addr.sin6_family = AF_INET6;
862   addr.sin6_port = htons (dnsoutport);
863   int err = GNUNET_NETWORK_socket_bind (dnsout6,
864                                         (struct sockaddr *) &addr,
865                                         sizeof (struct sockaddr_in6));
866
867   if (err != GNUNET_OK)
868   {
869     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
870                 _("Could not bind to port %u: %s\n"),
871                 (unsigned int) dnsoutport,
872                 STRERROR (errno));
873     GNUNET_NETWORK_socket_close (dnsout6);
874     dnsout6 = NULL;
875     return GNUNET_SYSERR;
876   }
877   if (0 == dnsoutport)
878   {
879     addrlen = sizeof (struct sockaddr_in6);
880     if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6), 
881                           (struct sockaddr *) &addr,
882                           &addrlen))
883     {
884       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 
885                   _("Could not determine port I got: %s\n"),
886                   STRERROR (errno));
887       GNUNET_NETWORK_socket_close (dnsout6);
888       dnsout6 = NULL;
889       return GNUNET_SYSERR;
890     }
891   }
892   dnsoutport = htons (addr.sin6_port);
893   read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
894                                               dnsout6,
895                                               &read_response, dnsout6);
896   return GNUNET_YES;
897 }
898
899
900 /**
901  * We got a new client.  Make sure all new DNS requests pass by its desk.
902  *
903  * @param cls unused
904  * @param client the new client
905  * @param message the init message (unused)
906  */
907 static void
908 handle_client_init (void *cls GNUNET_UNUSED, 
909                     struct GNUNET_SERVER_Client *client,
910                     const struct GNUNET_MessageHeader *message)
911 {
912   struct ClientRecord *cr;
913   const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
914
915   cr = GNUNET_malloc (sizeof (struct ClientRecord));
916   cr->client = client;
917   cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);  
918   GNUNET_SERVER_client_keep (client);
919   GNUNET_CONTAINER_DLL_insert (clients_head,
920                                clients_tail,
921                                cr);
922   GNUNET_SERVER_notification_context_add (nc, client);
923   GNUNET_SERVER_receive_done (client, GNUNET_OK);
924 }
925
926
927 /**
928  * We got a response from a client.
929  *
930  * @param cls unused
931  * @param client the client
932  * @param message the response
933  */
934 static void
935 handle_client_response (void *cls GNUNET_UNUSED, 
936                         struct GNUNET_SERVER_Client *client,
937                         const struct GNUNET_MessageHeader *message)
938 {
939   const struct GNUNET_DNS_Response *resp;
940   struct RequestRecord *rr;
941   unsigned int i;
942   uint16_t msize;
943   uint16_t off;
944
945   msize = ntohs (message->size);
946   if (msize < sizeof (struct GNUNET_DNS_Response))
947   {
948     GNUNET_break (0);
949     GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
950     return;
951   }
952   resp = (const struct GNUNET_DNS_Response*) message;
953   off = (uint16_t) resp->request_id;
954   rr = &requests[off];
955   if (rr->request_id != resp->request_id)
956   {
957     GNUNET_STATISTICS_update (stats,
958                               gettext_noop ("# Client response discarded (no matching request)"),
959                               1, GNUNET_NO);
960     GNUNET_SERVER_receive_done (client, GNUNET_OK);
961     return;
962   }
963   for (i=0;i<rr->client_wait_list_length;i++)
964   {
965     if (NULL == rr->client_wait_list[i])
966       continue;
967     if (rr->client_wait_list[i]->client != client)
968       continue;
969     rr->client_wait_list[i] = NULL;
970     switch (ntohl (resp->drop_flag))
971     {
972     case 0: /* drop */
973       rr->phase = RP_DROP;
974       break;
975     case 1: /* no change */
976       break;
977     case 2: /* update */
978       msize -= sizeof (struct GNUNET_DNS_Response);
979       if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
980            (RP_REQUEST_MONITOR == rr->phase) ||
981            (RP_RESPONSE_MONITOR == rr->phase) )
982       {
983         GNUNET_break (0);
984         GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
985         next_phase (rr); 
986         return;
987       }
988       GNUNET_free_non_null (rr->payload);
989 #if DEBUG_DNS
990       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991                   _("Changing DNS reply according to client specifications\n"));
992 #endif
993       rr->payload = GNUNET_malloc (msize);
994       rr->payload_length = msize;
995       memcpy (rr->payload, &resp[1], msize);
996       if (rr->phase == RP_QUERY)
997       {
998         /* clear wait list, we're moving to MODIFY phase next */
999         GNUNET_array_grow (rr->client_wait_list,
1000                            rr->client_wait_list_length,
1001                            0);
1002       }
1003       break;
1004     }
1005     next_phase (rr); 
1006     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1007     return;      
1008   }
1009   /* odd, client was not on our list for the request, that ought
1010      to be an error */
1011   GNUNET_break (0);
1012   GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1013 }
1014
1015
1016 /**
1017  * Functions with this signature are called whenever a complete
1018  * message is received by the tokenizer from the DNS hijack process.
1019  *
1020  * @param cls closure
1021  * @param client identification of the client
1022  * @param message the actual message, a DNS request we should handle
1023  */
1024 static void
1025 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1026                          const struct GNUNET_MessageHeader *message)
1027 {
1028   uint16_t msize;
1029   const struct GNUNET_TUN_Layer2PacketHeader *tun;
1030   const struct GNUNET_TUN_IPv4Header *ip4;
1031   const struct GNUNET_TUN_IPv6Header *ip6;
1032   const struct GNUNET_TUN_UdpHeader *udp;
1033   const struct GNUNET_TUN_DnsHeader *dns;
1034   struct RequestRecord *rr;
1035   struct sockaddr_in *srca4;
1036   struct sockaddr_in6 *srca6;
1037   struct sockaddr_in *dsta4;
1038   struct sockaddr_in6 *dsta6;
1039
1040   msize = ntohs (message->size);
1041   if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1042   {
1043     /* non-IP packet received on TUN!? */
1044     GNUNET_break (0);
1045     return;
1046   }
1047   msize -= sizeof (struct GNUNET_MessageHeader);
1048   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1049   msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1050   switch (ntohs (tun->proto))
1051   {
1052   case ETH_P_IPV4:
1053     ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1054     if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1055          (ip4->version != 4) ||
1056          (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1057          (ntohs(ip4->total_length) != msize) ||
1058          (ip4->protocol != IPPROTO_UDP) )
1059     {
1060       /* non-IP/UDP packet received on TUN (or with options) */
1061       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1062                   _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1063       return;
1064     }
1065     udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1066     msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1067     break;
1068   case ETH_P_IPV6:
1069     ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1070     if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1071          (ip6->version != 6) ||
1072          (ntohs (ip6->payload_length) != msize) ||
1073          (ip6->next_header != IPPROTO_UDP) )
1074     {
1075       /* non-IP/UDP packet received on TUN (or with extensions) */
1076       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1077                   _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1078       return;
1079     }
1080     udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1081     msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1082     break;
1083   default:
1084     /* non-IP packet received on TUN!? */
1085     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1086                 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1087                 (unsigned int) msize,
1088                 ntohs (tun->proto));
1089     return;
1090   }
1091   if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1092   {    
1093     /* non-DNS packet received on TUN, ignore */
1094     GNUNET_STATISTICS_update (stats,
1095                               gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1096                               1, GNUNET_NO);
1097     return;
1098   }
1099   msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1100   dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1101   rr = &requests[dns->id];
1102
1103   /* clean up from previous request */
1104   GNUNET_free_non_null (rr->payload);
1105   rr->payload = NULL;
1106   GNUNET_array_grow (rr->client_wait_list,
1107                      rr->client_wait_list_length,
1108                      0);
1109
1110   /* setup new request */
1111   rr->phase = RP_INIT;
1112   if (ip4->version == 4)
1113   {
1114     srca4 = (struct sockaddr_in*) &rr->src_addr;
1115     dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1116     memset (srca4, 0, sizeof (struct sockaddr_in));
1117     memset (dsta4, 0, sizeof (struct sockaddr_in));
1118     srca4->sin_family = AF_INET;
1119     dsta4->sin_family = AF_INET;
1120     srca4->sin_addr = ip4->source_address;
1121     dsta4->sin_addr = ip4->destination_address;
1122     srca4->sin_port = udp->spt;
1123     dsta4->sin_port = udp->dpt;
1124 #if HAVE_SOCKADDR_IN_SIN_LEN
1125     srca4->sin_len = sizeof (sizeof (struct sockaddr_in));
1126     dsta4->sin_len = sizeof (sizeof (struct sockaddr_in));
1127 #endif
1128   }
1129   else /* ipv6 */
1130   {
1131     srca6 = (struct sockaddr_in6*) &rr->src_addr;
1132     dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1133     memset (srca6, 0, sizeof (struct sockaddr_in6));
1134     memset (dsta6, 0, sizeof (struct sockaddr_in6));
1135     srca6->sin6_family = AF_INET6;
1136     dsta6->sin6_family = AF_INET6;
1137     srca6->sin6_addr = ip6->source_address;
1138     dsta6->sin6_addr = ip6->destination_address;
1139     srca6->sin6_port = udp->spt;
1140     dsta6->sin6_port = udp->dpt;
1141 #if HAVE_SOCKADDR_IN_SIN_LEN
1142     srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1143     dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1144 #endif
1145   }
1146   rr->payload = GNUNET_malloc (msize);
1147   rr->payload_length = msize;
1148   memcpy (rr->payload, dns, msize);
1149   rr->request_id = dns->id | (request_id_gen << 16);
1150   request_id_gen++;
1151
1152   GNUNET_STATISTICS_update (stats,
1153                             gettext_noop ("# DNS requests received via TUN interface"),
1154                             1, GNUNET_NO);
1155   /* start request processing state machine */
1156   next_phase (rr);
1157 }
1158
1159
1160 /**
1161  * @param cls closure
1162  * @param server the initialized server
1163  * @param cfg_ configuration to use
1164  */
1165 static void
1166 run (void *cls, struct GNUNET_SERVER_Handle *server,
1167      const struct GNUNET_CONFIGURATION_Handle *cfg_)
1168 {
1169   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1170     /* callback, cls, type, size */
1171     {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, 
1172      sizeof (struct GNUNET_DNS_Register)},
1173     {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1174     {NULL, NULL, 0, 0}
1175   };
1176   char port_s[6];
1177   char *ifc_name;
1178   char *ipv4addr;
1179   char *ipv4mask;
1180   char *ipv6addr;
1181   char *ipv6prefix;
1182
1183   cfg = cfg_;
1184   stats = GNUNET_STATISTICS_create ("dns", cfg);
1185   nc = GNUNET_SERVER_notification_context_create (server, 1);
1186   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1187                                 cls);
1188   if (GNUNET_YES ==
1189       GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1190   {
1191     if ( (GNUNET_OK != open_port4 ()) &&
1192          (GNUNET_OK != open_port6 ()) )
1193     {
1194       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1195                   _("Failed to open any port to provide DNS exit\n"));
1196       GNUNET_SCHEDULER_shutdown ();
1197       return;
1198     }
1199   }
1200
1201   helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1202   if (GNUNET_SYSERR ==
1203       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1204   {
1205     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1206                 "No entry 'IFNAME' in configuration!\n");
1207     GNUNET_SCHEDULER_shutdown ();
1208     return;
1209   }
1210   helper_argv[1] = ifc_name;
1211   if ( (GNUNET_SYSERR ==
1212         GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1213                                                &ipv6addr)) )
1214   {
1215     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1216                 "No entry 'IPV6ADDR' in configuration!\n");
1217     GNUNET_SCHEDULER_shutdown ();
1218     return;
1219   }
1220   helper_argv[2] = ipv6addr;
1221   if (GNUNET_SYSERR ==
1222       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1223                                              &ipv6prefix))
1224   {
1225     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1226                 "No entry 'IPV6PREFIX' in configuration!\n");
1227     GNUNET_SCHEDULER_shutdown ();
1228     return;
1229   }
1230   helper_argv[3] = ipv6prefix;
1231
1232   if (GNUNET_SYSERR ==
1233       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1234                                              &ipv4addr))
1235   {
1236     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1237                 "No entry 'IPV4ADDR' in configuration!\n");
1238     GNUNET_SCHEDULER_shutdown ();
1239     return;
1240   }
1241   helper_argv[4] = ipv4addr;
1242   if (GNUNET_SYSERR ==
1243       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1244                                              &ipv4mask))
1245   {
1246     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1247                 "No entry 'IPV4MASK' in configuration!\n");
1248     GNUNET_SCHEDULER_shutdown ();
1249     return;
1250   }
1251   helper_argv[5] = ipv4mask;
1252   GNUNET_snprintf (port_s, 
1253                    sizeof (port_s), 
1254                    "%u", 
1255                    (unsigned int) dnsoutport);
1256   helper_argv[6] = GNUNET_strdup (port_s);
1257   helper_argv[7] = NULL;
1258   hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1259                                   helper_argv,
1260                                   &process_helper_messages,
1261                                   NULL);
1262   GNUNET_SERVER_add_handlers (server, handlers);
1263   GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1264 }
1265
1266
1267 /**
1268  * The main function for the dns service.
1269  *
1270  * @param argc number of arguments from the command line
1271  * @param argv command line arguments
1272  * @return 0 ok, 1 on error
1273  */
1274 int
1275 main (int argc, char *const *argv)
1276 {
1277   return (GNUNET_OK ==
1278           GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1279                               &run, NULL)) ? 0 : 1;
1280 }
1281
1282
1283 /* end of gnunet-service-dns_new.c */