Merge branch 'master' of ssh://gnunet.org/gnunet
[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_SERVICE_Client *client;
131
132   /**
133    * Message queue to talk to @a client.
134    */
135   struct GNUNET_MQ_Handle *mq;
136
137   /**
138    * Flags for the client.
139    */
140   enum GNUNET_DNS_Flags flags;
141
142 };
143
144
145 /**
146  * Entry we keep for each active request.
147  */
148 struct RequestRecord
149 {
150
151   /**
152    * List of clients that still need to see this request (each entry
153    * is set to NULL when the client is done).
154    */
155   struct ClientRecord **client_wait_list;
156
157   /**
158    * Payload of the UDP packet (the UDP payload), can be either query
159    * or already the response.
160    */
161   char *payload;
162
163   /**
164    * Socket we are using to transmit this request (must match if we receive
165    * a response).
166    */
167   struct GNUNET_DNSSTUB_RequestSocket *rs;
168
169   /**
170    * Source address of the original request (for sending response).
171    */
172   struct sockaddr_storage src_addr;
173
174   /**
175    * Destination address of the original request (for potential use as exit).
176    */
177   struct sockaddr_storage dst_addr;
178
179   /**
180    * ID of this request, also basis for hashing.  Lowest 16 bit will
181    * be our message ID when doing a global DNS request and our index
182    * into the 'requests' array.
183    */
184   uint64_t request_id;
185
186   /**
187    * Number of bytes in payload.
188    */
189   size_t payload_length;
190
191   /**
192    * Length of the @e client_wait_list.
193    */
194   unsigned int client_wait_list_length;
195
196   /**
197    * In which phase this this request?
198    */
199   enum RequestPhase phase;
200
201 };
202
203
204 /**
205  * Global return value from 'main'.
206  */
207 static int global_ret;
208
209 /**
210  * The configuration to use
211  */
212 static const struct GNUNET_CONFIGURATION_Handle *cfg;
213
214 /**
215  * Statistics.
216  */
217 static struct GNUNET_STATISTICS_Handle *stats;
218
219 /**
220  * Handle to DNS hijacker helper process ("gnunet-helper-dns").
221  */
222 static struct GNUNET_HELPER_Handle *hijacker;
223
224 /**
225  * Command-line arguments we are giving to the hijacker process.
226  */
227 static char *helper_argv[8];
228
229 /**
230  * Head of DLL of clients we consult.
231  */
232 static struct ClientRecord *clients_head;
233
234 /**
235  * Tail of DLL of clients we consult.
236  */
237 static struct ClientRecord *clients_tail;
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   if (NULL != hijacker)
281   {
282     GNUNET_HELPER_stop (hijacker, GNUNET_NO);
283     hijacker = NULL;
284   }
285   for (unsigned int i=0;i<8;i++)
286     GNUNET_free_non_null (helper_argv[i]);
287   for (unsigned int i=0;i<=UINT16_MAX;i++)
288     cleanup_rr (&requests[i]);
289   if (NULL != stats)
290   {
291     GNUNET_STATISTICS_destroy (stats,
292                                GNUNET_NO);
293     stats = NULL;
294   }
295   if (NULL != dnsstub)
296   {
297     GNUNET_DNSSTUB_stop (dnsstub);
298     dnsstub = 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 source_port;
314   uint16_t destination_port;
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     LOG (GNUNET_ERROR_TYPE_DEBUG,
323          "Got no response for request %llu, dropping\n",
324          (unsigned long long) rr->request_id);
325     cleanup_rr (rr);
326     return;
327   }
328
329   LOG (GNUNET_ERROR_TYPE_DEBUG,
330        "Transmitting response for request %llu\n",
331        (unsigned long long) rr->request_id);
332   /* send response via hijacker */
333   reply_len = sizeof (struct GNUNET_MessageHeader);
334   reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
335   switch (rr->src_addr.ss_family)
336   {
337   case AF_INET:
338     reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
339     break;
340   case AF_INET6:
341     reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
342     break;
343   default:
344     GNUNET_break (0);
345     cleanup_rr (rr);
346     return;
347   }
348   reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
349   reply_len += rr->payload_length;
350   if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
351   {
352     /* response too big, drop */
353     GNUNET_break (0); /* how can this be? */
354     cleanup_rr(rr);
355     return;
356   }
357   {
358     char buf[reply_len] GNUNET_ALIGN;
359     size_t off;
360     struct GNUNET_TUN_IPv4Header ip4;
361     struct GNUNET_TUN_IPv6Header ip6;
362
363     /* first, GNUnet message header */
364     hdr = (struct GNUNET_MessageHeader*) buf;
365     hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
366     hdr->size = htons ((uint16_t) reply_len);
367     off = sizeof (struct GNUNET_MessageHeader);
368
369     /* first, TUN header */
370     {
371       struct GNUNET_TUN_Layer2PacketHeader tun;
372
373       tun.flags = htons (0);
374       if (rr->src_addr.ss_family == AF_INET)
375         tun.proto = htons (ETH_P_IPV4);
376       else
377         tun.proto = htons (ETH_P_IPV6);
378       GNUNET_memcpy (&buf[off],
379                      &tun,
380                      sizeof (struct GNUNET_TUN_Layer2PacketHeader));
381       off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
382     }
383
384     /* now IP header */
385     switch (rr->src_addr.ss_family)
386     {
387     case AF_INET:
388       {
389         struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
390         struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
391
392         source_port = dst->sin_port;
393         destination_port = src->sin_port;
394         GNUNET_TUN_initialize_ipv4_header (&ip4,
395                                            IPPROTO_UDP,
396                                            reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
397                                            &dst->sin_addr,
398                                            &src->sin_addr);
399         GNUNET_memcpy (&buf[off],
400                        &ip4,
401                        sizeof (ip4));
402         off += sizeof (ip4);
403       }
404       break;
405     case AF_INET6:
406       {
407         struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
408         struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
409
410         source_port = dst->sin6_port;
411         destination_port = src->sin6_port;
412         GNUNET_TUN_initialize_ipv6_header (&ip6,
413                                            IPPROTO_UDP,
414                                            reply_len - off - sizeof (struct GNUNET_TUN_IPv6Header),
415                                            &dst->sin6_addr,
416                                            &src->sin6_addr);
417         GNUNET_memcpy (&buf[off],
418                        &ip6,
419                        sizeof (ip6));
420         off += sizeof (ip6);
421       }
422       break;
423     default:
424       GNUNET_assert (0);
425     }
426
427     /* now UDP header */
428     {
429       struct GNUNET_TUN_UdpHeader udp;
430
431       udp.source_port = source_port;
432       udp.destination_port = destination_port;
433       udp.len = htons (reply_len - off);
434       if (AF_INET == rr->src_addr.ss_family)
435         GNUNET_TUN_calculate_udp4_checksum (&ip4,
436                                             &udp,
437                                             rr->payload,
438                                             rr->payload_length);
439       else
440         GNUNET_TUN_calculate_udp6_checksum (&ip6,
441                                             &udp,
442                                             rr->payload,
443                                             rr->payload_length);
444       GNUNET_memcpy (&buf[off],
445                      &udp,
446                      sizeof (udp));
447       off += sizeof (udp);
448     }
449
450     /* now DNS payload */
451     {
452       GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
453       off += rr->payload_length;
454     }
455     /* final checks & sending */
456     GNUNET_assert (off == reply_len);
457     (void) GNUNET_HELPER_send (hijacker,
458                                hdr,
459                                GNUNET_YES,
460                                NULL, NULL);
461     GNUNET_STATISTICS_update (stats,
462                               gettext_noop ("# DNS requests answered via TUN interface"),
463                               1, GNUNET_NO);
464   }
465   /* clean up, we're done */
466   cleanup_rr (rr);
467 }
468
469
470 /**
471  * Show the payload of the given request record to the client
472  * (and wait for a response).
473  *
474  * @param rr request to send to client
475  * @param cr client to send the response to
476  */
477 static void
478 send_request_to_client (struct RequestRecord *rr,
479                         struct ClientRecord *cr)
480 {
481   struct GNUNET_MQ_Envelope *env;
482   struct GNUNET_DNS_Request *req;
483
484   if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
485   {
486     GNUNET_break (0);
487     cleanup_rr (rr);
488     return;
489   }
490   LOG (GNUNET_ERROR_TYPE_DEBUG,
491        "Sending information about request %llu to local client\n",
492        (unsigned long long) rr->request_id);
493   env = GNUNET_MQ_msg_extra (req,
494                              rr->payload_length,
495                              GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
496   req->reserved = htonl (0);
497   req->request_id = rr->request_id;
498   GNUNET_memcpy (&req[1],
499                  rr->payload,
500                  rr->payload_length);
501   GNUNET_MQ_send (cr->mq,
502                   env);
503 }
504
505
506 /**
507  * Callback called from DNSSTUB resolver when a resolution
508  * succeeded.
509  *
510  * @param cls NULL
511  * @param rs the socket that received the response
512  * @param dns the response itself
513  * @param r number of bytes in dns
514  */
515 static void
516 process_dns_result (void *cls,
517                     struct GNUNET_DNSSTUB_RequestSocket *rs,
518                     const struct GNUNET_TUN_DnsHeader *dns,
519                     size_t r);
520
521
522 /**
523  * A client has completed its processing for this
524  * request.  Move on.
525  *
526  * @param rr request to process further
527  */
528 static void
529 next_phase (struct RequestRecord *rr)
530 {
531   struct ClientRecord *cr;
532   int nz;
533   socklen_t salen;
534
535   if (rr->phase == RP_DROP)
536   {
537     cleanup_rr (rr);
538     return;
539   }
540   nz = -1;
541   for (unsigned int j=0;j<rr->client_wait_list_length;j++)
542   {
543     if (NULL != rr->client_wait_list[j])
544     {
545       nz = (int) j;
546       break;
547     }
548   }
549   if (-1 != nz)
550   {
551     send_request_to_client (rr,
552                             rr->client_wait_list[nz]);
553     return;
554   }
555   /* done with current phase, advance! */
556   LOG (GNUNET_ERROR_TYPE_DEBUG,
557        "Request %llu now in phase %d\n",
558        rr->request_id,
559        rr->phase);
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     switch (rr->dst_addr.ss_family)
586     {
587     case AF_INET:
588       salen = sizeof (struct sockaddr_in);
589       break;
590     case AF_INET6:
591       salen = sizeof (struct sockaddr_in6);
592       break;
593     default:
594       GNUNET_assert (0);
595     }
596
597     rr->phase = RP_INTERNET_DNS;
598     rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
599                                      (struct sockaddr*) &rr->dst_addr,
600                                      salen,
601                                      rr->payload,
602                                      rr->payload_length,
603                                      &process_dns_result,
604                                      NULL);
605     if (NULL == rr->rs)
606     {
607       GNUNET_STATISTICS_update (stats,
608                                 gettext_noop ("# DNS exit failed (failed to open socket)"),
609                                 1,
610                                 GNUNET_NO);
611       cleanup_rr (rr);
612       return;
613     }
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 connected, setup our data structures.
653  *
654  * @param cls unused
655  * @param client handle of client that connected
656  * @param mq message queue to talk to @a client
657  * @return our `struct ClientRecord`
658  */
659 static void *
660 client_connect_cb (void *cls,
661                    struct GNUNET_SERVICE_Client *client,
662                    struct GNUNET_MQ_Handle *mq)
663 {
664   struct ClientRecord *cr = cls;
665
666   cr = GNUNET_new (struct ClientRecord);
667   cr->client = client;
668   cr->mq = mq;
669   GNUNET_CONTAINER_DLL_insert (clients_head,
670                                clients_tail,
671                                cr);
672   return cr;
673 }
674
675
676 /**
677  * A client disconnected, clean up after it.
678  *
679  * @param cls unused
680  * @param client handle of client that disconnected
681  * @param app_ctx our `struct ClientRecord`
682  */
683 static void
684 client_disconnect_cb (void *cls,
685                       struct GNUNET_SERVICE_Client *client,
686                       void *app_ctx)
687 {
688   struct ClientRecord *cr = app_ctx;
689   struct RequestRecord *rr;
690
691   GNUNET_CONTAINER_DLL_remove (clients_head,
692                                clients_tail,
693                                cr);
694   for (unsigned int i=0;i<UINT16_MAX;i++)
695   {
696     rr = &requests[i];
697     if (0 == rr->client_wait_list_length)
698       continue; /* not in use */
699     for (unsigned int j=0;j<rr->client_wait_list_length;j++)
700     {
701       if (rr->client_wait_list[j] == cr)
702       {
703         rr->client_wait_list[j] = NULL;
704         next_phase (rr);
705       }
706     }
707   }
708   GNUNET_free (cr);
709 }
710
711
712 /**
713  * Callback called from DNSSTUB resolver when a resolution
714  * succeeded.
715  *
716  * @param cls NULL
717  * @param rs the socket that received the response
718  * @param dns the response itself
719  * @param r number of bytes in dns
720  */
721 static void
722 process_dns_result (void *cls,
723                     struct GNUNET_DNSSTUB_RequestSocket *rs,
724                     const struct GNUNET_TUN_DnsHeader *dns,
725                     size_t r)
726 {
727   struct RequestRecord *rr;
728
729   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730               "Processing DNS result from stub resolver\n");
731   GNUNET_assert (NULL == cls);
732   rr = &requests[dns->id];
733   if ( (rr->phase != RP_INTERNET_DNS) ||
734        (rr->rs != rs) )
735   {
736     /* unexpected / bogus reply */
737     GNUNET_STATISTICS_update (stats,
738                               gettext_noop ("# External DNS response discarded (no matching request)"),
739                               1, GNUNET_NO);
740     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741                 "Received DNS reply that does not match any pending request.  Dropping.\n");
742     return;
743   }
744   LOG (GNUNET_ERROR_TYPE_DEBUG,
745        "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
746        (unsigned long long) rr->request_id);
747   GNUNET_free_non_null (rr->payload);
748   rr->payload = GNUNET_malloc (r);
749   GNUNET_memcpy (rr->payload,
750                  dns,
751                  r);
752   rr->payload_length = r;
753   next_phase (rr);
754 }
755
756
757 /**
758  * We got a new client.  Make sure all new DNS requests pass by its desk.
759  *
760  * @param cls the client
761  * @param reg the init message
762  */
763 static void
764 handle_client_init (void *cls,
765                     const struct GNUNET_DNS_Register *reg)
766 {
767   struct ClientRecord *cr = cls;
768
769   cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
770   GNUNET_SERVICE_client_continue (cr->client);
771 }
772
773
774 /**
775  * Check a response from a client.
776  *
777  * @param cls the client
778  * @param resp the response
779  * @return #GNUNET_OK (always fine)
780  */
781 static int
782 check_client_response (void *cls,
783                        const struct GNUNET_DNS_Response *resp)
784 {
785   return GNUNET_OK; /* any payload is acceptable */
786 }
787
788
789 /**
790  * Handle a response from a client.
791  *
792  * @param cls the client
793  * @param resp the response
794  */
795 static void
796 handle_client_response (void *cls,
797                         const struct GNUNET_DNS_Response *resp)
798 {
799   struct ClientRecord *cr = cls;
800   struct RequestRecord *rr;
801   uint16_t msize;
802   uint16_t off;
803
804   msize = ntohs (resp->header.size);
805   off = (uint16_t) resp->request_id;
806   rr = &requests[off];
807   LOG (GNUNET_ERROR_TYPE_DEBUG,
808        "Received DNS response with ID %llu from local client!\n",
809        (unsigned long long) resp->request_id);
810   if (rr->request_id != resp->request_id)
811   {
812     GNUNET_STATISTICS_update (stats,
813                               gettext_noop ("# Client response discarded (no matching request)"),
814                               1,
815                               GNUNET_NO);
816     GNUNET_SERVICE_client_continue (cr->client);
817     return;
818   }
819   for (unsigned int i=0;i<rr->client_wait_list_length;i++)
820   {
821     if (NULL == rr->client_wait_list[i])
822       continue;
823     if (rr->client_wait_list[i] != cr)
824       continue;
825     rr->client_wait_list[i] = NULL;
826     switch (ntohl (resp->drop_flag))
827     {
828     case 0: /* drop */
829       rr->phase = RP_DROP;
830       break;
831     case 1: /* no change */
832       break;
833     case 2: /* update */
834       msize -= sizeof (struct GNUNET_DNS_Response);
835       if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
836            (RP_REQUEST_MONITOR == rr->phase) ||
837            (RP_RESPONSE_MONITOR == rr->phase) )
838       {
839         GNUNET_break (0);
840         GNUNET_SERVICE_client_drop (cr->client);
841         next_phase (rr);
842         return;
843       }
844       GNUNET_free_non_null (rr->payload);
845       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846                   "Changing DNS reply according to client specifications\n");
847       rr->payload = GNUNET_malloc (msize);
848       rr->payload_length = msize;
849       GNUNET_memcpy (rr->payload, &resp[1], msize);
850       if (rr->phase == RP_QUERY)
851       {
852         /* clear wait list, we're moving to MODIFY phase next */
853         GNUNET_array_grow (rr->client_wait_list,
854                            rr->client_wait_list_length,
855                            0);
856       }
857       /* if query changed to answer, move past DNS resolution phase... */
858       if ( (RP_QUERY == rr->phase) &&
859            (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
860            ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
861       {
862         rr->phase = RP_INTERNET_DNS;
863         GNUNET_array_grow (rr->client_wait_list,
864                            rr->client_wait_list_length,
865                            0);
866       }
867       break;
868     }
869     next_phase (rr);
870     GNUNET_SERVICE_client_continue (cr->client);
871     return;
872   }
873   /* odd, client was not on our list for the request, that ought
874      to be an error */
875   GNUNET_break (0);
876   GNUNET_SERVICE_client_drop (cr->client);
877 }
878
879
880 /**
881  * Functions with this signature are called whenever a complete
882  * message is received by the tokenizer from the DNS hijack process.
883  *
884  * @param cls closure
885  * @param message the actual message, a DNS request we should handle
886  */
887 static int
888 process_helper_messages (void *cls,
889                          const struct GNUNET_MessageHeader *message)
890 {
891   uint16_t msize;
892   const struct GNUNET_TUN_Layer2PacketHeader *tun;
893   const struct GNUNET_TUN_IPv4Header *ip4;
894   const struct GNUNET_TUN_IPv6Header *ip6;
895   const struct GNUNET_TUN_UdpHeader *udp;
896   const struct GNUNET_TUN_DnsHeader *dns;
897   struct RequestRecord *rr;
898   struct sockaddr_in *srca4;
899   struct sockaddr_in6 *srca6;
900   struct sockaddr_in *dsta4;
901   struct sockaddr_in6 *dsta6;
902
903   LOG (GNUNET_ERROR_TYPE_DEBUG,
904        "Intercepted message via DNS hijacker\n");
905   msize = ntohs (message->size);
906   if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
907   {
908     /* non-IP packet received on TUN!? */
909     GNUNET_break (0);
910     return GNUNET_OK;
911   }
912   msize -= sizeof (struct GNUNET_MessageHeader);
913   tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
914   msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
915   switch (ntohs (tun->proto))
916   {
917   case ETH_P_IPV4:
918     ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
919     ip6 = NULL; /* make compiler happy */
920     if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
921          (ip4->version != 4) ||
922          (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
923          (ntohs(ip4->total_length) != msize) ||
924          (ip4->protocol != IPPROTO_UDP) )
925     {
926       /* non-IP/UDP packet received on TUN (or with options) */
927       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
928                   _("Received malformed IPv4-UDP packet on TUN interface.\n"));
929       return GNUNET_OK;
930     }
931     udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
932     msize -= sizeof (struct GNUNET_TUN_IPv4Header);
933     break;
934   case ETH_P_IPV6:
935     ip4 = NULL; /* make compiler happy */
936     ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
937     if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
938          (ip6->version != 6) ||
939          (ntohs (ip6->payload_length) != msize - sizeof (struct GNUNET_TUN_IPv6Header)) ||
940          (ip6->next_header != IPPROTO_UDP) )
941     {
942       /* non-IP/UDP packet received on TUN (or with extensions) */
943       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
944                   _("Received malformed IPv6-UDP packet on TUN interface.\n"));
945       return GNUNET_OK;
946     }
947     udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
948     msize -= sizeof (struct GNUNET_TUN_IPv6Header);
949     break;
950   default:
951     /* non-IP packet received on TUN!? */
952     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
953                 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
954                 (unsigned int) msize,
955                 ntohs (tun->proto));
956     return GNUNET_OK;
957   }
958   if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) ||
959        (DNS_PORT != ntohs (udp->destination_port)) )
960   {
961     /* non-DNS packet received on TUN, ignore */
962     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
963                 _("DNS interceptor got non-DNS packet (dropped)\n"));
964     GNUNET_STATISTICS_update (stats,
965                               gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
966                               1, GNUNET_NO);
967     return GNUNET_OK;
968   }
969   msize -= sizeof (struct GNUNET_TUN_UdpHeader);
970   dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
971   rr = &requests[dns->id];
972
973   /* clean up from previous request */
974   GNUNET_free_non_null (rr->payload);
975   rr->payload = NULL;
976   GNUNET_array_grow (rr->client_wait_list,
977                      rr->client_wait_list_length,
978                      0);
979
980   /* setup new request */
981   rr->phase = RP_INIT;
982   switch (ntohs (tun->proto))
983   {
984   case ETH_P_IPV4:
985     {
986       srca4 = (struct sockaddr_in*) &rr->src_addr;
987       dsta4 = (struct sockaddr_in*) &rr->dst_addr;
988       memset (srca4, 0, sizeof (struct sockaddr_in));
989       memset (dsta4, 0, sizeof (struct sockaddr_in));
990       srca4->sin_family = AF_INET;
991       dsta4->sin_family = AF_INET;
992       srca4->sin_addr = ip4->source_address;
993       dsta4->sin_addr = ip4->destination_address;
994       srca4->sin_port = udp->source_port;
995       dsta4->sin_port = udp->destination_port;
996 #if HAVE_SOCKADDR_IN_SIN_LEN
997       srca4->sin_len = sizeof (struct sockaddr_in);
998       dsta4->sin_len = sizeof (struct sockaddr_in);
999 #endif
1000     }
1001     break;
1002   case ETH_P_IPV6:
1003     {
1004       srca6 = (struct sockaddr_in6*) &rr->src_addr;
1005       dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1006       memset (srca6, 0, sizeof (struct sockaddr_in6));
1007       memset (dsta6, 0, sizeof (struct sockaddr_in6));
1008       srca6->sin6_family = AF_INET6;
1009       dsta6->sin6_family = AF_INET6;
1010       srca6->sin6_addr = ip6->source_address;
1011       dsta6->sin6_addr = ip6->destination_address;
1012       srca6->sin6_port = udp->source_port;
1013       dsta6->sin6_port = udp->destination_port;
1014 #if HAVE_SOCKADDR_IN_SIN_LEN
1015       srca6->sin6_len = sizeof (struct sockaddr_in6);
1016       dsta6->sin6_len = sizeof (struct sockaddr_in6);
1017 #endif
1018     }
1019   break;
1020   default:
1021     GNUNET_assert (0);
1022   }
1023   rr->payload = GNUNET_malloc (msize);
1024   rr->payload_length = msize;
1025   GNUNET_memcpy (rr->payload, dns, msize);
1026   rr->request_id = dns->id | (request_id_gen << 16);
1027   request_id_gen++;
1028   LOG (GNUNET_ERROR_TYPE_DEBUG,
1029        "Creating new DNS request %llu\n",
1030        (unsigned long long) rr->request_id);
1031   GNUNET_STATISTICS_update (stats,
1032                             gettext_noop ("# DNS requests received via TUN interface"),
1033                             1, GNUNET_NO);
1034   /* start request processing state machine */
1035   next_phase (rr);
1036   return GNUNET_OK;
1037 }
1038
1039
1040 /**
1041  * @param cls closure
1042  * @param cfg_ configuration to use
1043  * @param service the initialized service
1044  */
1045 static void
1046 run (void *cls,
1047      const struct GNUNET_CONFIGURATION_Handle *cfg_,
1048      struct GNUNET_SERVICE_Handle *service)
1049 {
1050   char *ifc_name;
1051   char *ipv4addr;
1052   char *ipv4mask;
1053   char *ipv6addr;
1054   char *ipv6prefix;
1055   struct in_addr dns_exit4;
1056   struct in6_addr dns_exit6;
1057   char *dns_exit;
1058   char *binary;
1059   int nortsetup;
1060
1061   cfg = cfg_;
1062   stats = GNUNET_STATISTICS_create ("dns", cfg);
1063   GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1064                                  cls);
1065   dns_exit = NULL;
1066   if ( ( (GNUNET_OK !=
1067           GNUNET_CONFIGURATION_get_value_string (cfg,
1068                                                  "dns",
1069                                                  "DNS_EXIT",
1070                                                  &dns_exit)) ||
1071          ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1072            (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1073   {
1074     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1075                                "dns",
1076                                "DNS_EXIT",
1077                                _("need a valid IPv4 or IPv6 address\n"));
1078     GNUNET_free_non_null (dns_exit);
1079     dns_exit = NULL;
1080   }
1081   dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1082   GNUNET_free_non_null (dns_exit);
1083   binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
1084   if (GNUNET_YES !=
1085       GNUNET_OS_check_helper_binary (binary,
1086                                      GNUNET_YES,
1087                                      NULL)) // TODO: once we have a windows-testcase, add test parameters here
1088   {
1089     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1090                 _("`%s' must be installed SUID, will not run DNS interceptor\n"),
1091                 binary);
1092     global_ret = 1;
1093     GNUNET_free (binary);
1094     return;
1095   }
1096   GNUNET_free (binary);
1097
1098   helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1099   if (GNUNET_SYSERR ==
1100       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1101   {
1102     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1103                 "No entry 'IFNAME' in configuration!\n");
1104     GNUNET_SCHEDULER_shutdown ();
1105     return;
1106   }
1107   helper_argv[1] = ifc_name;
1108   if ( (GNUNET_SYSERR ==
1109         GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1110                                                &ipv6addr)) )
1111   {
1112     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1113                 "No entry 'IPV6ADDR' in configuration!\n");
1114     GNUNET_SCHEDULER_shutdown ();
1115     return;
1116   }
1117   helper_argv[2] = ipv6addr;
1118   if (GNUNET_SYSERR ==
1119       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1120                                              &ipv6prefix))
1121   {
1122     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1123                 "No entry 'IPV6PREFIX' in configuration!\n");
1124     GNUNET_SCHEDULER_shutdown ();
1125     return;
1126   }
1127   helper_argv[3] = ipv6prefix;
1128
1129   if (GNUNET_SYSERR ==
1130       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1131                                              &ipv4addr))
1132   {
1133     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1134                 "No entry 'IPV4ADDR' in configuration!\n");
1135     GNUNET_SCHEDULER_shutdown ();
1136     return;
1137   }
1138   helper_argv[4] = ipv4addr;
1139   if (GNUNET_SYSERR ==
1140       GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1141                                              &ipv4mask))
1142   {
1143     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144                 "No entry 'IPV4MASK' in configuration!\n");
1145     GNUNET_SCHEDULER_shutdown ();
1146     return;
1147   }
1148   helper_argv[5] = ipv4mask;
1149
1150   nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1151                                                      "SKIP_ROUTING_SETUP");
1152   if (GNUNET_YES == nortsetup)
1153     helper_argv[6] = GNUNET_strdup("1");
1154   else
1155     helper_argv[6] = GNUNET_strdup("0");
1156
1157   helper_argv[7] = NULL;
1158   hijacker = GNUNET_HELPER_start (GNUNET_NO,
1159                                   "gnunet-helper-dns",
1160                                   helper_argv,
1161                                   &process_helper_messages,
1162                                   NULL, NULL);
1163 }
1164
1165
1166 /**
1167  * Define "main" method using service macro.
1168  */
1169 GNUNET_SERVICE_MAIN
1170 ("dns",
1171  GNUNET_SERVICE_OPTION_NONE,
1172  &run,
1173  &client_connect_cb,
1174  &client_disconnect_cb,
1175  NULL,
1176  GNUNET_MQ_hd_fixed_size (client_init,
1177                           GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1178                           struct GNUNET_DNS_Register,
1179                           NULL),
1180  GNUNET_MQ_hd_var_size (client_response,
1181                         GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE,
1182                         struct GNUNET_DNS_Response,
1183                         NULL),
1184  GNUNET_MQ_handler_end ());
1185
1186
1187 /* FIXME: this might need a port on systems without 'getresgid' */
1188 #if HAVE_GETRESGID
1189 /**
1190  * Enable use of SGID capabilities on POSIX
1191  */
1192 void __attribute__ ((constructor))
1193 GNUNET_DNS_init ()
1194 {
1195   gid_t rgid;
1196   gid_t egid;
1197   gid_t sgid;
1198
1199   if (-1 == getresgid (&rgid,
1200                        &egid,
1201                        &sgid))
1202   {
1203     fprintf (stderr,
1204              "getresgid failed: %s\n",
1205              strerror (errno));
1206   }
1207   else if (sgid != rgid)
1208   {
1209     if (-1 == setregid (sgid,
1210                         sgid))
1211       fprintf (stderr,
1212                "setregid failed: %s\n",
1213                strerror (errno));
1214   }
1215 }
1216 #endif
1217
1218
1219 /* end of gnunet-service-dns.c */