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