GNUnet  0.19.5
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"
48 
52 #define DNS_PORT 53
53 
54 
58 #define LOG(kind, ...) \
59  GNUNET_log_from (kind, "dns", __VA_ARGS__);
60 
61 
66 {
71 
77 
83 
88 
95 
101 
105  RP_DROP
106 };
107 
108 
113 {
118 
123 
128 
133 
137  enum GNUNET_DNS_Flags flags;
138 };
139 
140 
145 {
151 
156  char *payload;
157 
163 
167  struct sockaddr_storage src_addr;
168 
172  struct sockaddr_storage dst_addr;
173 
179  uint64_t request_id;
180 
185 
190 
194  enum RequestPhase phase;
195 };
196 
197 
201 static int global_ret;
202 
206 static const struct GNUNET_CONFIGURATION_Handle *cfg;
207 
212 
217 
221 static char *helper_argv[8];
222 
226 static struct ClientRecord *clients_head;
227 
231 static struct ClientRecord *clients_tail;
232 
236 static struct RequestRecord requests[UINT16_MAX + 1];
237 
241 static uint64_t request_id_gen;
242 
247 
248 
254 static void
256 {
257  GNUNET_free (rr->payload);
258  rr->payload = NULL;
259  rr->payload_length = 0;
262  0);
263 }
264 
265 
271 static void
273 {
274  if (NULL != hijacker)
275  {
277  hijacker = NULL;
278  }
279  for (unsigned int i = 0; i < 8; i++)
281  for (unsigned int i = 0; i <= UINT16_MAX; i++)
282  cleanup_rr (&requests[i]);
283  if (NULL != stats)
284  {
286  GNUNET_NO);
287  stats = NULL;
288  }
289  if (NULL != dnsstub)
290  {
292  dnsstub = NULL;
293  }
294 }
295 
296 
302 static void
304 {
305  struct GNUNET_MessageHeader *hdr;
306  size_t reply_len;
307  uint16_t source_port;
308  uint16_t destination_port;
309 
312  0);
313  if (RP_RESPONSE_MONITOR != rr->phase)
314  {
315  /* no response, drop */
317  "Got no response for request %llu, dropping\n",
318  (unsigned long long) rr->request_id);
319  cleanup_rr (rr);
320  return;
321  }
322 
324  "Transmitting response for request %llu\n",
325  (unsigned long long) rr->request_id);
326  /* send response via hijacker */
327  reply_len = sizeof(struct GNUNET_MessageHeader);
328  reply_len += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
329  switch (rr->src_addr.ss_family)
330  {
331  case AF_INET:
332  reply_len += sizeof(struct GNUNET_TUN_IPv4Header);
333  break;
334 
335  case AF_INET6:
336  reply_len += sizeof(struct GNUNET_TUN_IPv6Header);
337  break;
338 
339  default:
340  GNUNET_break (0);
341  cleanup_rr (rr);
342  return;
343  }
344  reply_len += sizeof(struct GNUNET_TUN_UdpHeader);
345  reply_len += rr->payload_length;
346  if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
347  {
348  /* response too big, drop */
349  GNUNET_break (0); /* how can this be? */
350  cleanup_rr (rr);
351  return;
352  }
353  {
354  char buf[reply_len] GNUNET_ALIGN;
355  size_t off;
356  struct GNUNET_TUN_IPv4Header ip4;
357  struct GNUNET_TUN_IPv6Header ip6;
358 
359  /* first, GNUnet message header */
360  hdr = (struct GNUNET_MessageHeader*) buf;
361  hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
362  hdr->size = htons ((uint16_t) reply_len);
363  off = sizeof(struct GNUNET_MessageHeader);
364 
365  /* first, TUN header */
366  {
368 
369  tun.flags = htons (0);
370  if (rr->src_addr.ss_family == AF_INET)
371  tun.proto = htons (ETH_P_IPV4);
372  else
373  tun.proto = htons (ETH_P_IPV6);
374  GNUNET_memcpy (&buf[off],
375  &tun,
376  sizeof(struct GNUNET_TUN_Layer2PacketHeader));
377  off += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
378  }
379 
380  /* now IP header */
381  switch (rr->src_addr.ss_family)
382  {
383  case AF_INET:
384  {
385  struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
386  struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
387 
388  source_port = dst->sin_port;
389  destination_port = src->sin_port;
391  IPPROTO_UDP,
392  reply_len - off - sizeof(struct
394  &dst->sin_addr,
395  &src->sin_addr);
396  GNUNET_memcpy (&buf[off],
397  &ip4,
398  sizeof(ip4));
399  off += sizeof(ip4);
400  }
401  break;
402 
403  case AF_INET6:
404  {
405  struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
406  struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
407 
408  source_port = dst->sin6_port;
409  destination_port = src->sin6_port;
411  IPPROTO_UDP,
412  reply_len - off - sizeof(struct
414  &dst->sin6_addr,
415  &src->sin6_addr);
416  GNUNET_memcpy (&buf[off],
417  &ip6,
418  sizeof(ip6));
419  off += sizeof(ip6);
420  }
421  break;
422 
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)
436  &udp,
437  rr->payload,
438  rr->payload_length);
439  else
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);
458  hdr,
459  GNUNET_YES,
460  NULL, NULL);
462  gettext_noop (
463  "# DNS requests answered via TUN interface"),
464  1, GNUNET_NO);
465  }
466  /* clean up, we're done */
467  cleanup_rr (rr);
468 }
469 
470 
478 static void
480  struct ClientRecord *cr)
481 {
482  struct GNUNET_MQ_Envelope *env;
483  struct GNUNET_DNS_Request *req;
484 
485  if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >=
487  {
488  GNUNET_break (0);
489  cleanup_rr (rr);
490  return;
491  }
493  "Sending information about request %llu to local client\n",
494  (unsigned long long) rr->request_id);
495  env = GNUNET_MQ_msg_extra (req,
496  rr->payload_length,
498  req->reserved = htonl (0);
499  req->request_id = rr->request_id;
500  GNUNET_memcpy (&req[1],
501  rr->payload,
502  rr->payload_length);
503  GNUNET_MQ_send (cr->mq,
504  env);
505 }
506 
507 
516 static void
517 process_dns_result (void *cls,
518  const struct GNUNET_TUN_DnsHeader *dns,
519  size_t r);
520 
521 
528 static void
530 {
531  struct ClientRecord *cr;
532  int nz;
533 
534  if (rr->phase == RP_DROP)
535  {
536  cleanup_rr (rr);
537  return;
538  }
539  nz = -1;
540  for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
541  {
542  if (NULL != rr->client_wait_list[j])
543  {
544  nz = (int) j;
545  break;
546  }
547  }
548  if (-1 != nz)
549  {
551  rr->client_wait_list[nz]);
552  return;
553  }
554  /* done with current phase, advance! */
556  "Request %llu now in phase %d\n",
557  (unsigned long long) rr->request_id,
558  rr->phase);
559  switch (rr->phase)
560  {
561  case RP_INIT:
563  for (cr = clients_head; NULL != cr; cr = cr->next)
564  {
565  if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
568  cr);
569  }
570  next_phase (rr);
571  return;
572 
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))
580  cr);
581  }
582  next_phase (rr);
583  return;
584 
585  case RP_QUERY:
586 #if 0
587  /* TODO: optionally, use this to forward DNS requests to the
588  * original* DNS server instead of the one we have configured...
589  (but then we need to create a fresh dnsstub for each request
590  * and* manage the timeout) */
591  switch (rr->dst_addr.ss_family)
592  {
593  case AF_INET:
594  salen = sizeof(struct sockaddr_in);
595  sa = (const struct sockaddr *) &rr->dst_addr;
596  break;
597 
598  case AF_INET6:
599  salen = sizeof(struct sockaddr_in6);
600  sa = (const struct sockaddr *) &rr->dst_addr;
601  break;
602 
603  default:
604  GNUNET_assert (0);
605  }
606 #endif
607  rr->phase = RP_INTERNET_DNS;
609  rr->payload,
610  rr->payload_length,
612  NULL);
613  if (NULL == rr->rs)
614  {
616  gettext_noop (
617  "# DNS exit failed (failed to open socket)"),
618  1,
619  GNUNET_NO);
620  cleanup_rr (rr);
621  return;
622  }
623  return;
624 
625  case RP_INTERNET_DNS:
626  rr->phase = RP_MODIFY;
627  for (cr = clients_head; NULL != cr; cr = cr->next)
628  {
629  if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
632  cr);
633  }
634  next_phase (rr);
635  return;
636 
637  case RP_MODIFY:
639  for (cr = clients_head; NULL != cr; cr = cr->next)
640  {
641  if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
644  cr);
645  }
646  next_phase (rr);
647  return;
648 
649  case RP_RESPONSE_MONITOR:
650  request_done (rr);
651  break;
652 
653  case RP_DROP:
654  cleanup_rr (rr);
655  break;
656 
657  default:
658  GNUNET_break (0);
659  cleanup_rr (rr);
660  break;
661  }
662 }
663 
664 
673 static void *
674 client_connect_cb (void *cls,
675  struct GNUNET_SERVICE_Client *client,
676  struct GNUNET_MQ_Handle *mq)
677 {
678  struct ClientRecord *cr = cls;
679 
680  cr = GNUNET_new (struct ClientRecord);
681  cr->client = client;
682  cr->mq = mq;
684  clients_tail,
685  cr);
686  return cr;
687 }
688 
689 
697 static void
700  void *app_ctx)
701 {
702  struct ClientRecord *cr = app_ctx;
703  struct RequestRecord *rr;
704 
706  clients_tail,
707  cr);
708  for (unsigned int i = 0; i < UINT16_MAX; i++)
709  {
710  rr = &requests[i];
711  if (0 == rr->client_wait_list_length)
712  continue; /* not in use */
713  for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
714  {
715  if (rr->client_wait_list[j] == cr)
716  {
717  rr->client_wait_list[j] = NULL;
718  next_phase (rr);
719  }
720  }
721  }
722  GNUNET_free (cr);
723 }
724 
725 
734 static void
736  const struct GNUNET_TUN_DnsHeader *dns,
737  size_t r)
738 {
739  struct RequestRecord *rr;
740 
742  "Processing DNS result from stub resolver\n");
743  GNUNET_assert (NULL == cls);
744  if (NULL == dns)
745  return; /* ignore */
746 
747  rr = &requests[dns->id];
748  if (rr->phase != RP_INTERNET_DNS)
749  {
750  /* unexpected / bogus reply */
752  gettext_noop (
753  "# External DNS response discarded (no matching request)"),
754  1, GNUNET_NO);
756  "Received DNS reply that does not match any pending request. Dropping.\n");
757  return;
758  }
760  "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
761  (unsigned long long) rr->request_id);
762  GNUNET_free (rr->payload);
763  rr->payload = GNUNET_malloc (r);
764  GNUNET_memcpy (rr->payload,
765  dns,
766  r);
767  rr->payload_length = r;
768  next_phase (rr);
769 }
770 
771 
778 static void
780  const struct GNUNET_DNS_Register *reg)
781 {
782  struct ClientRecord *cr = cls;
783 
784  cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
786 }
787 
788 
796 static int
798  const struct GNUNET_DNS_Response *resp)
799 {
800  return GNUNET_OK; /* any payload is acceptable */
801 }
802 
803 
810 static void
812  const struct GNUNET_DNS_Response *resp)
813 {
814  struct ClientRecord *cr = cls;
815  struct RequestRecord *rr;
816  uint16_t msize;
817  uint16_t off;
818 
819  msize = ntohs (resp->header.size);
820  off = (uint16_t) resp->request_id;
821  rr = &requests[off];
823  "Received DNS response with ID %llu from local client!\n",
824  (unsigned long long) resp->request_id);
825  if (rr->request_id != resp->request_id)
826  {
828  gettext_noop (
829  "# Client response discarded (no matching request)"),
830  1,
831  GNUNET_NO);
833  return;
834  }
835  for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
836  {
837  if (NULL == rr->client_wait_list[i])
838  continue;
839  if (rr->client_wait_list[i] != cr)
840  continue;
841  rr->client_wait_list[i] = NULL;
842  switch (ntohl (resp->drop_flag))
843  {
844  case 0: /* drop */
845  rr->phase = RP_DROP;
846  break;
847 
848  case 1: /* no change */
849  break;
850 
851  case 2: /* update */
852  msize -= sizeof(struct GNUNET_DNS_Response);
853  if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
854  (RP_REQUEST_MONITOR == rr->phase) ||
855  (RP_RESPONSE_MONITOR == rr->phase))
856  {
857  GNUNET_break (0);
859  next_phase (rr);
860  return;
861  }
862  GNUNET_free (rr->payload);
864  "Changing DNS reply according to client specifications\n");
865  rr->payload = GNUNET_malloc (msize);
866  rr->payload_length = msize;
867  GNUNET_memcpy (rr->payload, &resp[1], msize);
868  if (rr->phase == RP_QUERY)
869  {
870  /* clear wait list, we're moving to MODIFY phase next */
873  0);
874  }
875  /* if query changed to answer, move past DNS resolution phase... */
876  if ((RP_QUERY == rr->phase) &&
877  (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
878  ( ((struct GNUNET_TUN_DnsFlags*) &(((struct
879  GNUNET_TUN_DnsHeader*) rr->
880  payload)->flags))->
881  query_or_response == 1) )
882  {
883  rr->phase = RP_INTERNET_DNS;
886  0);
887  }
888  break;
889  }
890  next_phase (rr);
892  return;
893  }
894  /* odd, client was not on our list for the request, that ought
895  to be an error */
896  GNUNET_break (0);
898 }
899 
900 
908 static int
910  const struct GNUNET_MessageHeader *message)
911 {
912  uint16_t msize;
913  const struct GNUNET_TUN_Layer2PacketHeader *tun;
914  const struct GNUNET_TUN_IPv4Header *ip4;
915  const struct GNUNET_TUN_IPv6Header *ip6;
916  const struct GNUNET_TUN_UdpHeader *udp;
917  const struct GNUNET_TUN_DnsHeader *dns;
918  struct RequestRecord *rr;
919  struct sockaddr_in *srca4;
920  struct sockaddr_in6 *srca6;
921  struct sockaddr_in *dsta4;
922  struct sockaddr_in6 *dsta6;
923 
925  "Intercepted message via DNS hijacker\n");
926  msize = ntohs (message->size);
927  if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
929  + sizeof(struct GNUNET_TUN_IPv4Header))
930  {
931  /* non-IP packet received on TUN!? */
932  GNUNET_break (0);
933  return GNUNET_OK;
934  }
935  msize -= sizeof(struct GNUNET_MessageHeader);
936  tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
937  msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
938  switch (ntohs (tun->proto))
939  {
940  case ETH_P_IPV4:
941  ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
942  ip6 = NULL; /* make compiler happy */
943  if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
944  (ip4->version != 4) ||
945  (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
946  (ntohs (ip4->total_length) != msize) ||
947  (ip4->protocol != IPPROTO_UDP))
948  {
949  /* non-IP/UDP packet received on TUN (or with options) */
951  _ ("Received malformed IPv4-UDP packet on TUN interface.\n"));
952  return GNUNET_OK;
953  }
954  udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
955  msize -= sizeof(struct GNUNET_TUN_IPv4Header);
956  break;
957 
958  case ETH_P_IPV6:
959  ip4 = NULL; /* make compiler happy */
960  ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
961  if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
962  (ip6->version != 6) ||
963  (ntohs (ip6->payload_length) != msize - sizeof(struct
965  ||
966  (ip6->next_header != IPPROTO_UDP))
967  {
968  /* non-IP/UDP packet received on TUN (or with extensions) */
970  _ ("Received malformed IPv6-UDP packet on TUN interface.\n"));
971  return GNUNET_OK;
972  }
973  udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
974  msize -= sizeof(struct GNUNET_TUN_IPv6Header);
975  break;
976 
977  default:
978  /* non-IP packet received on TUN!? */
980  _ (
981  "Got non-IP packet with %u bytes and protocol %u from TUN\n"),
982  (unsigned int) msize,
983  ntohs (tun->proto));
984  return GNUNET_OK;
985  }
986  if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct
988  ||
989  (DNS_PORT != ntohs (udp->destination_port)))
990  {
991  /* non-DNS packet received on TUN, ignore */
993  _ ("DNS interceptor got non-DNS packet (dropped)\n"));
995  gettext_noop (
996  "# Non-DNS UDP packet received via TUN interface"),
997  1, GNUNET_NO);
998  return GNUNET_OK;
999  }
1000  msize -= sizeof(struct GNUNET_TUN_UdpHeader);
1001  dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1002  rr = &requests[dns->id];
1003 
1004  /* clean up from previous request */
1005  GNUNET_free (rr->payload);
1006  rr->payload = NULL;
1009  0);
1010 
1011  /* setup new request */
1012  rr->phase = RP_INIT;
1013  switch (ntohs (tun->proto))
1014  {
1015  case ETH_P_IPV4:
1016  {
1017  srca4 = (struct sockaddr_in*) &rr->src_addr;
1018  dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1019  memset (srca4, 0, sizeof(struct sockaddr_in));
1020  memset (dsta4, 0, sizeof(struct sockaddr_in));
1021  srca4->sin_family = AF_INET;
1022  dsta4->sin_family = AF_INET;
1023  srca4->sin_addr = ip4->source_address;
1024  dsta4->sin_addr = ip4->destination_address;
1025  srca4->sin_port = udp->source_port;
1026  dsta4->sin_port = udp->destination_port;
1027 #if HAVE_SOCKADDR_IN_SIN_LEN
1028  srca4->sin_len = sizeof(struct sockaddr_in);
1029  dsta4->sin_len = sizeof(struct sockaddr_in);
1030 #endif
1031  }
1032  break;
1033 
1034  case ETH_P_IPV6:
1035  {
1036  srca6 = (struct sockaddr_in6*) &rr->src_addr;
1037  dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1038  memset (srca6, 0, sizeof(struct sockaddr_in6));
1039  memset (dsta6, 0, sizeof(struct sockaddr_in6));
1040  srca6->sin6_family = AF_INET6;
1041  dsta6->sin6_family = AF_INET6;
1042  srca6->sin6_addr = ip6->source_address;
1043  dsta6->sin6_addr = ip6->destination_address;
1044  srca6->sin6_port = udp->source_port;
1045  dsta6->sin6_port = udp->destination_port;
1046 #if HAVE_SOCKADDR_IN_SIN_LEN
1047  srca6->sin6_len = sizeof(struct sockaddr_in6);
1048  dsta6->sin6_len = sizeof(struct sockaddr_in6);
1049 #endif
1050  }
1051  break;
1052 
1053  default:
1054  GNUNET_assert (0);
1055  }
1056  rr->payload = GNUNET_malloc (msize);
1057  rr->payload_length = msize;
1058  GNUNET_memcpy (rr->payload, dns, msize);
1059  rr->request_id = dns->id | (request_id_gen << 16);
1060  request_id_gen++;
1062  "Creating new DNS request %llu\n",
1063  (unsigned long long) rr->request_id);
1065  gettext_noop (
1066  "# DNS requests received via TUN interface"),
1067  1, GNUNET_NO);
1068  /* start request processing state machine */
1069  next_phase (rr);
1070  return GNUNET_OK;
1071 }
1072 
1073 
1079 static void
1080 run (void *cls,
1081  const struct GNUNET_CONFIGURATION_Handle *cfg_,
1083 {
1084  char *ifc_name;
1085  char *ipv4addr;
1086  char *ipv4mask;
1087  char *ipv6addr;
1088  char *ipv6prefix;
1089  char *dns_exit;
1090  char *binary;
1091  int nortsetup;
1092 
1093  cfg = cfg_;
1094  stats = GNUNET_STATISTICS_create ("dns", cfg);
1096  cls);
1097  dnsstub = GNUNET_DNSSTUB_start (128);
1098  /* TODO: support multiple DNS_EXIT servers being configured */
1099  /* TODO: see above TODO on using DNS server from original packet.
1100  Not sure which is best... */
1101  dns_exit = NULL;
1102  if ((GNUNET_OK !=
1104  "dns",
1105  "DNS_EXIT",
1106  &dns_exit)) ||
1107  (GNUNET_OK !=
1109  dns_exit)))
1110  {
1112  "dns",
1113  "DNS_EXIT",
1114  _ ("need a valid IPv4 or IPv6 address\n"));
1115  GNUNET_free (dns_exit);
1116  }
1117  binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns");
1118 
1119  if (GNUNET_YES !=
1121  GNUNET_YES,
1122  NULL)) // TODO: once we have a windows-testcase, add test parameters here
1123  {
1125  _ ("`%s' is not SUID or the path is invalid, "
1126  "will not run DNS interceptor\n"),
1127  binary);
1128  global_ret = 1;
1129  GNUNET_free (binary);
1130  return;
1131  }
1132  GNUNET_free (binary);
1133 
1134  helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1135  if (GNUNET_SYSERR ==
1137  "dns",
1138  "IFNAME",
1139  &ifc_name))
1140  {
1142  "No entry 'IFNAME' in configuration!\n");
1143  GNUNET_free (binary);
1145  return;
1146  }
1147  helper_argv[1] = ifc_name;
1148  if ((GNUNET_SYSERR ==
1150  "dns",
1151  "IPV6ADDR",
1152  &ipv6addr)))
1153  {
1155  "No entry 'IPV6ADDR' in configuration!\n");
1156  GNUNET_free (binary);
1158  return;
1159  }
1160  helper_argv[2] = ipv6addr;
1161  if (GNUNET_SYSERR ==
1163  "dns",
1164  "IPV6PREFIX",
1165  &ipv6prefix))
1166  {
1168  "No entry 'IPV6PREFIX' in configuration!\n");
1169  GNUNET_free (binary);
1171  return;
1172  }
1173  helper_argv[3] = ipv6prefix;
1174 
1175  if (GNUNET_SYSERR ==
1177  "dns",
1178  "IPV4ADDR",
1179  &ipv4addr))
1180  {
1182  "No entry 'IPV4ADDR' in configuration!\n");
1183  GNUNET_free (binary);
1185  return;
1186  }
1187  helper_argv[4] = ipv4addr;
1188  if (GNUNET_SYSERR ==
1189  GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1190  &ipv4mask))
1191  {
1193  "No entry 'IPV4MASK' in configuration!\n");
1194  GNUNET_free (binary);
1196  return;
1197  }
1198  helper_argv[5] = ipv4mask;
1199 
1200  nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1201  "SKIP_ROUTING_SETUP");
1202  if (GNUNET_YES == nortsetup)
1203  helper_argv[6] = GNUNET_strdup ("1");
1204  else
1205  helper_argv[6] = GNUNET_strdup ("0");
1206 
1207  helper_argv[7] = NULL;
1209  binary,
1210  helper_argv,
1212  NULL, NULL);
1213  GNUNET_free (binary);
1214 }
1215 
1216 
1221  ("dns",
1223  &run,
1226  NULL,
1227  GNUNET_MQ_hd_fixed_size (client_init,
1229  struct GNUNET_DNS_Register,
1230  NULL),
1231  GNUNET_MQ_hd_var_size (client_response,
1233  struct GNUNET_DNS_Response,
1234  NULL),
1236 
1237 
1238 /* FIXME: this might need a port on systems without 'getresgid' */
1239 #if HAVE_GETRESGID
1243 void __attribute__ ((constructor))
1244 GNUNET_DNS_init ()
1245 {
1246  gid_t rgid;
1247  gid_t egid;
1248  gid_t sgid;
1249 
1250  if (-1 == getresgid (&rgid,
1251  &egid,
1252  &sgid))
1253  {
1254  fprintf (stderr,
1255  "getresgid failed: %s\n",
1256  strerror (errno));
1257  }
1258  else if (sgid != rgid)
1259  {
1260  if (-1 == setregid (sgid,
1261  sgid))
1262  fprintf (stderr,
1263  "setregid failed: %s\n",
1264  strerror (errno));
1265  }
1266 }
1267 
1268 
1269 #endif
1270 
1271 
1272 /* 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:70
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:75
Constants for network applications operating on top of the CADET service.
API to access the DNS service.
Constants for network protocols.
API to create, modify and access statistics.
#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:613
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:705
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:586
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:526
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:614
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:461
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:537
#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
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#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:304
#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:62
#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 ...
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool 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:562
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:1334
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2330
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2249
@ 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:82
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:160
GNUNET_NETWORK_STRUCT_END 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:47
#define ETH_P_IPV6
Number for IPv6.
#define ETH_P_IPV4
Number for IPv4.
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:191
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
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:125
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:46
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:78
Handle to a message queue.
Definition: mq.c:87
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:252
Handle to a service.
Definition: service.c:118
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?