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 
69 {
74 
80 
86 
91 
98 
104 
109 };
110 
111 
116 {
121 
126 
131 
136 
141 
142 };
143 
144 
149 {
150 
156 
161  char *payload;
162 
168 
172  struct sockaddr_storage src_addr;
173 
177  struct sockaddr_storage dst_addr;
178 
184  uint64_t request_id;
185 
190 
195 
200 
201 };
202 
203 
207 static int global_ret;
208 
212 static const struct GNUNET_CONFIGURATION_Handle *cfg;
213 
218 
223 
227 static char *helper_argv[8];
228 
232 static struct ClientRecord *clients_head;
233 
237 static struct ClientRecord *clients_tail;
238 
242 static struct RequestRecord requests[UINT16_MAX + 1];
243 
247 static uint64_t request_id_gen;
248 
253 
254 
260 static void
262 {
264  rr->payload = NULL;
265  rr->payload_length = 0;
268  0);
269 }
270 
271 
277 static void
279 {
280  if (NULL != hijacker)
281  {
282  GNUNET_HELPER_stop (hijacker, GNUNET_NO);
283  hijacker = NULL;
284  }
285  for (unsigned int i=0;i<8;i++)
287  for (unsigned int i=0;i<=UINT16_MAX;i++)
288  cleanup_rr (&requests[i]);
289  if (NULL != stats)
290  {
292  GNUNET_NO);
293  stats = NULL;
294  }
295  if (NULL != dnsstub)
296  {
297  GNUNET_DNSSTUB_stop (dnsstub);
298  dnsstub = NULL;
299  }
300 }
301 
302 
308 static void
310 {
311  struct GNUNET_MessageHeader *hdr;
312  size_t reply_len;
313  uint16_t source_port;
314  uint16_t destination_port;
315 
318  0);
319  if (RP_RESPONSE_MONITOR != rr->phase)
320  {
321  /* no response, drop */
323  "Got no response for request %llu, dropping\n",
324  (unsigned long long) rr->request_id);
325  cleanup_rr (rr);
326  return;
327  }
328 
330  "Transmitting response for request %llu\n",
331  (unsigned long long) rr->request_id);
332  /* send response via hijacker */
333  reply_len = sizeof (struct GNUNET_MessageHeader);
334  reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
335  switch (rr->src_addr.ss_family)
336  {
337  case AF_INET:
338  reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
339  break;
340  case AF_INET6:
341  reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
342  break;
343  default:
344  GNUNET_break (0);
345  cleanup_rr (rr);
346  return;
347  }
348  reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
349  reply_len += rr->payload_length;
350  if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
351  {
352  /* response too big, drop */
353  GNUNET_break (0); /* how can this be? */
354  cleanup_rr(rr);
355  return;
356  }
357  {
358  char buf[reply_len] GNUNET_ALIGN;
359  size_t off;
360  struct GNUNET_TUN_IPv4Header ip4;
361  struct GNUNET_TUN_IPv6Header ip6;
362 
363  /* first, GNUnet message header */
364  hdr = (struct GNUNET_MessageHeader*) buf;
365  hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
366  hdr->size = htons ((uint16_t) reply_len);
367  off = sizeof (struct GNUNET_MessageHeader);
368 
369  /* first, TUN header */
370  {
372 
373  tun.flags = htons (0);
374  if (rr->src_addr.ss_family == AF_INET)
375  tun.proto = htons (ETH_P_IPV4);
376  else
377  tun.proto = htons (ETH_P_IPV6);
378  GNUNET_memcpy (&buf[off],
379  &tun,
380  sizeof (struct GNUNET_TUN_Layer2PacketHeader));
381  off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
382  }
383 
384  /* now IP header */
385  switch (rr->src_addr.ss_family)
386  {
387  case AF_INET:
388  {
389  struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
390  struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
391 
392  source_port = dst->sin_port;
393  destination_port = src->sin_port;
395  IPPROTO_UDP,
396  reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
397  &dst->sin_addr,
398  &src->sin_addr);
399  GNUNET_memcpy (&buf[off],
400  &ip4,
401  sizeof (ip4));
402  off += sizeof (ip4);
403  }
404  break;
405  case AF_INET6:
406  {
407  struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
408  struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
409 
410  source_port = dst->sin6_port;
411  destination_port = src->sin6_port;
413  IPPROTO_UDP,
414  reply_len - off - sizeof (struct GNUNET_TUN_IPv6Header),
415  &dst->sin6_addr,
416  &src->sin6_addr);
417  GNUNET_memcpy (&buf[off],
418  &ip6,
419  sizeof (ip6));
420  off += sizeof (ip6);
421  }
422  break;
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;
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);
457  (void) GNUNET_HELPER_send (hijacker,
458  hdr,
459  GNUNET_YES,
460  NULL, NULL);
462  gettext_noop ("# DNS requests answered via TUN interface"),
463  1, GNUNET_NO);
464  }
465  /* clean up, we're done */
466  cleanup_rr (rr);
467 }
468 
469 
477 static void
479  struct ClientRecord *cr)
480 {
481  struct GNUNET_MQ_Envelope *env;
482  struct GNUNET_DNS_Request *req;
483 
484  if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_MAX_MESSAGE_SIZE)
485  {
486  GNUNET_break (0);
487  cleanup_rr (rr);
488  return;
489  }
491  "Sending information about request %llu to local client\n",
492  (unsigned long long) rr->request_id);
493  env = GNUNET_MQ_msg_extra (req,
494  rr->payload_length,
496  req->reserved = htonl (0);
497  req->request_id = rr->request_id;
498  GNUNET_memcpy (&req[1],
499  rr->payload,
500  rr->payload_length);
501  GNUNET_MQ_send (cr->mq,
502  env);
503 }
504 
505 
514 static void
515 process_dns_result (void *cls,
516  const struct GNUNET_TUN_DnsHeader *dns,
517  size_t r);
518 
519 
526 static void
528 {
529  struct ClientRecord *cr;
530  int nz;
531 
532  if (rr->phase == RP_DROP)
533  {
534  cleanup_rr (rr);
535  return;
536  }
537  nz = -1;
538  for (unsigned int j=0;j<rr->client_wait_list_length;j++)
539  {
540  if (NULL != rr->client_wait_list[j])
541  {
542  nz = (int) j;
543  break;
544  }
545  }
546  if (-1 != nz)
547  {
549  rr->client_wait_list[nz]);
550  return;
551  }
552  /* done with current phase, advance! */
554  "Request %llu now in phase %d\n",
555  rr->request_id,
556  rr->phase);
557  switch (rr->phase)
558  {
559  case RP_INIT:
561  for (cr = clients_head; NULL != cr; cr = cr->next)
562  {
563  if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
566  cr);
567  }
568  next_phase (rr);
569  return;
570  case RP_REQUEST_MONITOR:
571  rr->phase = RP_QUERY;
572  for (cr = clients_head; NULL != cr; cr = cr->next)
573  {
574  if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
577  cr);
578  }
579  next_phase (rr);
580  return;
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  case AF_INET6:
594  salen = sizeof (struct sockaddr_in6);
595  sa = (const struct sockaddr *) &rr->dst_addr;
596  break;
597  default:
598  GNUNET_assert (0);
599  }
600 #endif
601  rr->phase = RP_INTERNET_DNS;
602  rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
603  rr->payload,
604  rr->payload_length,
606  NULL);
607  if (NULL == rr->rs)
608  {
610  gettext_noop ("# DNS exit failed (failed to open socket)"),
611  1,
612  GNUNET_NO);
613  cleanup_rr (rr);
614  return;
615  }
616  return;
617  case RP_INTERNET_DNS:
618  rr->phase = RP_MODIFY;
619  for (cr = clients_head; NULL != cr; cr = cr->next)
620  {
621  if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
624  cr);
625  }
626  next_phase (rr);
627  return;
628  case RP_MODIFY:
630  for (cr = clients_head; NULL != cr; cr = cr->next)
631  {
632  if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
635  cr);
636  }
637  next_phase (rr);
638  return;
639  case RP_RESPONSE_MONITOR:
640  request_done (rr);
641  break;
642  case RP_DROP:
643  cleanup_rr (rr);
644  break;
645  default:
646  GNUNET_break (0);
647  cleanup_rr (rr);
648  break;
649  }
650 }
651 
652 
661 static void *
662 client_connect_cb (void *cls,
664  struct GNUNET_MQ_Handle *mq)
665 {
666  struct ClientRecord *cr = cls;
667 
668  cr = GNUNET_new (struct ClientRecord);
669  cr->client = client;
670  cr->mq = mq;
671  GNUNET_CONTAINER_DLL_insert (clients_head,
672  clients_tail,
673  cr);
674  return cr;
675 }
676 
677 
685 static void
688  void *app_ctx)
689 {
690  struct ClientRecord *cr = app_ctx;
691  struct RequestRecord *rr;
692 
693  GNUNET_CONTAINER_DLL_remove (clients_head,
694  clients_tail,
695  cr);
696  for (unsigned int i=0;i<UINT16_MAX;i++)
697  {
698  rr = &requests[i];
699  if (0 == rr->client_wait_list_length)
700  continue; /* not in use */
701  for (unsigned int j=0;j<rr->client_wait_list_length;j++)
702  {
703  if (rr->client_wait_list[j] == cr)
704  {
705  rr->client_wait_list[j] = NULL;
706  next_phase (rr);
707  }
708  }
709  }
710  GNUNET_free (cr);
711 }
712 
713 
722 static void
724  const struct GNUNET_TUN_DnsHeader *dns,
725  size_t r)
726 {
727  struct RequestRecord *rr;
728 
730  "Processing DNS result from stub resolver\n");
731  GNUNET_assert (NULL == cls);
732  if (NULL == dns)
733  return; /* ignore */
734 
735  rr = &requests[dns->id];
736  if (rr->phase != RP_INTERNET_DNS)
737  {
738  /* unexpected / bogus reply */
740  gettext_noop ("# External DNS response discarded (no matching request)"),
741  1, GNUNET_NO);
743  "Received DNS reply that does not match any pending request. Dropping.\n");
744  return;
745  }
747  "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
748  (unsigned long long) rr->request_id);
750  rr->payload = GNUNET_malloc (r);
751  GNUNET_memcpy (rr->payload,
752  dns,
753  r);
754  rr->payload_length = r;
755  next_phase (rr);
756 }
757 
758 
765 static void
767  const struct GNUNET_DNS_Register *reg)
768 {
769  struct ClientRecord *cr = cls;
770 
771  cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
773 }
774 
775 
783 static int
785  const struct GNUNET_DNS_Response *resp)
786 {
787  return GNUNET_OK; /* any payload is acceptable */
788 }
789 
790 
797 static void
799  const struct GNUNET_DNS_Response *resp)
800 {
801  struct ClientRecord *cr = cls;
802  struct RequestRecord *rr;
803  uint16_t msize;
804  uint16_t off;
805 
806  msize = ntohs (resp->header.size);
807  off = (uint16_t) resp->request_id;
808  rr = &requests[off];
810  "Received DNS response with ID %llu from local client!\n",
811  (unsigned long long) resp->request_id);
812  if (rr->request_id != resp->request_id)
813  {
815  gettext_noop ("# Client response discarded (no matching request)"),
816  1,
817  GNUNET_NO);
819  return;
820  }
821  for (unsigned int i=0;i<rr->client_wait_list_length;i++)
822  {
823  if (NULL == rr->client_wait_list[i])
824  continue;
825  if (rr->client_wait_list[i] != cr)
826  continue;
827  rr->client_wait_list[i] = NULL;
828  switch (ntohl (resp->drop_flag))
829  {
830  case 0: /* drop */
831  rr->phase = RP_DROP;
832  break;
833  case 1: /* no change */
834  break;
835  case 2: /* update */
836  msize -= sizeof (struct GNUNET_DNS_Response);
837  if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
838  (RP_REQUEST_MONITOR == rr->phase) ||
839  (RP_RESPONSE_MONITOR == rr->phase) )
840  {
841  GNUNET_break (0);
843  next_phase (rr);
844  return;
845  }
848  "Changing DNS reply according to client specifications\n");
849  rr->payload = GNUNET_malloc (msize);
850  rr->payload_length = msize;
851  GNUNET_memcpy (rr->payload, &resp[1], msize);
852  if (rr->phase == RP_QUERY)
853  {
854  /* clear wait list, we're moving to MODIFY phase next */
857  0);
858  }
859  /* if query changed to answer, move past DNS resolution phase... */
860  if ( (RP_QUERY == rr->phase) &&
861  (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
862  ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
863  {
864  rr->phase = RP_INTERNET_DNS;
867  0);
868  }
869  break;
870  }
871  next_phase (rr);
873  return;
874  }
875  /* odd, client was not on our list for the request, that ought
876  to be an error */
877  GNUNET_break (0);
879 }
880 
881 
889 static int
891  const struct GNUNET_MessageHeader *message)
892 {
893  uint16_t msize;
894  const struct GNUNET_TUN_Layer2PacketHeader *tun;
895  const struct GNUNET_TUN_IPv4Header *ip4;
896  const struct GNUNET_TUN_IPv6Header *ip6;
897  const struct GNUNET_TUN_UdpHeader *udp;
898  const struct GNUNET_TUN_DnsHeader *dns;
899  struct RequestRecord *rr;
900  struct sockaddr_in *srca4;
901  struct sockaddr_in6 *srca6;
902  struct sockaddr_in *dsta4;
903  struct sockaddr_in6 *dsta6;
904 
906  "Intercepted message via DNS hijacker\n");
907  msize = ntohs (message->size);
908  if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
909  {
910  /* non-IP packet received on TUN!? */
911  GNUNET_break (0);
912  return GNUNET_OK;
913  }
914  msize -= sizeof (struct GNUNET_MessageHeader);
915  tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
916  msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
917  switch (ntohs (tun->proto))
918  {
919  case ETH_P_IPV4:
920  ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
921  ip6 = NULL; /* make compiler happy */
922  if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
923  (ip4->version != 4) ||
924  (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
925  (ntohs(ip4->total_length) != msize) ||
926  (ip4->protocol != IPPROTO_UDP) )
927  {
928  /* non-IP/UDP packet received on TUN (or with options) */
930  _("Received malformed IPv4-UDP packet on TUN interface.\n"));
931  return GNUNET_OK;
932  }
933  udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
934  msize -= sizeof (struct GNUNET_TUN_IPv4Header);
935  break;
936  case ETH_P_IPV6:
937  ip4 = NULL; /* make compiler happy */
938  ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
939  if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
940  (ip6->version != 6) ||
941  (ntohs (ip6->payload_length) != msize - sizeof (struct GNUNET_TUN_IPv6Header)) ||
942  (ip6->next_header != IPPROTO_UDP) )
943  {
944  /* non-IP/UDP packet received on TUN (or with extensions) */
946  _("Received malformed IPv6-UDP packet on TUN interface.\n"));
947  return GNUNET_OK;
948  }
949  udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
950  msize -= sizeof (struct GNUNET_TUN_IPv6Header);
951  break;
952  default:
953  /* non-IP packet received on TUN!? */
955  _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
956  (unsigned int) msize,
957  ntohs (tun->proto));
958  return GNUNET_OK;
959  }
960  if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) ||
961  (DNS_PORT != ntohs (udp->destination_port)) )
962  {
963  /* non-DNS packet received on TUN, ignore */
965  _("DNS interceptor got non-DNS packet (dropped)\n"));
967  gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
968  1, GNUNET_NO);
969  return GNUNET_OK;
970  }
971  msize -= sizeof (struct GNUNET_TUN_UdpHeader);
972  dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
973  rr = &requests[dns->id];
974 
975  /* clean up from previous request */
977  rr->payload = NULL;
980  0);
981 
982  /* setup new request */
983  rr->phase = RP_INIT;
984  switch (ntohs (tun->proto))
985  {
986  case ETH_P_IPV4:
987  {
988  srca4 = (struct sockaddr_in*) &rr->src_addr;
989  dsta4 = (struct sockaddr_in*) &rr->dst_addr;
990  memset (srca4, 0, sizeof (struct sockaddr_in));
991  memset (dsta4, 0, sizeof (struct sockaddr_in));
992  srca4->sin_family = AF_INET;
993  dsta4->sin_family = AF_INET;
994  srca4->sin_addr = ip4->source_address;
995  dsta4->sin_addr = ip4->destination_address;
996  srca4->sin_port = udp->source_port;
997  dsta4->sin_port = udp->destination_port;
998 #if HAVE_SOCKADDR_IN_SIN_LEN
999  srca4->sin_len = sizeof (struct sockaddr_in);
1000  dsta4->sin_len = sizeof (struct sockaddr_in);
1001 #endif
1002  }
1003  break;
1004  case ETH_P_IPV6:
1005  {
1006  srca6 = (struct sockaddr_in6*) &rr->src_addr;
1007  dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1008  memset (srca6, 0, sizeof (struct sockaddr_in6));
1009  memset (dsta6, 0, sizeof (struct sockaddr_in6));
1010  srca6->sin6_family = AF_INET6;
1011  dsta6->sin6_family = AF_INET6;
1012  srca6->sin6_addr = ip6->source_address;
1013  dsta6->sin6_addr = ip6->destination_address;
1014  srca6->sin6_port = udp->source_port;
1015  dsta6->sin6_port = udp->destination_port;
1016 #if HAVE_SOCKADDR_IN_SIN_LEN
1017  srca6->sin6_len = sizeof (struct sockaddr_in6);
1018  dsta6->sin6_len = sizeof (struct sockaddr_in6);
1019 #endif
1020  }
1021  break;
1022  default:
1023  GNUNET_assert (0);
1024  }
1025  rr->payload = GNUNET_malloc (msize);
1026  rr->payload_length = msize;
1027  GNUNET_memcpy (rr->payload, dns, msize);
1028  rr->request_id = dns->id | (request_id_gen << 16);
1029  request_id_gen++;
1031  "Creating new DNS request %llu\n",
1032  (unsigned long long) rr->request_id);
1033  GNUNET_STATISTICS_update (stats,
1034  gettext_noop ("# DNS requests received via TUN interface"),
1035  1, GNUNET_NO);
1036  /* start request processing state machine */
1037  next_phase (rr);
1038  return GNUNET_OK;
1039 }
1040 
1041 
1047 static void
1048 run (void *cls,
1049  const struct GNUNET_CONFIGURATION_Handle *cfg_,
1051 {
1052  char *ifc_name;
1053  char *ipv4addr;
1054  char *ipv4mask;
1055  char *ipv6addr;
1056  char *ipv6prefix;
1057  char *dns_exit;
1058  char *binary;
1059  int nortsetup;
1060 
1061  cfg = cfg_;
1062  stats = GNUNET_STATISTICS_create ("dns", cfg);
1064  cls);
1065  dnsstub = GNUNET_DNSSTUB_start (128);
1066  /* TODO: support multiple DNS_EXIT servers being configured */
1067  /* TODO: see above TODO on using DNS server from original packet.
1068  Not sure which is best... */
1069  dns_exit = NULL;
1070  if ( (GNUNET_OK !=
1072  "dns",
1073  "DNS_EXIT",
1074  &dns_exit)) ||
1075  (GNUNET_OK !=
1076  GNUNET_DNSSTUB_add_dns_ip (dnsstub,
1077  dns_exit)) )
1078  {
1080  "dns",
1081  "DNS_EXIT",
1082  _("need a valid IPv4 or IPv6 address\n"));
1083  GNUNET_free_non_null (dns_exit);
1084  }
1085  binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns");
1086 
1087  if (GNUNET_YES !=
1089  GNUNET_YES,
1090  NULL)) // TODO: once we have a windows-testcase, add test parameters here
1091  {
1093  _("`%s' is not SUID or the path is invalid, "
1094  "will not run DNS interceptor\n"),
1095  binary);
1096  global_ret = 1;
1097  GNUNET_free (binary);
1098  return;
1099  }
1100  GNUNET_free (binary);
1101 
1102  helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1103  if (GNUNET_SYSERR ==
1105  "dns",
1106  "IFNAME",
1107  &ifc_name))
1108  {
1110  "No entry 'IFNAME' in configuration!\n");
1111  GNUNET_free (binary);
1113  return;
1114  }
1115  helper_argv[1] = ifc_name;
1116  if ( (GNUNET_SYSERR ==
1118  "dns",
1119  "IPV6ADDR",
1120  &ipv6addr)) )
1121  {
1123  "No entry 'IPV6ADDR' in configuration!\n");
1124  GNUNET_free (binary);
1126  return;
1127  }
1128  helper_argv[2] = ipv6addr;
1129  if (GNUNET_SYSERR ==
1131  "dns",
1132  "IPV6PREFIX",
1133  &ipv6prefix))
1134  {
1136  "No entry 'IPV6PREFIX' in configuration!\n");
1137  GNUNET_free (binary);
1139  return;
1140  }
1141  helper_argv[3] = ipv6prefix;
1142 
1143  if (GNUNET_SYSERR ==
1145  "dns",
1146  "IPV4ADDR",
1147  &ipv4addr))
1148  {
1150  "No entry 'IPV4ADDR' in configuration!\n");
1151  GNUNET_free (binary);
1153  return;
1154  }
1155  helper_argv[4] = ipv4addr;
1156  if (GNUNET_SYSERR ==
1157  GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1158  &ipv4mask))
1159  {
1161  "No entry 'IPV4MASK' in configuration!\n");
1162  GNUNET_free (binary);
1164  return;
1165  }
1166  helper_argv[5] = ipv4mask;
1167 
1168  nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1169  "SKIP_ROUTING_SETUP");
1170  if (GNUNET_YES == nortsetup)
1171  helper_argv[6] = GNUNET_strdup("1");
1172  else
1173  helper_argv[6] = GNUNET_strdup("0");
1174 
1175  helper_argv[7] = NULL;
1176  hijacker = GNUNET_HELPER_start (GNUNET_NO,
1177  binary,
1178  helper_argv,
1180  NULL, NULL);
1181  GNUNET_free (binary);
1182 }
1183 
1184 
1189 ("dns",
1191  &run,
1194  NULL,
1195  GNUNET_MQ_hd_fixed_size (client_init,
1197  struct GNUNET_DNS_Register,
1198  NULL),
1199  GNUNET_MQ_hd_var_size (client_response,
1201  struct GNUNET_DNS_Response,
1202  NULL),
1204 
1205 
1206 /* FIXME: this might need a port on systems without 'getresgid' */
1207 #if HAVE_GETRESGID
1208 
1211 void __attribute__ ((constructor))
1212 GNUNET_DNS_init ()
1213 {
1214  gid_t rgid;
1215  gid_t egid;
1216  gid_t sgid;
1217 
1218  if (-1 == getresgid (&rgid,
1219  &egid,
1220  &sgid))
1221  {
1222  fprintf (stderr,
1223  "getresgid failed: %s\n",
1224  strerror (errno));
1225  }
1226  else if (sgid != rgid)
1227  {
1228  if (-1 == setregid (sgid,
1229  sgid))
1230  fprintf (stderr,
1231  "setregid failed: %s\n",
1232  strerror (errno));
1233  }
1234 }
1235 #endif
1236 
1237 
1238 /* 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: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:82
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:80
struct GNUNET_HELPER_Handle * GNUNET_HELPER_start(int with_control_pipe, const char *binary_name, char *const binary_argv[], GNUNET_MessageTokenizerCallback cb, GNUNET_HELPER_ExceptionCallback exp_cb, void *cb_cls)
Starts a helper and begins reading from it.
Definition: helper.c:491
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:1293
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:731
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:622
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:569
UDP packet header.
#define ETH_P_IPV6
Number for IPv6.
#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:77
#define GNUNET_NO
Definition: gnunet_common.h:81
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
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:524
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:208
Handle to a client that is connected to a service.
Definition: service.c:249
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.
#define GNUNET_memcpy(dst, src, n)
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:595
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
GUID ip4
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:2618
Handle to the stub resolver.
Definition: dnsstub.c:125
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:533
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
uint64_t request_id
Unique request ID.
Definition: dns.h:92
uint32_t reserved
Always zero.
Definition: dns.h:62
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: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:660
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:80
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
GUID ip6
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:43
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:2533
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:87
#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.