GNUnet  0.11.x
gnunet-service-dns.c
Go to the documentation of this file.
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 
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"
50 #include "gnunet_tun_lib.h"
51 
55 #define DNS_PORT 53
56 
57 
61 #define LOG(kind, ...) \
62  GNUNET_log_from (kind, "dns", __VA_ARGS__);
63 
64 
69 {
74 
80 
86 
91 
98 
104 
108  RP_DROP
109 };
110 
111 
116 {
121 
126 
131 
136 
140  enum GNUNET_DNS_Flags flags;
141 };
142 
143 
148 {
154 
159  char *payload;
160 
166 
170  struct sockaddr_storage src_addr;
171 
175  struct sockaddr_storage dst_addr;
176 
182  uint64_t request_id;
183 
188 
193 
197  enum RequestPhase phase;
198 };
199 
200 
204 static int global_ret;
205 
209 static const struct GNUNET_CONFIGURATION_Handle *cfg;
210 
215 
220 
224 static char *helper_argv[8];
225 
229 static struct ClientRecord *clients_head;
230 
234 static struct ClientRecord *clients_tail;
235 
239 static struct RequestRecord requests[UINT16_MAX + 1];
240 
244 static uint64_t request_id_gen;
245 
250 
251 
257 static void
259 {
260  GNUNET_free (rr->payload);
261  rr->payload = NULL;
262  rr->payload_length = 0;
265  0);
266 }
267 
268 
274 static void
276 {
277  if (NULL != hijacker)
278  {
280  hijacker = NULL;
281  }
282  for (unsigned int i = 0; i < 8; i++)
284  for (unsigned int i = 0; i <= UINT16_MAX; i++)
285  cleanup_rr (&requests[i]);
286  if (NULL != stats)
287  {
289  GNUNET_NO);
290  stats = NULL;
291  }
292  if (NULL != dnsstub)
293  {
295  dnsstub = NULL;
296  }
297 }
298 
299 
305 static void
307 {
308  struct GNUNET_MessageHeader *hdr;
309  size_t reply_len;
310  uint16_t source_port;
311  uint16_t destination_port;
312 
315  0);
316  if (RP_RESPONSE_MONITOR != rr->phase)
317  {
318  /* no response, drop */
320  "Got no response for request %llu, dropping\n",
321  (unsigned long long) rr->request_id);
322  cleanup_rr (rr);
323  return;
324  }
325 
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  {
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;
394  IPPROTO_UDP,
395  reply_len - off - sizeof(struct
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;
414  IPPROTO_UDP,
415  reply_len - off - sizeof(struct
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)
439  &udp,
440  rr->payload,
441  rr->payload_length);
442  else
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);
461  hdr,
462  GNUNET_YES,
463  NULL, NULL);
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 
481 static void
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 >=
490  {
491  GNUNET_break (0);
492  cleanup_rr (rr);
493  return;
494  }
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,
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 
519 static void
520 process_dns_result (void *cls,
521  const struct GNUNET_TUN_DnsHeader *dns,
522  size_t r);
523 
524 
531 static void
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  {
554  rr->client_wait_list[nz]);
555  return;
556  }
557  /* done with current phase, advance! */
559  "Request %llu now in phase %d\n",
560  (unsigned long long) rr->request_id,
561  rr->phase);
562  switch (rr->phase)
563  {
564  case RP_INIT:
566  for (cr = clients_head; NULL != cr; cr = cr->next)
567  {
568  if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
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))
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;
612  rr->payload,
613  rr->payload_length,
615  NULL);
616  if (NULL == rr->rs)
617  {
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))
635  cr);
636  }
637  next_phase (rr);
638  return;
639 
640  case RP_MODIFY:
642  for (cr = clients_head; NULL != cr; cr = cr->next)
643  {
644  if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
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 
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;
687  clients_tail,
688  cr);
689  return cr;
690 }
691 
692 
700 static void
703  void *app_ctx)
704 {
705  struct ClientRecord *cr = app_ctx;
706  struct RequestRecord *rr;
707 
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 
737 static void
739  const struct GNUNET_TUN_DnsHeader *dns,
740  size_t r)
741 {
742  struct RequestRecord *rr;
743 
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 */
755  gettext_noop (
756  "# External DNS response discarded (no matching request)"),
757  1, GNUNET_NO);
759  "Received DNS reply that does not match any pending request. Dropping.\n");
760  return;
761  }
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 (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 
781 static void
783  const struct GNUNET_DNS_Register *reg)
784 {
785  struct ClientRecord *cr = cls;
786 
787  cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
789 }
790 
791 
799 static int
801  const struct GNUNET_DNS_Response *resp)
802 {
803  return GNUNET_OK; /* any payload is acceptable */
804 }
805 
806 
813 static void
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];
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  {
831  gettext_noop (
832  "# Client response discarded (no matching request)"),
833  1,
834  GNUNET_NO);
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);
862  next_phase (rr);
863  return;
864  }
865  GNUNET_free (rr->payload);
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 */
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;
889  0);
890  }
891  break;
892  }
893  next_phase (rr);
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);
901 }
902 
903 
911 static int
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 
928  "Intercepted message via DNS hijacker\n");
929  msize = ntohs (message->size);
930  if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
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) */
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
968  ||
969  (ip6->next_header != IPPROTO_UDP))
970  {
971  /* non-IP/UDP packet received on TUN (or with extensions) */
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!? */
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
991  ||
992  (DNS_PORT != ntohs (udp->destination_port)))
993  {
994  /* non-DNS packet received on TUN, ignore */
996  _ ("DNS interceptor got non-DNS packet (dropped)\n"));
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 (rr->payload);
1009  rr->payload = NULL;
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++;
1065  "Creating new DNS request %llu\n",
1066  (unsigned long long) rr->request_id);
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 
1082 static void
1083 run (void *cls,
1084  const struct GNUNET_CONFIGURATION_Handle *cfg_,
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);
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 !=
1107  "dns",
1108  "DNS_EXIT",
1109  &dns_exit)) ||
1110  (GNUNET_OK !=
1112  dns_exit)))
1113  {
1115  "dns",
1116  "DNS_EXIT",
1117  _ ("need a valid IPv4 or IPv6 address\n"));
1118  GNUNET_free (dns_exit);
1119  }
1120  binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns");
1121 
1122  if (GNUNET_YES !=
1124  GNUNET_YES,
1125  NULL)) // TODO: once we have a windows-testcase, add test parameters here
1126  {
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 ==
1140  "dns",
1141  "IFNAME",
1142  &ifc_name))
1143  {
1145  "No entry 'IFNAME' in configuration!\n");
1146  GNUNET_free (binary);
1148  return;
1149  }
1150  helper_argv[1] = ifc_name;
1151  if ((GNUNET_SYSERR ==
1153  "dns",
1154  "IPV6ADDR",
1155  &ipv6addr)))
1156  {
1158  "No entry 'IPV6ADDR' in configuration!\n");
1159  GNUNET_free (binary);
1161  return;
1162  }
1163  helper_argv[2] = ipv6addr;
1164  if (GNUNET_SYSERR ==
1166  "dns",
1167  "IPV6PREFIX",
1168  &ipv6prefix))
1169  {
1171  "No entry 'IPV6PREFIX' in configuration!\n");
1172  GNUNET_free (binary);
1174  return;
1175  }
1176  helper_argv[3] = ipv6prefix;
1177 
1178  if (GNUNET_SYSERR ==
1180  "dns",
1181  "IPV4ADDR",
1182  &ipv4addr))
1183  {
1185  "No entry 'IPV4ADDR' in configuration!\n");
1186  GNUNET_free (binary);
1188  return;
1189  }
1190  helper_argv[4] = ipv4addr;
1191  if (GNUNET_SYSERR ==
1192  GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1193  &ipv4mask))
1194  {
1196  "No entry 'IPV4MASK' in configuration!\n");
1197  GNUNET_free (binary);
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;
1212  binary,
1213  helper_argv,
1215  NULL, NULL);
1216  GNUNET_free (binary);
1217 }
1218 
1219 
1224  ("dns",
1226  &run,
1229  NULL,
1230  GNUNET_MQ_hd_fixed_size (client_init,
1232  struct GNUNET_DNS_Register,
1233  NULL),
1234  GNUNET_MQ_hd_var_size (client_response,
1236  struct GNUNET_DNS_Response,
1237  NULL),
1239 
1240 
1241 /* FIXME: this might need a port on systems without 'getresgid' */
1242 #if HAVE_GETRESGID
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 */
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
IPC messages between DNS API and DNS service.
#define gettext_noop(String)
Definition: gettext.h:69
static unsigned long long ipv6prefix
IPv6 prefix (0..127) from configuration file.
enum RadiotapType __attribute__
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void next_phase(struct RequestRecord *rr)
A client has completed its processing for this request.
static int process_helper_messages(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer fro...
static void handle_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Handle a response from a client.
static int global_ret
Global return value from 'main'.
RequestPhase
Phases each request goes through.
@ RP_REQUEST_MONITOR
Showing the request to all monitor clients.
@ RP_QUERY
Showing the request to PRE-RESOLUTION clients to find an answer.
@ RP_MODIFY
Client (or global DNS request) has resulted in a response.
@ RP_DROP
Some client has told us to drop the request.
@ RP_INTERNET_DNS
Global Internet query is now pending.
@ RP_INIT
Request has just been received.
@ RP_RESPONSE_MONITOR
Showing the request to all monitor clients.
static void process_dns_result(void *cls, const struct GNUNET_TUN_DnsHeader *dns, size_t r)
Callback called from DNSSTUB resolver when a resolution succeeded.
static struct GNUNET_STATISTICS_Handle * stats
Statistics.
static const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration to use.
static struct GNUNET_HELPER_Handle * hijacker
Handle to DNS hijacker helper process ("gnunet-helper-dns").
static struct GNUNET_DNSSTUB_Context * dnsstub
Handle to the DNS Stub resolver.
static void cleanup_task(void *cls)
Task run during shutdown.
static void request_done(struct RequestRecord *rr)
We're done with some request, finish processing.
static char * helper_argv[8]
Command-line arguments we are giving to the hijacker process.
GNUNET_SERVICE_MAIN("dns", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_fixed_size(client_init, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, struct GNUNET_DNS_Register, NULL), GNUNET_MQ_hd_var_size(client_response, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, struct GNUNET_DNS_Response, NULL), GNUNET_MQ_handler_end())
Define "main" method using service macro.
static struct ClientRecord * clients_head
Head of DLL of clients we consult.
static uint64_t request_id_gen
Generator for unique request IDs.
#define DNS_PORT
Port number for DNS.
static void handle_client_init(void *cls, const struct GNUNET_DNS_Register *reg)
We got a new client.
static int check_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Check a response from a client.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct GNUNET_SERVICE_Handle *service)
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, setup our data structures.
static struct RequestRecord requests[UINT16_MAX+1]
Array of all open requests.
#define LOG(kind,...)
Generic logging shorthand.
static void cleanup_rr(struct RequestRecord *rr)
We're done processing a DNS request, free associated memory.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up after it.
static void send_request_to_client(struct RequestRecord *rr, struct ClientRecord *cr)
Show the payload of the given request record to the client (and wait for a response).
static struct ClientRecord * clients_tail
Tail of DLL of clients we consult.
static char buf[2048]
static int udp
Option -u: UDP requested.
Definition: gnunet-vpn.c:76
#define GNUNET_log(kind,...)
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_UNUSED
gcc-ism to document unused arguments
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
@ GNUNET_OK
Definition: gnunet_common.h:95
@ GNUNET_YES
Definition: gnunet_common.h:97
@ GNUNET_NO
Definition: gnunet_common.h:94
@ GNUNET_SYSERR
Definition: gnunet_common.h:93
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
int GNUNET_DNSSTUB_add_dns_ip(struct GNUNET_DNSSTUB_Context *ctx, const char *dns_ip)
Add nameserver for use by the DNSSTUB.
Definition: dnsstub.c:591
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:690
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:564
struct GNUNET_DNSSTUB_RequestSocket * GNUNET_DNSSTUB_resolve(struct GNUNET_DNSSTUB_Context *ctx, const void *request, size_t request_len, GNUNET_DNSSTUB_ResultCallback rc, void *rc_cls)
Perform DNS resolution using our default IP from init.
Definition: dnsstub.c:504
GNUNET_DNS_Flags
Flags that specify when to call the client's handler.
@ GNUNET_DNS_FLAG_RESPONSE_MONITOR
Set this flag to see all requests just before they are returned to the network.
@ GNUNET_DNS_FLAG_REQUEST_MONITOR
Set this flag to see all requests first prior to resolution (for monitoring).
@ GNUNET_DNS_FLAG_PRE_RESOLUTION
This client should be called on requests that have not yet been resolved as this client provides a re...
@ GNUNET_DNS_FLAG_POST_RESOLUTION
This client wants to be called on the results of a DNS resolution (either resolved by PRE-RESOLUTION ...
struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send(struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, int can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls)
Send an message to the helper.
Definition: helper.c:657
struct GNUNET_HELPER_Handle * GNUNET_HELPER_start(int with_control_pipe, const char *binary_name, char *const binary_argv[], GNUNET_MessageTokenizerCallback cb, GNUNET_HELPER_ExceptionCallback exp_cb, void *cb_cls)
Starts a helper and begins reading from it.
Definition: helper.c:491
void GNUNET_HELPER_stop(struct GNUNET_HELPER_Handle *h, int soft_kill)
Kills the helper, closes the pipe, frees the handle and calls wait() on the helper process.
Definition: helper.c:567
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:355
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:52
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
char * GNUNET_OS_get_suid_binary_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *progname)
Given the name of a helper, service or daemon binary construct the full path to the binary using the ...
int GNUNET_OS_check_helper_binary(const char *binary, int check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_HELPER
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT
Initial message from client to DNS service for registration.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1331
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2325
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2244
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
void GNUNET_TUN_initialize_ipv6_header(struct GNUNET_TUN_IPv6Header *ip, uint8_t protocol, uint16_t payload_length, const struct in6_addr *src, const struct in6_addr *dst)
Initialize an IPv6 header.
Definition: tun.c:81
void GNUNET_TUN_calculate_udp4_checksum(const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv4 UDP checksum.
Definition: tun.c:183
#define ETH_P_IPV6
Number for IPv6.
#define ETH_P_IPV4
Number for IPv4.
void GNUNET_TUN_initialize_ipv4_header(struct GNUNET_TUN_IPv4Header *ip, uint8_t protocol, uint16_t payload_length, const struct in_addr *src, const struct in_addr *dst)
Initialize an IPv4 header.
Definition: tun.c:46
void GNUNET_TUN_calculate_udp6_checksum(const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv6 UDP checksum.
Definition: tun.c:222
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
Entry we keep for each client.
struct ClientRecord * prev
Kept in doubly-linked list.
struct GNUNET_MQ_Handle * mq
Message queue to talk to client.
enum GNUNET_DNS_Flags flags
Flags for the client.
struct GNUNET_SERVICE_Client * client
Handle to the client.
struct ClientRecord * next
Kept in doubly-linked list.
Handle to the stub resolver.
Definition: dnsstub.c:124
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:45
Message from client to DNS service to register itself.
Definition: dns.h:36
uint32_t flags
NBO encoding of enum GNUNET_DNS_Flags for the client.
Definition: dns.h:45
Message from DNS service to client: please handle a request.
Definition: dns.h:53
uint32_t reserved
Always zero.
Definition: dns.h:62
uint64_t request_id
Unique request ID.
Definition: dns.h:67
Message from client to DNS service: here is my reply.
Definition: dns.h:77
struct GNUNET_MessageHeader header
Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE.
Definition: dns.h:81
uint32_t drop_flag
Zero to drop, 1 for no change (no payload), 2 for update (message has payload).
Definition: dns.h:86
uint64_t request_id
Unique request ID.
Definition: dns.h:91
The handle to a helper process.
Definition: helper.c:79
Handle to a message queue.
Definition: mq.c:86
Header for all communications.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
Handle to a client that is connected to a service.
Definition: service.c:251
Handle to a service.
Definition: service.c:117
Handle for the service.
DNS flags (largely RFC 1035 / RFC 2136).
uint16_t id
Unique identifier for the request/response.
Standard IPv4 header.
uint16_t total_length
Length of the packet, including this header.
uint8_t protocol
L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP.
struct in_addr source_address
Origin of the packet.
struct in_addr destination_address
Destination of the packet.
unsigned int header_length
Standard IPv6 header.
struct in6_addr source_address
Origin of the packet.
uint8_t next_header
For example, IPPROTO_UDP or IPPROTO_TCP.
struct in6_addr destination_address
Destination of the packet.
uint16_t payload_length
Length of the payload, excluding this header.
Header from Linux TUN interface.
uint16_t proto
Here we get an ETH_P_-number.
uint16_t flags
Some flags (unused).
UDP packet header.
uint16_t destination_port
Destination port (in NBO).
uint16_t source_port
Source port (in NBO).
Entry we keep for each active request.
struct sockaddr_storage src_addr
Source address of the original request (for sending response).
char * payload
Payload of the UDP packet (the UDP payload), can be either query or already the response.
uint64_t request_id
ID of this request, also basis for hashing.
unsigned int client_wait_list_length
Length of the client_wait_list.
struct sockaddr_storage dst_addr
Destination address of the original request (for potential use as exit).
size_t payload_length
Number of bytes in payload.
struct ClientRecord ** client_wait_list
List of clients that still need to see this request (each entry is set to NULL when the client is don...
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket we are using to transmit this request (must match if we receive a response).
enum RequestPhase phase
In which phase this this request?