GNUnet 0.21.2
gnunet-service-dns.c
Go to the documentation of this file.
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
39#include "platform.h"
40#include "gnunet_util_lib.h"
41#include "gnunet_applications.h"
42#include "gnunet_constants.h"
43#include "gnunet_protocols.h"
44#include "gnunet_signatures.h"
45#include "dns.h"
46#include "gnunet_dns_service.h"
48
52#define DNS_PORT 53
53
54
58#define LOG(kind, ...) \
59 GNUNET_log_from (kind, "dns", __VA_ARGS__);
60
61
66{
71
77
83
88
95
101
105 RP_DROP
107
108
113{
118
123
128
133
138};
139
140
145{
151
156 char *payload;
157
163
167 struct sockaddr_storage src_addr;
168
172 struct sockaddr_storage dst_addr;
173
179 uint64_t request_id;
180
185
190
195};
196
197
201static int global_ret;
202
206static const struct GNUNET_CONFIGURATION_Handle *cfg;
207
212
217
221static char *helper_argv[8];
222
227
232
236static struct RequestRecord requests[UINT16_MAX + 1];
237
241static uint64_t request_id_gen;
242
247
248
254static void
256{
257 GNUNET_free (rr->payload);
258 rr->payload = NULL;
259 rr->payload_length = 0;
262 0);
263}
264
265
271static void
273{
274 if (NULL != hijacker)
275 {
277 hijacker = NULL;
278 }
279 for (unsigned int i = 0; i < 8; i++)
281 for (unsigned int i = 0; i <= UINT16_MAX; i++)
282 cleanup_rr (&requests[i]);
283 if (NULL != stats)
284 {
286 GNUNET_NO);
287 stats = NULL;
288 }
289 if (NULL != dnsstub)
290 {
292 dnsstub = NULL;
293 }
294}
295
296
302static 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;
362 hdr->size = htons ((uint16_t) reply_len);
363 off = sizeof(struct GNUNET_MessageHeader);
364
365 /* first, TUN header */
366 {
368
369 tun.flags = htons (0);
370 if (rr->src_addr.ss_family == AF_INET)
371 tun.proto = htons (ETH_P_IPV4);
372 else
373 tun.proto = htons (ETH_P_IPV6);
374 GNUNET_memcpy (&buf[off],
375 &tun,
376 sizeof(struct GNUNET_TUN_Layer2PacketHeader));
377 off += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
378 }
379
380 /* now IP header */
381 switch (rr->src_addr.ss_family)
382 {
383 case AF_INET:
384 {
385 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
386 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
387
388 source_port = dst->sin_port;
389 destination_port = src->sin_port;
391 IPPROTO_UDP,
392 reply_len - off - sizeof(struct
394 &dst->sin_addr,
395 &src->sin_addr);
396 GNUNET_memcpy (&buf[off],
397 &ip4,
398 sizeof(ip4));
399 off += sizeof(ip4);
400 }
401 break;
402
403 case AF_INET6:
404 {
405 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
406 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
407
408 source_port = dst->sin6_port;
409 destination_port = src->sin6_port;
411 IPPROTO_UDP,
412 reply_len - off - sizeof(struct
414 &dst->sin6_addr,
415 &src->sin6_addr);
416 GNUNET_memcpy (&buf[off],
417 &ip6,
418 sizeof(ip6));
419 off += sizeof(ip6);
420 }
421 break;
422
423 default:
424 GNUNET_assert (0);
425 }
426
427 /* now UDP header */
428 {
430
431 udp.source_port = source_port;
432 udp.destination_port = destination_port;
433 udp.len = htons (reply_len - off);
434 if (AF_INET == rr->src_addr.ss_family)
436 &udp,
437 rr->payload,
438 rr->payload_length);
439 else
441 &udp,
442 rr->payload,
443 rr->payload_length);
444 GNUNET_memcpy (&buf[off],
445 &udp,
446 sizeof(udp));
447 off += sizeof(udp);
448 }
449
450 /* now DNS payload */
451 {
452 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
453 off += rr->payload_length;
454 }
455 /* final checks & sending */
456 GNUNET_assert (off == reply_len);
458 hdr,
460 NULL, NULL);
463 "# DNS requests answered via TUN interface"),
464 1, GNUNET_NO);
465 }
466 /* clean up, we're done */
467 cleanup_rr (rr);
468}
469
470
478static void
480 struct ClientRecord *cr)
481{
482 struct GNUNET_MQ_Envelope *env;
483 struct GNUNET_DNS_Request *req;
484
485 if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >=
487 {
488 GNUNET_break (0);
489 cleanup_rr (rr);
490 return;
491 }
493 "Sending information about request %llu to local client\n",
494 (unsigned long long) rr->request_id);
496 rr->payload_length,
498 req->reserved = htonl (0);
499 req->request_id = rr->request_id;
500 GNUNET_memcpy (&req[1],
501 rr->payload,
502 rr->payload_length);
503 GNUNET_MQ_send (cr->mq,
504 env);
505}
506
507
516static void
517process_dns_result (void *cls,
518 const struct GNUNET_TUN_DnsHeader *dns,
519 size_t r);
520
521
528static void
530{
531 struct ClientRecord *cr;
532 int nz;
533
534 if (rr->phase == RP_DROP)
535 {
536 cleanup_rr (rr);
537 return;
538 }
539 nz = -1;
540 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
541 {
542 if (NULL != rr->client_wait_list[j])
543 {
544 nz = (int) j;
545 break;
546 }
547 }
548 if (-1 != nz)
549 {
551 rr->client_wait_list[nz]);
552 return;
553 }
554 /* done with current phase, advance! */
556 "Request %llu now in phase %d\n",
557 (unsigned long long) rr->request_id,
558 rr->phase);
559 switch (rr->phase)
560 {
561 case RP_INIT:
563 for (cr = clients_head; NULL != cr; cr = cr->next)
564 {
565 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
568 cr);
569 }
570 next_phase (rr);
571 return;
572
574 rr->phase = RP_QUERY;
575 for (cr = clients_head; NULL != cr; cr = cr->next)
576 {
577 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
580 cr);
581 }
582 next_phase (rr);
583 return;
584
585 case RP_QUERY:
586#if 0
587 /* TODO: optionally, use this to forward DNS requests to the
588 * original* DNS server instead of the one we have configured...
589 (but then we need to create a fresh dnsstub for each request
590 * and* manage the timeout) */
591 switch (rr->dst_addr.ss_family)
592 {
593 case AF_INET:
594 salen = sizeof(struct sockaddr_in);
595 sa = (const struct sockaddr *) &rr->dst_addr;
596 break;
597
598 case AF_INET6:
599 salen = sizeof(struct sockaddr_in6);
600 sa = (const struct sockaddr *) &rr->dst_addr;
601 break;
602
603 default:
604 GNUNET_assert (0);
605 }
606#endif
609 rr->payload,
610 rr->payload_length,
612 NULL);
613 if (NULL == rr->rs)
614 {
617 "# DNS exit failed (failed to open socket)"),
618 1,
619 GNUNET_NO);
620 cleanup_rr (rr);
621 return;
622 }
623 return;
624
625 case RP_INTERNET_DNS:
626 rr->phase = RP_MODIFY;
627 for (cr = clients_head; NULL != cr; cr = cr->next)
628 {
629 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
632 cr);
633 }
634 next_phase (rr);
635 return;
636
637 case RP_MODIFY:
639 for (cr = clients_head; NULL != cr; cr = cr->next)
640 {
644 cr);
645 }
646 next_phase (rr);
647 return;
648
650 request_done (rr);
651 break;
652
653 case RP_DROP:
654 cleanup_rr (rr);
655 break;
656
657 default:
658 GNUNET_break (0);
659 cleanup_rr (rr);
660 break;
661 }
662}
663
664
673static void *
675 struct GNUNET_SERVICE_Client *client,
676 struct GNUNET_MQ_Handle *mq)
677{
678 struct ClientRecord *cr = cls;
679
680 cr = GNUNET_new (struct ClientRecord);
681 cr->client = client;
682 cr->mq = mq;
685 cr);
686 return cr;
687}
688
689
697static void
700 void *app_ctx)
701{
702 struct ClientRecord *cr = app_ctx;
703 struct RequestRecord *rr;
704
707 cr);
708 for (unsigned int i = 0; i < UINT16_MAX; i++)
709 {
710 rr = &requests[i];
711 if (0 == rr->client_wait_list_length)
712 continue; /* not in use */
713 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
714 {
715 if (rr->client_wait_list[j] == cr)
716 {
717 rr->client_wait_list[j] = NULL;
718 next_phase (rr);
719 }
720 }
721 }
722 GNUNET_free (cr);
723}
724
725
734static void
736 const struct GNUNET_TUN_DnsHeader *dns,
737 size_t r)
738{
739 struct RequestRecord *rr;
740
742 "Processing DNS result from stub resolver\n");
743 GNUNET_assert (NULL == cls);
744 if (NULL == dns)
745 return; /* ignore */
746
747 rr = &requests[dns->id];
748 if (rr->phase != RP_INTERNET_DNS)
749 {
750 /* unexpected / bogus reply */
753 "# External DNS response discarded (no matching request)"),
754 1, GNUNET_NO);
756 "Received DNS reply that does not match any pending request. Dropping.\n");
757 return;
758 }
760 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
761 (unsigned long long) rr->request_id);
762 GNUNET_free (rr->payload);
763 rr->payload = GNUNET_malloc (r);
765 dns,
766 r);
767 rr->payload_length = r;
768 next_phase (rr);
769}
770
771
778static void
780 const struct GNUNET_DNS_Register *reg)
781{
782 struct ClientRecord *cr = cls;
783
784 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
786}
787
788
796static int
798 const struct GNUNET_DNS_Response *resp)
799{
800 return GNUNET_OK; /* any payload is acceptable */
801}
802
803
810static void
812 const struct GNUNET_DNS_Response *resp)
813{
814 struct ClientRecord *cr = cls;
815 struct RequestRecord *rr;
816 uint16_t msize;
817 uint16_t off;
818
819 msize = ntohs (resp->header.size);
820 off = (uint16_t) resp->request_id;
821 rr = &requests[off];
823 "Received DNS response with ID %llu from local client!\n",
824 (unsigned long long) resp->request_id);
825 if (rr->request_id != resp->request_id)
826 {
829 "# Client response discarded (no matching request)"),
830 1,
831 GNUNET_NO);
833 return;
834 }
835 for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
836 {
837 if (NULL == rr->client_wait_list[i])
838 continue;
839 if (rr->client_wait_list[i] != cr)
840 continue;
841 rr->client_wait_list[i] = NULL;
842 switch (ntohl (resp->drop_flag))
843 {
844 case 0: /* drop */
845 rr->phase = RP_DROP;
846 break;
847
848 case 1: /* no change */
849 break;
850
851 case 2: /* update */
852 msize -= sizeof(struct GNUNET_DNS_Response);
853 if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
854 (RP_REQUEST_MONITOR == rr->phase) ||
855 (RP_RESPONSE_MONITOR == rr->phase))
856 {
857 GNUNET_break (0);
859 next_phase (rr);
860 return;
861 }
862 GNUNET_free (rr->payload);
864 "Changing DNS reply according to client specifications\n");
865 rr->payload = GNUNET_malloc (msize);
866 rr->payload_length = msize;
867 GNUNET_memcpy (rr->payload, &resp[1], msize);
868 if (rr->phase == RP_QUERY)
869 {
870 /* clear wait list, we're moving to MODIFY phase next */
873 0);
874 }
875 /* if query changed to answer, move past DNS resolution phase... */
876 if ((RP_QUERY == rr->phase) &&
877 (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
878 ( ((struct GNUNET_TUN_DnsFlags*) &(((struct
880 payload)->flags))->
881 query_or_response == 1) )
882 {
886 0);
887 }
888 break;
889 }
890 next_phase (rr);
892 return;
893 }
894 /* odd, client was not on our list for the request, that ought
895 to be an error */
896 GNUNET_break (0);
898}
899
900
908static int
910 const struct GNUNET_MessageHeader *message)
911{
912 uint16_t msize;
913 const struct GNUNET_TUN_Layer2PacketHeader *tun;
914 const struct GNUNET_TUN_IPv4Header *ip4;
915 const struct GNUNET_TUN_IPv6Header *ip6;
916 const struct GNUNET_TUN_UdpHeader *udp;
917 const struct GNUNET_TUN_DnsHeader *dns;
918 struct RequestRecord *rr;
919 struct sockaddr_in *srca4;
920 struct sockaddr_in6 *srca6;
921 struct sockaddr_in *dsta4;
922 struct sockaddr_in6 *dsta6;
923
925 "Intercepted message via DNS hijacker\n");
926 msize = ntohs (message->size);
927 if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
929 + sizeof(struct GNUNET_TUN_IPv4Header))
930 {
931 /* non-IP packet received on TUN!? */
932 GNUNET_break (0);
933 return GNUNET_OK;
934 }
935 msize -= sizeof(struct GNUNET_MessageHeader);
936 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
937 msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
938 switch (ntohs (tun->proto))
939 {
940 case ETH_P_IPV4:
941 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
942 ip6 = NULL; /* make compiler happy */
943 if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
944 (ip4->version != 4) ||
945 (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
946 (ntohs (ip4->total_length) != msize) ||
947 (ip4->protocol != IPPROTO_UDP))
948 {
949 /* non-IP/UDP packet received on TUN (or with options) */
951 _ ("Received malformed IPv4-UDP packet on TUN interface.\n"));
952 return GNUNET_OK;
953 }
954 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
955 msize -= sizeof(struct GNUNET_TUN_IPv4Header);
956 break;
957
958 case ETH_P_IPV6:
959 ip4 = NULL; /* make compiler happy */
960 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
961 if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
962 (ip6->version != 6) ||
963 (ntohs (ip6->payload_length) != msize - sizeof(struct
965 ||
966 (ip6->next_header != IPPROTO_UDP))
967 {
968 /* non-IP/UDP packet received on TUN (or with extensions) */
970 _ ("Received malformed IPv6-UDP packet on TUN interface.\n"));
971 return GNUNET_OK;
972 }
973 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
974 msize -= sizeof(struct GNUNET_TUN_IPv6Header);
975 break;
976
977 default:
978 /* non-IP packet received on TUN!? */
980 _ (
981 "Got non-IP packet with %u bytes and protocol %u from TUN\n"),
982 (unsigned int) msize,
983 ntohs (tun->proto));
984 return GNUNET_OK;
985 }
986 if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct
988 ||
989 (DNS_PORT != ntohs (udp->destination_port)))
990 {
991 /* non-DNS packet received on TUN, ignore */
993 _ ("DNS interceptor got non-DNS packet (dropped)\n"));
996 "# Non-DNS UDP packet received via TUN interface"),
997 1, GNUNET_NO);
998 return GNUNET_OK;
999 }
1000 msize -= sizeof(struct GNUNET_TUN_UdpHeader);
1001 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1002 rr = &requests[dns->id];
1003
1004 /* clean up from previous request */
1005 GNUNET_free (rr->payload);
1006 rr->payload = NULL;
1009 0);
1010
1011 /* setup new request */
1012 rr->phase = RP_INIT;
1013 switch (ntohs (tun->proto))
1014 {
1015 case ETH_P_IPV4:
1016 {
1017 srca4 = (struct sockaddr_in*) &rr->src_addr;
1018 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1019 memset (srca4, 0, sizeof(struct sockaddr_in));
1020 memset (dsta4, 0, sizeof(struct sockaddr_in));
1021 srca4->sin_family = AF_INET;
1022 dsta4->sin_family = AF_INET;
1023 srca4->sin_addr = ip4->source_address;
1024 dsta4->sin_addr = ip4->destination_address;
1025 srca4->sin_port = udp->source_port;
1026 dsta4->sin_port = udp->destination_port;
1027#if HAVE_SOCKADDR_IN_SIN_LEN
1028 srca4->sin_len = sizeof(struct sockaddr_in);
1029 dsta4->sin_len = sizeof(struct sockaddr_in);
1030#endif
1031 }
1032 break;
1033
1034 case ETH_P_IPV6:
1035 {
1036 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1037 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1038 memset (srca6, 0, sizeof(struct sockaddr_in6));
1039 memset (dsta6, 0, sizeof(struct sockaddr_in6));
1040 srca6->sin6_family = AF_INET6;
1041 dsta6->sin6_family = AF_INET6;
1042 srca6->sin6_addr = ip6->source_address;
1043 dsta6->sin6_addr = ip6->destination_address;
1044 srca6->sin6_port = udp->source_port;
1045 dsta6->sin6_port = udp->destination_port;
1046#if HAVE_SOCKADDR_IN_SIN_LEN
1047 srca6->sin6_len = sizeof(struct sockaddr_in6);
1048 dsta6->sin6_len = sizeof(struct sockaddr_in6);
1049#endif
1050 }
1051 break;
1052
1053 default:
1054 GNUNET_assert (0);
1055 }
1056 rr->payload = GNUNET_malloc (msize);
1057 rr->payload_length = msize;
1058 GNUNET_memcpy (rr->payload, dns, msize);
1059 rr->request_id = dns->id | (request_id_gen << 16);
1062 "Creating new DNS request %llu\n",
1063 (unsigned long long) rr->request_id);
1065 gettext_noop (
1066 "# DNS requests received via TUN interface"),
1067 1, GNUNET_NO);
1068 /* start request processing state machine */
1069 next_phase (rr);
1070 return GNUNET_OK;
1071}
1072
1073
1079static void
1080run (void *cls,
1081 const struct GNUNET_CONFIGURATION_Handle *cfg_,
1083{
1084 char *ifc_name;
1085 char *ipv4addr;
1086 char *ipv4mask;
1087 char *ipv6addr;
1088 char *ipv6prefix;
1089 char *dns_exit;
1090 char *binary;
1091 int nortsetup;
1092
1093 cfg = cfg_;
1096 cls);
1098 /* TODO: support multiple DNS_EXIT servers being configured */
1099 /* TODO: see above TODO on using DNS server from original packet.
1100 Not sure which is best... */
1101 dns_exit = NULL;
1102 if ((GNUNET_OK !=
1104 "dns",
1105 "DNS_EXIT",
1106 &dns_exit)) ||
1107 (GNUNET_OK !=
1109 dns_exit)))
1110 {
1112 "dns",
1113 "DNS_EXIT",
1114 _ ("need a valid IPv4 or IPv6 address\n"));
1115 GNUNET_free (dns_exit);
1116 }
1117 binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns");
1118
1119 if (GNUNET_YES !=
1121 GNUNET_YES,
1122 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1123 {
1125 _ ("`%s' is not SUID or the path is invalid, "
1126 "will not run DNS interceptor\n"),
1127 binary);
1128 global_ret = 1;
1129 GNUNET_free (binary);
1130 return;
1131 }
1132 GNUNET_free (binary);
1133
1134 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1135 if (GNUNET_SYSERR ==
1137 "dns",
1138 "IFNAME",
1139 &ifc_name))
1140 {
1142 "No entry 'IFNAME' in configuration!\n");
1143 GNUNET_free (binary);
1145 return;
1146 }
1147 helper_argv[1] = ifc_name;
1148 if ((GNUNET_SYSERR ==
1150 "dns",
1151 "IPV6ADDR",
1152 &ipv6addr)))
1153 {
1155 "No entry 'IPV6ADDR' in configuration!\n");
1156 GNUNET_free (binary);
1158 return;
1159 }
1160 helper_argv[2] = ipv6addr;
1161 if (GNUNET_SYSERR ==
1163 "dns",
1164 "IPV6PREFIX",
1165 &ipv6prefix))
1166 {
1168 "No entry 'IPV6PREFIX' in configuration!\n");
1169 GNUNET_free (binary);
1171 return;
1172 }
1174
1175 if (GNUNET_SYSERR ==
1177 "dns",
1178 "IPV4ADDR",
1179 &ipv4addr))
1180 {
1182 "No entry 'IPV4ADDR' in configuration!\n");
1183 GNUNET_free (binary);
1185 return;
1186 }
1187 helper_argv[4] = ipv4addr;
1188 if (GNUNET_SYSERR ==
1189 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1190 &ipv4mask))
1191 {
1193 "No entry 'IPV4MASK' in configuration!\n");
1194 GNUNET_free (binary);
1196 return;
1197 }
1198 helper_argv[5] = ipv4mask;
1199
1200 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1201 "SKIP_ROUTING_SETUP");
1202 if (GNUNET_YES == nortsetup)
1203 helper_argv[6] = GNUNET_strdup ("1");
1204 else
1205 helper_argv[6] = GNUNET_strdup ("0");
1206
1207 helper_argv[7] = NULL;
1209 binary,
1212 NULL, NULL);
1213 GNUNET_free (binary);
1214}
1215
1216
1221 ("dns",
1223 &run,
1226 NULL,
1227 GNUNET_MQ_hd_fixed_size (client_init,
1229 struct GNUNET_DNS_Register,
1230 NULL),
1231 GNUNET_MQ_hd_var_size (client_response,
1233 struct GNUNET_DNS_Response,
1234 NULL),
1236
1237
1238/* FIXME: this might need a port on systems without 'getresgid' */
1239#if HAVE_GETRESGID
1243void __attribute__ ((constructor))
1244GNUNET_DNS_init ()
1245{
1246 gid_t rgid;
1247 gid_t egid;
1248 gid_t sgid;
1249
1250 if (-1 == getresgid (&rgid,
1251 &egid,
1252 &sgid))
1253 {
1254 fprintf (stderr,
1255 "getresgid failed: %s\n",
1256 strerror (errno));
1257 }
1258 else if (sgid != rgid)
1259 {
1260 if (-1 == setregid (sgid,
1261 sgid))
1262 fprintf (stderr,
1263 "setregid failed: %s\n",
1264 strerror (errno));
1265 }
1266}
1267
1268
1269#endif
1270
1271
1272/* end of gnunet-service-dns.c */
struct GNUNET_MQ_Handle * mq
Definition: 003.c:5
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
IPC messages between DNS API and DNS service.
#define gettext_noop(String)
Definition: gettext.h:74
static unsigned long long ipv6prefix
IPv6 prefix (0..127) from configuration file.
static struct GNUNET_SERVICE_Handle * service
Handle to our service instance.
static unsigned long long payload
How much data are we currently storing in the database?
static void next_phase(struct RequestRecord *rr)
A client has completed its processing for this request.
static int process_helper_messages(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer fro...
static void handle_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Handle a response from a client.
static int global_ret
Global return value from 'main'.
RequestPhase
Phases each request goes through.
@ RP_REQUEST_MONITOR
Showing the request to all monitor clients.
@ RP_QUERY
Showing the request to PRE-RESOLUTION clients to find an answer.
@ RP_MODIFY
Client (or global DNS request) has resulted in a response.
@ RP_DROP
Some client has told us to drop the request.
@ RP_INTERNET_DNS
Global Internet query is now pending.
@ RP_INIT
Request has just been received.
@ RP_RESPONSE_MONITOR
Showing the request to all monitor clients.
static void process_dns_result(void *cls, const struct GNUNET_TUN_DnsHeader *dns, size_t r)
Callback called from DNSSTUB resolver when a resolution succeeded.
static struct GNUNET_STATISTICS_Handle * stats
Statistics.
static const struct GNUNET_CONFIGURATION_Handle * cfg
The configuration to use.
static struct GNUNET_HELPER_Handle * hijacker
Handle to DNS hijacker helper process ("gnunet-helper-dns").
static struct GNUNET_DNSSTUB_Context * dnsstub
Handle to the DNS Stub resolver.
static void cleanup_task(void *cls)
Task run during shutdown.
static void request_done(struct RequestRecord *rr)
We're done with some request, finish processing.
static char * helper_argv[8]
Command-line arguments we are giving to the hijacker process.
GNUNET_SERVICE_MAIN("dns", GNUNET_SERVICE_OPTION_NONE, &run, &client_connect_cb, &client_disconnect_cb, NULL, GNUNET_MQ_hd_fixed_size(client_init, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, struct GNUNET_DNS_Register, NULL), GNUNET_MQ_hd_var_size(client_response, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, struct GNUNET_DNS_Response, NULL), GNUNET_MQ_handler_end())
Define "main" method using service macro.
static void * client_connect_cb(void *cls, struct GNUNET_SERVICE_Client *client, struct GNUNET_MQ_Handle *mq)
A client connected, setup our data structures.
static struct ClientRecord * clients_head
Head of DLL of clients we consult.
static uint64_t request_id_gen
Generator for unique request IDs.
#define DNS_PORT
Port number for DNS.
static void handle_client_init(void *cls, const struct GNUNET_DNS_Register *reg)
We got a new client.
static int check_client_response(void *cls, const struct GNUNET_DNS_Response *resp)
Check a response from a client.
static void run(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg_, struct GNUNET_SERVICE_Handle *service)
static struct RequestRecord requests[UINT16_MAX+1]
Array of all open requests.
#define LOG(kind,...)
Generic logging shorthand.
static void cleanup_rr(struct RequestRecord *rr)
We're done processing a DNS request, free associated memory.
static void client_disconnect_cb(void *cls, struct GNUNET_SERVICE_Client *client, void *app_ctx)
A client disconnected, clean up after it.
static void send_request_to_client(struct RequestRecord *rr, struct ClientRecord *cr)
Show the payload of the given request record to the client (and wait for a response).
static struct ClientRecord * clients_tail
Tail of DLL of clients we consult.
static int udp
Option -u: UDP requested.
Definition: gnunet-vpn.c:75
Constants for network applications operating on top of the CADET service.
API to access the DNS service.
struct GNUNET_PQ_ResultSpec __attribute__
Constants for network protocols.
API to create, modify and access statistics.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_DNSSTUB_Context * GNUNET_DNSSTUB_start(unsigned int num_sockets)
Start a DNS stub resolver.
Definition: dnsstub.c:586
int GNUNET_DNSSTUB_add_dns_ip(struct GNUNET_DNSSTUB_Context *ctx, const char *dns_ip)
Add nameserver for use by the DNSSTUB.
Definition: dnsstub.c:613
void GNUNET_DNSSTUB_stop(struct GNUNET_DNSSTUB_Context *ctx)
Cleanup DNSSTUB resolver.
Definition: dnsstub.c:705
struct GNUNET_DNSSTUB_RequestSocket * GNUNET_DNSSTUB_resolve(struct GNUNET_DNSSTUB_Context *ctx, const void *request, size_t request_len, GNUNET_DNSSTUB_ResultCallback rc, void *rc_cls)
Perform DNS resolution using our default IP from init.
Definition: dnsstub.c:526
GNUNET_DNS_Flags
Flags that specify when to call the client's handler.
@ GNUNET_DNS_FLAG_RESPONSE_MONITOR
Set this flag to see all requests just before they are returned to the network.
@ GNUNET_DNS_FLAG_REQUEST_MONITOR
Set this flag to see all requests first prior to resolution (for monitoring).
@ GNUNET_DNS_FLAG_PRE_RESOLUTION
This client should be called on requests that have not yet been resolved as this client provides a re...
@ GNUNET_DNS_FLAG_POST_RESOLUTION
This client wants to be called on the results of a DNS resolution (either resolved by PRE-RESOLUTION ...
struct GNUNET_HELPER_SendHandle * GNUNET_HELPER_send(struct GNUNET_HELPER_Handle *h, const struct GNUNET_MessageHeader *msg, bool can_drop, GNUNET_HELPER_Continuation cont, void *cont_cls)
Send an message to the helper.
Definition: helper.c:613
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:460
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:536
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_ALIGN
gcc-ism to force alignment; we use this to align char-arrays that may then be cast to 'struct's.
#define GNUNET_UNUSED
gcc-ism to document unused arguments
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_invalid(enum GNUNET_ErrorType kind, const char *section, const char *option, const char *required)
Log error message about invalid configuration option value.
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_array_append(arr, len, element)
Append an element to an array (growing the array by one).
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition: mq.c:304
#define GNUNET_MQ_handler_end()
End-marker for the handlers array.
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
Definition: gnunet_mq_lib.h:63
#define GNUNET_MQ_hd_var_size(name, code, str, ctx)
#define GNUNET_MQ_hd_fixed_size(name, code, str, ctx)
char * GNUNET_OS_get_suid_binary_path(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *progname)
Given the name of a helper, service or daemon binary construct the full path to the binary using the ...
enum GNUNET_GenericReturnValue GNUNET_OS_check_helper_binary(const char *binary, bool check_suid, const char *params)
Check whether an executable exists and possibly if the suid bit is set on the file.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_HELPER
Type of messages between the gnunet-helper-dns and the service.
#define GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT
Initial message from client to DNS service for registration.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:567
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition: scheduler.c:1340
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition: service.c:2484
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition: service.c:2455
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
struct GNUNET_STATISTICS_Handle * GNUNET_STATISTICS_create(const char *subsystem, const struct GNUNET_CONFIGURATION_Handle *cfg)
Get handle for the statistics service.
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
void GNUNET_STATISTICS_destroy(struct GNUNET_STATISTICS_Handle *h, int sync_first)
Destroy a handle (free all state associated with it).
void GNUNET_TUN_initialize_ipv6_header(struct GNUNET_TUN_IPv6Header *ip, uint8_t protocol, uint16_t payload_length, const struct in6_addr *src, const struct in6_addr *dst)
Initialize an IPv6 header.
Definition: tun.c:82
void GNUNET_TUN_calculate_udp4_checksum(const struct GNUNET_TUN_IPv4Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv4 UDP checksum.
Definition: tun.c:160
GNUNET_NETWORK_STRUCT_END void GNUNET_TUN_initialize_ipv4_header(struct GNUNET_TUN_IPv4Header *ip, uint8_t protocol, uint16_t payload_length, const struct in_addr *src, const struct in_addr *dst)
Initialize an IPv4 header.
Definition: tun.c:47
#define ETH_P_IPV6
Number for IPv6.
#define ETH_P_IPV4
Number for IPv4.
void GNUNET_TUN_calculate_udp6_checksum(const struct GNUNET_TUN_IPv6Header *ip, struct GNUNET_TUN_UdpHeader *udp, const void *payload, uint16_t payload_length)
Calculate IPv6 UDP checksum.
Definition: tun.c:191
#define _(String)
GNU gettext support macro.
Definition: platform.h:178
Entry we keep for each client.
struct ClientRecord * prev
Kept in doubly-linked list.
struct GNUNET_MQ_Handle * mq
Message queue to talk to client.
enum GNUNET_DNS_Flags flags
Flags for the client.
struct GNUNET_SERVICE_Client * client
Handle to the client.
struct ClientRecord * next
Kept in doubly-linked list.
Handle to the stub resolver.
Definition: dnsstub.c:125
UDP socket we are using for sending DNS requests to the Internet.
Definition: dnsstub.c:46
Message from client to DNS service to register itself.
Definition: dns.h:36
uint32_t flags
NBO encoding of enum GNUNET_DNS_Flags for the client.
Definition: dns.h:45
Message from DNS service to client: please handle a request.
Definition: dns.h:53
uint32_t reserved
Always zero.
Definition: dns.h:62
uint64_t request_id
Unique request ID.
Definition: dns.h:67
Message from client to DNS service: here is my reply.
Definition: dns.h:77
struct GNUNET_MessageHeader header
Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE.
Definition: dns.h:81
uint32_t drop_flag
Zero to drop, 1 for no change (no payload), 2 for update (message has payload).
Definition: dns.h:86
uint64_t request_id
Unique request ID.
Definition: dns.h:91
The handle to a helper process.
Definition: helper.c:77
Handle to a message queue.
Definition: mq.c:87
Header for all communications.
Handle to a client that is connected to a service.
Definition: service.c:246
Handle to a service.
Definition: service.c:117
Handle for the service.
DNS flags (largely RFC 1035 / RFC 2136).
uint16_t id
Unique identifier for the request/response.
Standard IPv4 header.
uint16_t total_length
Length of the packet, including this header.
uint8_t protocol
L4-protocol, for example, IPPROTO_UDP or IPPROTO_TCP.
struct in_addr source_address
Origin of the packet.
struct in_addr destination_address
Destination of the packet.
unsigned int header_length
Standard IPv6 header.
struct in6_addr source_address
Origin of the packet.
uint8_t next_header
For example, IPPROTO_UDP or IPPROTO_TCP.
struct in6_addr destination_address
Destination of the packet.
uint16_t payload_length
Length of the payload, excluding this header.
Header from Linux TUN interface.
uint16_t proto
Here we get an ETH_P_-number.
uint16_t flags
Some flags (unused).
UDP packet header.
uint16_t destination_port
Destination port (in NBO).
uint16_t source_port
Source port (in NBO).
Entry we keep for each active request.
struct sockaddr_storage src_addr
Source address of the original request (for sending response).
char * payload
Payload of the UDP packet (the UDP payload), can be either query or already the response.
uint64_t request_id
ID of this request, also basis for hashing.
unsigned int client_wait_list_length
Length of the client_wait_list.
struct sockaddr_storage dst_addr
Destination address of the original request (for potential use as exit).
size_t payload_length
Number of bytes in payload.
struct ClientRecord ** client_wait_list
List of clients that still need to see this request (each entry is set to NULL when the client is don...
struct GNUNET_DNSSTUB_RequestSocket * rs
Socket we are using to transmit this request (must match if we receive a response).
enum RequestPhase phase
In which phase this this request?