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