GNUnet  0.10.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 
73 
79 
85 
90 
97 
103 
108 };
109 
110 
114 struct ClientRecord {
119 
124 
129 
134 
139 };
140 
141 
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 
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 {
258  rr->payload = NULL;
259  rr->payload_length = 0;
262  0);
263 }
264 
265 
271 static void
273 {
274  if (NULL != hijacker)
275  {
276  GNUNET_HELPER_stop(hijacker, GNUNET_NO);
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  {
291  GNUNET_DNSSTUB_stop(dnsstub);
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 GNUNET_TUN_IPv4Header),
393  &dst->sin_addr,
394  &src->sin_addr);
395  GNUNET_memcpy(&buf[off],
396  &ip4,
397  sizeof(ip4));
398  off += sizeof(ip4);
399  }
400  break;
401 
402  case AF_INET6:
403  {
404  struct sockaddr_in6 *src = (struct sockaddr_in6 *)&rr->src_addr;
405  struct sockaddr_in6 *dst = (struct sockaddr_in6 *)&rr->dst_addr;
406 
407  source_port = dst->sin6_port;
408  destination_port = src->sin6_port;
410  IPPROTO_UDP,
411  reply_len - off - sizeof(struct GNUNET_TUN_IPv6Header),
412  &dst->sin6_addr,
413  &src->sin6_addr);
414  GNUNET_memcpy(&buf[off],
415  &ip6,
416  sizeof(ip6));
417  off += sizeof(ip6);
418  }
419  break;
420 
421  default:
422  GNUNET_assert(0);
423  }
424 
425  /* now UDP header */
426  {
427  struct GNUNET_TUN_UdpHeader udp;
428 
429  udp.source_port = source_port;
431  udp.len = htons(reply_len - off);
432  if (AF_INET == rr->src_addr.ss_family)
434  &udp,
435  rr->payload,
436  rr->payload_length);
437  else
439  &udp,
440  rr->payload,
441  rr->payload_length);
442  GNUNET_memcpy(&buf[off],
443  &udp,
444  sizeof(udp));
445  off += sizeof(udp);
446  }
447 
448  /* now DNS payload */
449  {
450  GNUNET_memcpy(&buf[off], rr->payload, rr->payload_length);
451  off += rr->payload_length;
452  }
453  /* final checks & sending */
454  GNUNET_assert(off == reply_len);
455  (void)GNUNET_HELPER_send(hijacker,
456  hdr,
457  GNUNET_YES,
458  NULL, NULL);
460  gettext_noop("# DNS requests answered via TUN interface"),
461  1, GNUNET_NO);
462  }
463  /* clean up, we're done */
464  cleanup_rr(rr);
465 }
466 
467 
475 static void
477  struct ClientRecord *cr)
478 {
479  struct GNUNET_MQ_Envelope *env;
480  struct GNUNET_DNS_Request *req;
481 
482  if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
483  {
484  GNUNET_break(0);
485  cleanup_rr(rr);
486  return;
487  }
489  "Sending information about request %llu to local client\n",
490  (unsigned long long)rr->request_id);
491  env = GNUNET_MQ_msg_extra(req,
492  rr->payload_length,
494  req->reserved = htonl(0);
495  req->request_id = rr->request_id;
496  GNUNET_memcpy(&req[1],
497  rr->payload,
498  rr->payload_length);
499  GNUNET_MQ_send(cr->mq,
500  env);
501 }
502 
503 
512 static void
513 process_dns_result(void *cls,
514  const struct GNUNET_TUN_DnsHeader *dns,
515  size_t r);
516 
517 
524 static void
526 {
527  struct ClientRecord *cr;
528  int nz;
529 
530  if (rr->phase == RP_DROP)
531  {
532  cleanup_rr(rr);
533  return;
534  }
535  nz = -1;
536  for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
537  {
538  if (NULL != rr->client_wait_list[j])
539  {
540  nz = (int)j;
541  break;
542  }
543  }
544  if (-1 != nz)
545  {
547  rr->client_wait_list[nz]);
548  return;
549  }
550  /* done with current phase, advance! */
552  "Request %llu now in phase %d\n",
553  rr->request_id,
554  rr->phase);
555  switch (rr->phase)
556  {
557  case RP_INIT:
559  for (cr = clients_head; NULL != cr; cr = cr->next)
560  {
561  if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
564  cr);
565  }
566  next_phase(rr);
567  return;
568 
569  case RP_REQUEST_MONITOR:
570  rr->phase = RP_QUERY;
571  for (cr = clients_head; NULL != cr; cr = cr->next)
572  {
573  if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
576  cr);
577  }
578  next_phase(rr);
579  return;
580 
581  case RP_QUERY:
582 #if 0
583  /* TODO: optionally, use this to forward DNS requests to the
584  * original* DNS server instead of the one we have configured...
585  (but then we need to create a fresh dnsstub for each request
586  * and* manage the timeout) */
587  switch (rr->dst_addr.ss_family)
588  {
589  case AF_INET:
590  salen = sizeof(struct sockaddr_in);
591  sa = (const struct sockaddr *)&rr->dst_addr;
592  break;
593 
594  case AF_INET6:
595  salen = sizeof(struct sockaddr_in6);
596  sa = (const struct sockaddr *)&rr->dst_addr;
597  break;
598 
599  default:
600  GNUNET_assert(0);
601  }
602 #endif
603  rr->phase = RP_INTERNET_DNS;
604  rr->rs = GNUNET_DNSSTUB_resolve(dnsstub,
605  rr->payload,
606  rr->payload_length,
608  NULL);
609  if (NULL == rr->rs)
610  {
612  gettext_noop("# DNS exit failed (failed to open socket)"),
613  1,
614  GNUNET_NO);
615  cleanup_rr(rr);
616  return;
617  }
618  return;
619 
620  case RP_INTERNET_DNS:
621  rr->phase = RP_MODIFY;
622  for (cr = clients_head; NULL != cr; cr = cr->next)
623  {
624  if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
627  cr);
628  }
629  next_phase(rr);
630  return;
631 
632  case RP_MODIFY:
634  for (cr = clients_head; NULL != cr; cr = cr->next)
635  {
636  if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
639  cr);
640  }
641  next_phase(rr);
642  return;
643 
644  case RP_RESPONSE_MONITOR:
645  request_done(rr);
646  break;
647 
648  case RP_DROP:
649  cleanup_rr(rr);
650  break;
651 
652  default:
653  GNUNET_break(0);
654  cleanup_rr(rr);
655  break;
656  }
657 }
658 
659 
668 static void *
671  struct GNUNET_MQ_Handle *mq)
672 {
673  struct ClientRecord *cr = cls;
674 
675  cr = GNUNET_new(struct ClientRecord);
676  cr->client = client;
677  cr->mq = mq;
678  GNUNET_CONTAINER_DLL_insert(clients_head,
679  clients_tail,
680  cr);
681  return cr;
682 }
683 
684 
692 static void
695  void *app_ctx)
696 {
697  struct ClientRecord *cr = app_ctx;
698  struct RequestRecord *rr;
699 
700  GNUNET_CONTAINER_DLL_remove(clients_head,
701  clients_tail,
702  cr);
703  for (unsigned int i = 0; i < UINT16_MAX; i++)
704  {
705  rr = &requests[i];
706  if (0 == rr->client_wait_list_length)
707  continue; /* not in use */
708  for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
709  {
710  if (rr->client_wait_list[j] == cr)
711  {
712  rr->client_wait_list[j] = NULL;
713  next_phase(rr);
714  }
715  }
716  }
717  GNUNET_free(cr);
718 }
719 
720 
729 static void
731  const struct GNUNET_TUN_DnsHeader *dns,
732  size_t r)
733 {
734  struct RequestRecord *rr;
735 
737  "Processing DNS result from stub resolver\n");
738  GNUNET_assert(NULL == cls);
739  if (NULL == dns)
740  return; /* ignore */
741 
742  rr = &requests[dns->id];
743  if (rr->phase != RP_INTERNET_DNS)
744  {
745  /* unexpected / bogus reply */
747  gettext_noop("# External DNS response discarded (no matching request)"),
748  1, GNUNET_NO);
750  "Received DNS reply that does not match any pending request. Dropping.\n");
751  return;
752  }
754  "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
755  (unsigned long long)rr->request_id);
757  rr->payload = GNUNET_malloc(r);
759  dns,
760  r);
761  rr->payload_length = r;
762  next_phase(rr);
763 }
764 
765 
772 static void
774  const struct GNUNET_DNS_Register *reg)
775 {
776  struct ClientRecord *cr = cls;
777 
778  cr->flags = (enum GNUNET_DNS_Flags)ntohl(reg->flags);
780 }
781 
782 
790 static int
792  const struct GNUNET_DNS_Response *resp)
793 {
794  return GNUNET_OK; /* any payload is acceptable */
795 }
796 
797 
804 static void
806  const struct GNUNET_DNS_Response *resp)
807 {
808  struct ClientRecord *cr = cls;
809  struct RequestRecord *rr;
810  uint16_t msize;
811  uint16_t off;
812 
813  msize = ntohs(resp->header.size);
814  off = (uint16_t)resp->request_id;
815  rr = &requests[off];
817  "Received DNS response with ID %llu from local client!\n",
818  (unsigned long long)resp->request_id);
819  if (rr->request_id != resp->request_id)
820  {
822  gettext_noop("# Client response discarded (no matching request)"),
823  1,
824  GNUNET_NO);
826  return;
827  }
828  for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
829  {
830  if (NULL == rr->client_wait_list[i])
831  continue;
832  if (rr->client_wait_list[i] != cr)
833  continue;
834  rr->client_wait_list[i] = NULL;
835  switch (ntohl(resp->drop_flag))
836  {
837  case 0: /* drop */
838  rr->phase = RP_DROP;
839  break;
840 
841  case 1: /* no change */
842  break;
843 
844  case 2: /* update */
845  msize -= sizeof(struct GNUNET_DNS_Response);
846  if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
847  (RP_REQUEST_MONITOR == rr->phase) ||
848  (RP_RESPONSE_MONITOR == rr->phase))
849  {
850  GNUNET_break(0);
852  next_phase(rr);
853  return;
854  }
857  "Changing DNS reply according to client specifications\n");
858  rr->payload = GNUNET_malloc(msize);
859  rr->payload_length = msize;
860  GNUNET_memcpy(rr->payload, &resp[1], msize);
861  if (rr->phase == RP_QUERY)
862  {
863  /* clear wait list, we're moving to MODIFY phase next */
866  0);
867  }
868  /* if query changed to answer, move past DNS resolution phase... */
869  if ((RP_QUERY == rr->phase) &&
870  (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
871  ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*)rr->payload)->flags))->query_or_response == 1)
872  {
873  rr->phase = RP_INTERNET_DNS;
876  0);
877  }
878  break;
879  }
880  next_phase(rr);
882  return;
883  }
884  /* odd, client was not on our list for the request, that ought
885  to be an error */
886  GNUNET_break(0);
888 }
889 
890 
898 static int
900  const struct GNUNET_MessageHeader *message)
901 {
902  uint16_t msize;
903  const struct GNUNET_TUN_Layer2PacketHeader *tun;
904  const struct GNUNET_TUN_IPv4Header *ip4;
905  const struct GNUNET_TUN_IPv6Header *ip6;
906  const struct GNUNET_TUN_UdpHeader *udp;
907  const struct GNUNET_TUN_DnsHeader *dns;
908  struct RequestRecord *rr;
909  struct sockaddr_in *srca4;
910  struct sockaddr_in6 *srca6;
911  struct sockaddr_in *dsta4;
912  struct sockaddr_in6 *dsta6;
913 
915  "Intercepted message via DNS hijacker\n");
916  msize = ntohs(message->size);
917  if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct GNUNET_TUN_Layer2PacketHeader) + sizeof(struct GNUNET_TUN_IPv4Header))
918  {
919  /* non-IP packet received on TUN!? */
920  GNUNET_break(0);
921  return GNUNET_OK;
922  }
923  msize -= sizeof(struct GNUNET_MessageHeader);
924  tun = (const struct GNUNET_TUN_Layer2PacketHeader *)&message[1];
925  msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
926  switch (ntohs(tun->proto))
927  {
928  case ETH_P_IPV4:
929  ip4 = (const struct GNUNET_TUN_IPv4Header *)&tun[1];
930  ip6 = NULL; /* make compiler happy */
931  if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
932  (ip4->version != 4) ||
933  (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
934  (ntohs(ip4->total_length) != msize) ||
935  (ip4->protocol != IPPROTO_UDP))
936  {
937  /* non-IP/UDP packet received on TUN (or with options) */
939  _("Received malformed IPv4-UDP packet on TUN interface.\n"));
940  return GNUNET_OK;
941  }
942  udp = (const struct GNUNET_TUN_UdpHeader*)&ip4[1];
943  msize -= sizeof(struct GNUNET_TUN_IPv4Header);
944  break;
945 
946  case ETH_P_IPV6:
947  ip4 = NULL; /* make compiler happy */
948  ip6 = (const struct GNUNET_TUN_IPv6Header *)&tun[1];
949  if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
950  (ip6->version != 6) ||
951  (ntohs(ip6->payload_length) != msize - sizeof(struct GNUNET_TUN_IPv6Header)) ||
952  (ip6->next_header != IPPROTO_UDP))
953  {
954  /* non-IP/UDP packet received on TUN (or with extensions) */
956  _("Received malformed IPv6-UDP packet on TUN interface.\n"));
957  return GNUNET_OK;
958  }
959  udp = (const struct GNUNET_TUN_UdpHeader *)&ip6[1];
960  msize -= sizeof(struct GNUNET_TUN_IPv6Header);
961  break;
962 
963  default:
964  /* non-IP packet received on TUN!? */
966  _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
967  (unsigned int)msize,
968  ntohs(tun->proto));
969  return GNUNET_OK;
970  }
971  if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct GNUNET_TUN_DnsHeader)) ||
972  (DNS_PORT != ntohs(udp->destination_port)))
973  {
974  /* non-DNS packet received on TUN, ignore */
976  _("DNS interceptor got non-DNS packet (dropped)\n"));
978  gettext_noop("# Non-DNS UDP packet received via TUN interface"),
979  1, GNUNET_NO);
980  return GNUNET_OK;
981  }
982  msize -= sizeof(struct GNUNET_TUN_UdpHeader);
983  dns = (const struct GNUNET_TUN_DnsHeader*)&udp[1];
984  rr = &requests[dns->id];
985 
986  /* clean up from previous request */
988  rr->payload = NULL;
991  0);
992 
993  /* setup new request */
994  rr->phase = RP_INIT;
995  switch (ntohs(tun->proto))
996  {
997  case ETH_P_IPV4:
998  {
999  srca4 = (struct sockaddr_in*)&rr->src_addr;
1000  dsta4 = (struct sockaddr_in*)&rr->dst_addr;
1001  memset(srca4, 0, sizeof(struct sockaddr_in));
1002  memset(dsta4, 0, sizeof(struct sockaddr_in));
1003  srca4->sin_family = AF_INET;
1004  dsta4->sin_family = AF_INET;
1005  srca4->sin_addr = ip4->source_address;
1006  dsta4->sin_addr = ip4->destination_address;
1007  srca4->sin_port = udp->source_port;
1008  dsta4->sin_port = udp->destination_port;
1009 #if HAVE_SOCKADDR_IN_SIN_LEN
1010  srca4->sin_len = sizeof(struct sockaddr_in);
1011  dsta4->sin_len = sizeof(struct sockaddr_in);
1012 #endif
1013  }
1014  break;
1015 
1016  case ETH_P_IPV6:
1017  {
1018  srca6 = (struct sockaddr_in6*)&rr->src_addr;
1019  dsta6 = (struct sockaddr_in6*)&rr->dst_addr;
1020  memset(srca6, 0, sizeof(struct sockaddr_in6));
1021  memset(dsta6, 0, sizeof(struct sockaddr_in6));
1022  srca6->sin6_family = AF_INET6;
1023  dsta6->sin6_family = AF_INET6;
1024  srca6->sin6_addr = ip6->source_address;
1025  dsta6->sin6_addr = ip6->destination_address;
1026  srca6->sin6_port = udp->source_port;
1027  dsta6->sin6_port = udp->destination_port;
1028 #if HAVE_SOCKADDR_IN_SIN_LEN
1029  srca6->sin6_len = sizeof(struct sockaddr_in6);
1030  dsta6->sin6_len = sizeof(struct sockaddr_in6);
1031 #endif
1032  }
1033  break;
1034 
1035  default:
1036  GNUNET_assert(0);
1037  }
1038  rr->payload = GNUNET_malloc(msize);
1039  rr->payload_length = msize;
1040  GNUNET_memcpy(rr->payload, dns, msize);
1041  rr->request_id = dns->id | (request_id_gen << 16);
1042  request_id_gen++;
1044  "Creating new DNS request %llu\n",
1045  (unsigned long long)rr->request_id);
1047  gettext_noop("# DNS requests received via TUN interface"),
1048  1, GNUNET_NO);
1049  /* start request processing state machine */
1050  next_phase(rr);
1051  return GNUNET_OK;
1052 }
1053 
1054 
1060 static void
1061 run(void *cls,
1062  const struct GNUNET_CONFIGURATION_Handle *cfg_,
1064 {
1065  char *ifc_name;
1066  char *ipv4addr;
1067  char *ipv4mask;
1068  char *ipv6addr;
1069  char *ipv6prefix;
1070  char *dns_exit;
1071  char *binary;
1072  int nortsetup;
1073 
1074  cfg = cfg_;
1075  stats = GNUNET_STATISTICS_create("dns", cfg);
1077  cls);
1078  dnsstub = GNUNET_DNSSTUB_start(128);
1079  /* TODO: support multiple DNS_EXIT servers being configured */
1080  /* TODO: see above TODO on using DNS server from original packet.
1081  Not sure which is best... */
1082  dns_exit = NULL;
1083  if ((GNUNET_OK !=
1085  "dns",
1086  "DNS_EXIT",
1087  &dns_exit)) ||
1088  (GNUNET_OK !=
1089  GNUNET_DNSSTUB_add_dns_ip(dnsstub,
1090  dns_exit)))
1091  {
1093  "dns",
1094  "DNS_EXIT",
1095  _("need a valid IPv4 or IPv6 address\n"));
1096  GNUNET_free_non_null(dns_exit);
1097  }
1098  binary = GNUNET_OS_get_suid_binary_path(cfg, "gnunet-helper-dns");
1099 
1100  if (GNUNET_YES !=
1102  GNUNET_YES,
1103  NULL)) // TODO: once we have a windows-testcase, add test parameters here
1104  {
1106  _("`%s' is not SUID or the path is invalid, "
1107  "will not run DNS interceptor\n"),
1108  binary);
1109  global_ret = 1;
1110  GNUNET_free(binary);
1111  return;
1112  }
1113  GNUNET_free(binary);
1114 
1115  helper_argv[0] = GNUNET_strdup("gnunet-dns");
1116  if (GNUNET_SYSERR ==
1118  "dns",
1119  "IFNAME",
1120  &ifc_name))
1121  {
1123  "No entry 'IFNAME' in configuration!\n");
1124  GNUNET_free(binary);
1126  return;
1127  }
1128  helper_argv[1] = ifc_name;
1129  if ((GNUNET_SYSERR ==
1131  "dns",
1132  "IPV6ADDR",
1133  &ipv6addr)))
1134  {
1136  "No entry 'IPV6ADDR' in configuration!\n");
1137  GNUNET_free(binary);
1139  return;
1140  }
1141  helper_argv[2] = ipv6addr;
1142  if (GNUNET_SYSERR ==
1144  "dns",
1145  "IPV6PREFIX",
1146  &ipv6prefix))
1147  {
1149  "No entry 'IPV6PREFIX' in configuration!\n");
1150  GNUNET_free(binary);
1152  return;
1153  }
1154  helper_argv[3] = ipv6prefix;
1155 
1156  if (GNUNET_SYSERR ==
1158  "dns",
1159  "IPV4ADDR",
1160  &ipv4addr))
1161  {
1163  "No entry 'IPV4ADDR' in configuration!\n");
1164  GNUNET_free(binary);
1166  return;
1167  }
1168  helper_argv[4] = ipv4addr;
1169  if (GNUNET_SYSERR ==
1170  GNUNET_CONFIGURATION_get_value_string(cfg, "dns", "IPV4MASK",
1171  &ipv4mask))
1172  {
1174  "No entry 'IPV4MASK' in configuration!\n");
1175  GNUNET_free(binary);
1177  return;
1178  }
1179  helper_argv[5] = ipv4mask;
1180 
1181  nortsetup = GNUNET_CONFIGURATION_get_value_yesno(cfg, "dns",
1182  "SKIP_ROUTING_SETUP");
1183  if (GNUNET_YES == nortsetup)
1184  helper_argv[6] = GNUNET_strdup("1");
1185  else
1186  helper_argv[6] = GNUNET_strdup("0");
1187 
1188  helper_argv[7] = NULL;
1189  hijacker = GNUNET_HELPER_start(GNUNET_NO,
1190  binary,
1191  helper_argv,
1193  NULL, NULL);
1194  GNUNET_free(binary);
1195 }
1196 
1197 
1202  ("dns",
1204  &run,
1207  NULL,
1208  GNUNET_MQ_hd_fixed_size(client_init,
1210  struct GNUNET_DNS_Register,
1211  NULL),
1212  GNUNET_MQ_hd_var_size(client_response,
1214  struct GNUNET_DNS_Response,
1215  NULL),
1217 
1218 
1219 /* FIXME: this might need a port on systems without 'getresgid' */
1220 #if HAVE_GETRESGID
1221 
1224 void __attribute__ ((constructor))
1225 GNUNET_DNS_init()
1226 {
1227  gid_t rgid;
1228  gid_t egid;
1229  gid_t sgid;
1230 
1231  if (-1 == getresgid(&rgid,
1232  &egid,
1233  &sgid))
1234  {
1235  fprintf(stderr,
1236  "getresgid failed: %s\n",
1237  strerror(errno));
1238  }
1239  else if (sgid != rgid)
1240  {
1241  if (-1 == setregid(sgid,
1242  sgid))
1243  fprintf(stderr,
1244  "setregid failed: %s\n",
1245  strerror(errno));
1246  }
1247 }
1248 #endif
1249 
1250 
1251 /* 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:44
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:109
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:78
Handle to a service.
Definition: service.c:114
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:77
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:487
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:1284
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:687
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:588
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:563
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:74
#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:517
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:246
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:561
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:65
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:2315
Handle to the stub resolver.
Definition: dnsstub.c:121
Header from Linux TUN interface.
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:501
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
uint64_t request_id
Unique request ID.
Definition: dns.h:88
uint32_t reserved
Always zero.
Definition: dns.h:60
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
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:84
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:83
Message from DNS service to client: please handle a request.
Definition: dns.h:51
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:653
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:351
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:2234
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:83
#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.