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 
109 };
110 
111 
116 {
121 
126 
131 
136 
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 
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 {
261  rr->payload = NULL;
262  rr->payload_length = 0;
265  0);
266 }
267 
268 
274 static void
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++)
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  {
294  GNUNET_DNSSTUB_stop (dnsstub);
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;
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);
460  (void) GNUNET_HELPER_send (hijacker,
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  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;
611  rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
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,
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 
700 static void
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 
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);
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  }
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 */
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);
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 
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 !=
1111  GNUNET_DNSSTUB_add_dns_ip (dnsstub,
1112  dns_exit)))
1113  {
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 !=
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;
1211  hijacker = GNUNET_HELPER_start (GNUNET_NO,
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
1243 
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 */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
size_t payload_length
Number of bytes in payload.
uint32_t flags
NBO encoding of enum GNUNET_DNS_Flags for the client.
Definition: dns.h:45
static int check_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Check a response from a client.
unsigned int header_length
struct in6_addr source_address
Origin of the packet.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static int udp
Option -u: UDP requested.
Definition: gnunet-vpn.c:76
static unsigned int phase
Processing stage that we are in.
Definition: gnunet-arm.c:114
DNS flags (largely RFC 1035 / RFC 2136).
char * payload
Payload of the UDP packet (the UDP payload), can be either query or already the response.
uint16_t proto
Here we get an ETH_P_-number.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
static uint64_t request_id_gen
Generator for unique request IDs.
struct in6_addr destination_address
Destination of the packet.
struct GNUNET_MessageHeader header
Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE.
Definition: dns.h:81
Handle to a service.
Definition: service.c:116
struct in_addr destination_address
Destination of the packet.
#define GNUNET_UNUSED
gcc-ism to document unused arguments
The handle to a helper process.
Definition: helper.c:78
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:489
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, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1300
struct ClientRecord * next
Kept in doubly-linked list.
static struct GNUNET_DNSSTUB_Context * dnsstub
Handle to the DNS Stub resolver.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
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).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:690
This client wants to be called on the results of a DNS resolution (either resolved by PRE-RESOLUTION ...
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_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:565
UDP packet header.
#define ETH_P_IPV6
Number for IPv6.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST
Type of messages between the gnunet-helper-dns and the service.
Set this flag to see all requests just before they are returned to the network.
struct sockaddr_storage src_addr
Source address of the original request (for sending response).
Message from client to DNS service: here is my reply.
Definition: dns.h:76
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
Standard IPv4 header.
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
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_new(type)
Allocate a struct or union of the given type.
uint16_t flags
Some flags (unused).
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
static char * helper_argv[8]
Command-line arguments we are giving to the hijacker process.
#define DNS_PORT
Port number for DNS.
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.
#define LOG(kind,...)
Generic logging shorthand.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
uint16_t destination_port
Destination port (in NBO).
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
uint16_t len
Number of bytes of payload.
RequestPhase
Phases each request goes through.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:526
Handle for the service.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
static struct ClientRecord * clients_head
Head of DLL of clients we consult.
struct GNUNET_MQ_Handle * mq
Message queue to talk to client.
Showing the request to all monitor clients.
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
uint16_t id
Unique identifier for the request/response.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
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
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 unsigned long long ipv6prefix
IPv6 prefix (0..127) from configuration file.
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
Handle to a client that is connected to a service.
Definition: service.c:250
enum RequestPhase phase
In which phase this this request?
#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
static void handle_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Handle a response from a client.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE
Type of messages between the gnunet-helper-dns and the service.
static struct GNUNET_HELPER_Handle * hijacker
Handle to DNS hijacker helper process ("gnunet-helper-dns").
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT
Initial message from client to DNS service for registration.
Showing the request to all monitor clients.
enum GNUNET_DNS_Flags flags
Flags for the client.
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
Global Internet query is now pending.
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:564
Message from client to DNS service to register itself.
Definition: dns.h:35
static void cleanup_rr(struct RequestRecord *rr)
We&#39;re done processing a DNS request, free associated memory.
static const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration to use.
static char buf[2048]
Entry we keep for each active request.
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 ...
static struct GNUNET_STATISTICS_Handle * stats
Statistics.
uint64_t request_id
Unique request ID.
Definition: dns.h:67
Entry we keep for each client.
unsigned int client_wait_list_length
Length of the client_wait_list.
uint64_t request_id
ID of this request, also basis for hashing.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2324
Handle to the stub resolver.
Definition: dnsstub.c:123
Header from Linux TUN interface.
uint8_t next_header
For example, IPPROTO_UDP or IPPROTO_TCP.
int 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.
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
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
uint64_t request_id
Unique request ID.
Definition: dns.h:91
uint32_t reserved
Always zero.
Definition: dns.h:62
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static unsigned long long payload
How much data are we currently storing in the database?
static struct ClientRecord * clients_tail
Tail of DLL of clients we consult.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
Set this flag to see all requests first prior to resolution (for monitoring).
Standard IPv6 header.
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...
#define GNUNET_MESSAGE_TYPE_DNS_HELPER
Type of messages between the gnunet-helper-dns and the service.
uint8_t protocol
L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP.
uint16_t source_port
Source port (in NBO).
Handle to a message queue.
Definition: mq.c:85
struct ClientRecord * prev
Kept in doubly-linked list.
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, setup our data structures.
enum RadiotapType __attribute__
static void request_done(struct RequestRecord *rr)
We&#39;re done with some request, finish processing.
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to &#39;struct&#39;s...
struct sockaddr_storage dst_addr
Destination address of the original request (for potential use as exit).
configuration data
Definition: configuration.c:85
Message from DNS service to client: please handle a request.
Definition: dns.h:52
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:655
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...
#define GNUNET_log(kind,...)
static void cleanup_task(void *cls)
Task run during shutdown.
static void handle_client_init(void *cls, const struct GNUNET_DNS_Register *reg)
We got a new client.
uint16_t payload_length
Length of the payload, excluding this header.
Request has just been received.
This client should be called on requests that have not yet been resolved as this client provides a re...
struct in_addr source_address
Origin of the packet.
Header for all communications.
static struct RequestRecord requests[UINT16_MAX+1]
Array of all open requests.
#define GNUNET_YES
Definition: gnunet_common.h:77
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:353
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:44
static int global_ret
Global return value from &#39;main&#39;.
int 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".
static void next_phase(struct RequestRecord *rr)
A client has completed its processing for this request.
struct GNUNET_SERVICE_Client * client
Handle to the client.
Some client has told us to drop the request.
GNUNET_DNS_Flags
Flags that specify when to call the client&#39;s handler.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up after it.
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2243
Showing the request to PRE-RESOLUTION clients to find an answer.
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
uint32_t drop_flag
Zero to drop, 1 for no change (no payload), 2 for update (message has payload).
Definition: dns.h:86
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define ETH_P_IPV4
Number for IPv4.
#define GNUNET_malloc(size)
Wrapper around malloc.
IPC messages between DNS API and DNS service.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket we are using to transmit this request (must match if we receive a response).
#define gettext_noop(String)
Definition: gettext.h:69
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct GNUNET_SERVICE_Handle *service)
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.
Client (or global DNS request) has resulted in a response.