2 This file is part of GNUnet.
3 Copyright (C) 2012 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file dns/gnunet-service-dns.c
23 * @brief service to intercept and modify DNS queries (and replies) of this system
24 * @author Christian Grothoff
26 * For "secure" interaction with the legacy DNS system, we permit
27 * replies only to arrive within a 5s window (and they must match
28 * ports, IPs and request IDs). Furthermore, we let the OS pick a
29 * source port, opening up to 128 sockets per address family (IPv4 or
30 * IPv6). Those sockets are closed if they are not in use for 5s
31 * (which means they will be freshly randomized afterwards). For new
32 * requests, we pick a random slot in the array with 128 socket slots
33 * (and re-use an existing socket if the slot is still in use). Thus
34 * each request will be given one of 128 random source ports, and the
35 * 128 random source ports will also change "often" (less often if the
36 * system is very busy, each time if we are mostly idle). At the same
37 * time, the system will never use more than 256 UDP sockets.
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"
46 #include "gnunet_dns_service.h"
47 #include "gnunet_dnsparser_lib.h"
48 #include "gnunet_dnsstub_lib.h"
49 #include "gnunet_statistics_service.h"
50 #include "gnunet_tun_lib.h"
59 * Generic logging shorthand
61 #define LOG(kind, ...) \
62 GNUNET_log_from (kind, "dns", __VA_ARGS__);
66 * Phases each request goes through.
71 * Request has just been received.
76 * Showing the request to all monitor clients. If
77 * client list is empty, will enter QUERY phase.
82 * Showing the request to PRE-RESOLUTION clients to find an answer.
83 * If client list is empty, will trigger global DNS request.
88 * Global Internet query is now pending.
93 * Client (or global DNS request) has resulted in a response.
94 * Forward to all POST-RESOLUTION clients. If client list is empty,
95 * will enter RESPONSE_MONITOR phase.
100 * Showing the request to all monitor clients. If
101 * client list is empty, give the result to the hijacker (and be done).
106 * Some client has told us to drop the request.
113 * Entry we keep for each client.
118 * Kept in doubly-linked list.
120 struct ClientRecord *next;
123 * Kept in doubly-linked list.
125 struct ClientRecord *prev;
128 * Handle to the client.
130 struct GNUNET_SERVICE_Client *client;
133 * Message queue to talk to @a client.
135 struct GNUNET_MQ_Handle *mq;
138 * Flags for the client.
140 enum GNUNET_DNS_Flags flags;
145 * Entry we keep for each active request.
150 * List of clients that still need to see this request (each entry
151 * is set to NULL when the client is done).
153 struct ClientRecord **client_wait_list;
156 * Payload of the UDP packet (the UDP payload), can be either query
157 * or already the response.
162 * Socket we are using to transmit this request (must match if we receive
165 struct GNUNET_DNSSTUB_RequestSocket *rs;
168 * Source address of the original request (for sending response).
170 struct sockaddr_storage src_addr;
173 * Destination address of the original request (for potential use as exit).
175 struct sockaddr_storage dst_addr;
178 * ID of this request, also basis for hashing. Lowest 16 bit will
179 * be our message ID when doing a global DNS request and our index
180 * into the 'requests' array.
185 * Number of bytes in payload.
187 size_t payload_length;
190 * Length of the @e client_wait_list.
192 unsigned int client_wait_list_length;
195 * In which phase this this request?
197 enum RequestPhase phase;
202 * Global return value from 'main'.
204 static int global_ret;
207 * The configuration to use
209 static const struct GNUNET_CONFIGURATION_Handle *cfg;
214 static struct GNUNET_STATISTICS_Handle *stats;
217 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
219 static struct GNUNET_HELPER_Handle *hijacker;
222 * Command-line arguments we are giving to the hijacker process.
224 static char *helper_argv[8];
227 * Head of DLL of clients we consult.
229 static struct ClientRecord *clients_head;
232 * Tail of DLL of clients we consult.
234 static struct ClientRecord *clients_tail;
237 * Array of all open requests.
239 static struct RequestRecord requests[UINT16_MAX + 1];
242 * Generator for unique request IDs.
244 static uint64_t request_id_gen;
247 * Handle to the DNS Stub resolver.
249 static struct GNUNET_DNSSTUB_Context *dnsstub;
253 * We're done processing a DNS request, free associated memory.
255 * @param rr request to clean up
258 cleanup_rr (struct RequestRecord *rr)
260 GNUNET_free_non_null (rr->payload);
262 rr->payload_length = 0;
263 GNUNET_array_grow (rr->client_wait_list,
264 rr->client_wait_list_length,
270 * Task run during shutdown.
275 cleanup_task (void *cls GNUNET_UNUSED)
277 if (NULL != hijacker)
279 GNUNET_HELPER_stop (hijacker, GNUNET_NO);
282 for (unsigned int i = 0; i < 8; i++)
283 GNUNET_free_non_null (helper_argv[i]);
284 for (unsigned int i = 0; i <= UINT16_MAX; i++)
285 cleanup_rr (&requests[i]);
288 GNUNET_STATISTICS_destroy (stats,
294 GNUNET_DNSSTUB_stop (dnsstub);
301 * We're done with some request, finish processing.
303 * @param rr request send to the network or just clean up.
306 request_done (struct RequestRecord *rr)
308 struct GNUNET_MessageHeader *hdr;
310 uint16_t source_port;
311 uint16_t destination_port;
313 GNUNET_array_grow (rr->client_wait_list,
314 rr->client_wait_list_length,
316 if (RP_RESPONSE_MONITOR != rr->phase)
318 /* no response, drop */
319 LOG (GNUNET_ERROR_TYPE_DEBUG,
320 "Got no response for request %llu, dropping\n",
321 (unsigned long long) rr->request_id);
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Transmitting response for request %llu\n",
328 (unsigned long long) rr->request_id);
329 /* send response via hijacker */
330 reply_len = sizeof(struct GNUNET_MessageHeader);
331 reply_len += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
332 switch (rr->src_addr.ss_family)
335 reply_len += sizeof(struct GNUNET_TUN_IPv4Header);
339 reply_len += sizeof(struct GNUNET_TUN_IPv6Header);
347 reply_len += sizeof(struct GNUNET_TUN_UdpHeader);
348 reply_len += rr->payload_length;
349 if (reply_len >= GNUNET_MAX_MESSAGE_SIZE)
351 /* response too big, drop */
352 GNUNET_break (0); /* how can this be? */
357 char buf[reply_len] GNUNET_ALIGN;
359 struct GNUNET_TUN_IPv4Header ip4;
360 struct GNUNET_TUN_IPv6Header ip6;
362 /* first, GNUnet message header */
363 hdr = (struct GNUNET_MessageHeader*) buf;
364 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
365 hdr->size = htons ((uint16_t) reply_len);
366 off = sizeof(struct GNUNET_MessageHeader);
368 /* first, TUN header */
370 struct GNUNET_TUN_Layer2PacketHeader tun;
372 tun.flags = htons (0);
373 if (rr->src_addr.ss_family == AF_INET)
374 tun.proto = htons (ETH_P_IPV4);
376 tun.proto = htons (ETH_P_IPV6);
377 GNUNET_memcpy (&buf[off],
379 sizeof(struct GNUNET_TUN_Layer2PacketHeader));
380 off += sizeof(struct GNUNET_TUN_Layer2PacketHeader);
384 switch (rr->src_addr.ss_family)
388 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
389 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
391 source_port = dst->sin_port;
392 destination_port = src->sin_port;
393 GNUNET_TUN_initialize_ipv4_header (&ip4,
395 reply_len - off - sizeof(struct
396 GNUNET_TUN_IPv4Header),
399 GNUNET_memcpy (&buf[off],
408 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
409 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
411 source_port = dst->sin6_port;
412 destination_port = src->sin6_port;
413 GNUNET_TUN_initialize_ipv6_header (&ip6,
415 reply_len - off - sizeof(struct
416 GNUNET_TUN_IPv6Header),
419 GNUNET_memcpy (&buf[off],
432 struct GNUNET_TUN_UdpHeader udp;
434 udp.source_port = source_port;
435 udp.destination_port = destination_port;
436 udp.len = htons (reply_len - off);
437 if (AF_INET == rr->src_addr.ss_family)
438 GNUNET_TUN_calculate_udp4_checksum (&ip4,
443 GNUNET_TUN_calculate_udp6_checksum (&ip6,
447 GNUNET_memcpy (&buf[off],
453 /* now DNS payload */
455 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
456 off += rr->payload_length;
458 /* final checks & sending */
459 GNUNET_assert (off == reply_len);
460 (void) GNUNET_HELPER_send (hijacker,
464 GNUNET_STATISTICS_update (stats,
466 "# DNS requests answered via TUN interface"),
469 /* clean up, we're done */
475 * Show the payload of the given request record to the client
476 * (and wait for a response).
478 * @param rr request to send to client
479 * @param cr client to send the response to
482 send_request_to_client (struct RequestRecord *rr,
483 struct ClientRecord *cr)
485 struct GNUNET_MQ_Envelope *env;
486 struct GNUNET_DNS_Request *req;
488 if (sizeof(struct GNUNET_DNS_Request) + rr->payload_length >=
489 GNUNET_MAX_MESSAGE_SIZE)
495 LOG (GNUNET_ERROR_TYPE_DEBUG,
496 "Sending information about request %llu to local client\n",
497 (unsigned long long) rr->request_id);
498 env = GNUNET_MQ_msg_extra (req,
500 GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
501 req->reserved = htonl (0);
502 req->request_id = rr->request_id;
503 GNUNET_memcpy (&req[1],
506 GNUNET_MQ_send (cr->mq,
512 * Callback called from DNSSTUB resolver when a resolution
516 * @param dns the response itself
517 * @param r number of bytes in dns
520 process_dns_result (void *cls,
521 const struct GNUNET_TUN_DnsHeader *dns,
526 * A client has completed its processing for this
529 * @param rr request to process further
532 next_phase (struct RequestRecord *rr)
534 struct ClientRecord *cr;
537 if (rr->phase == RP_DROP)
543 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
545 if (NULL != rr->client_wait_list[j])
553 send_request_to_client (rr,
554 rr->client_wait_list[nz]);
557 /* done with current phase, advance! */
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Request %llu now in phase %d\n",
565 rr->phase = RP_REQUEST_MONITOR;
566 for (cr = clients_head; NULL != cr; cr = cr->next)
568 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
569 GNUNET_array_append (rr->client_wait_list,
570 rr->client_wait_list_length,
576 case RP_REQUEST_MONITOR:
577 rr->phase = RP_QUERY;
578 for (cr = clients_head; NULL != cr; cr = cr->next)
580 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
581 GNUNET_array_append (rr->client_wait_list,
582 rr->client_wait_list_length,
590 /* TODO: optionally, use this to forward DNS requests to the
591 * original* DNS server instead of the one we have configured...
592 (but then we need to create a fresh dnsstub for each request
593 * and* manage the timeout) */
594 switch (rr->dst_addr.ss_family)
597 salen = sizeof(struct sockaddr_in);
598 sa = (const struct sockaddr *) &rr->dst_addr;
602 salen = sizeof(struct sockaddr_in6);
603 sa = (const struct sockaddr *) &rr->dst_addr;
610 rr->phase = RP_INTERNET_DNS;
611 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
618 GNUNET_STATISTICS_update (stats,
620 "# DNS exit failed (failed to open socket)"),
628 case RP_INTERNET_DNS:
629 rr->phase = RP_MODIFY;
630 for (cr = clients_head; NULL != cr; cr = cr->next)
632 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
633 GNUNET_array_append (rr->client_wait_list,
634 rr->client_wait_list_length,
641 rr->phase = RP_RESPONSE_MONITOR;
642 for (cr = clients_head; NULL != cr; cr = cr->next)
644 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
645 GNUNET_array_append (rr->client_wait_list,
646 rr->client_wait_list_length,
652 case RP_RESPONSE_MONITOR:
669 * A client connected, setup our data structures.
672 * @param client handle of client that connected
673 * @param mq message queue to talk to @a client
674 * @return our `struct ClientRecord`
677 client_connect_cb (void *cls,
678 struct GNUNET_SERVICE_Client *client,
679 struct GNUNET_MQ_Handle *mq)
681 struct ClientRecord *cr = cls;
683 cr = GNUNET_new (struct ClientRecord);
686 GNUNET_CONTAINER_DLL_insert (clients_head,
694 * A client disconnected, clean up after it.
697 * @param client handle of client that disconnected
698 * @param app_ctx our `struct ClientRecord`
701 client_disconnect_cb (void *cls,
702 struct GNUNET_SERVICE_Client *client,
705 struct ClientRecord *cr = app_ctx;
706 struct RequestRecord *rr;
708 GNUNET_CONTAINER_DLL_remove (clients_head,
711 for (unsigned int i = 0; i < UINT16_MAX; i++)
714 if (0 == rr->client_wait_list_length)
715 continue; /* not in use */
716 for (unsigned int j = 0; j < rr->client_wait_list_length; j++)
718 if (rr->client_wait_list[j] == cr)
720 rr->client_wait_list[j] = NULL;
730 * Callback called from DNSSTUB resolver when a resolution
734 * @param dns the response itself
735 * @param r number of bytes in dns
738 process_dns_result (void *cls,
739 const struct GNUNET_TUN_DnsHeader *dns,
742 struct RequestRecord *rr;
744 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
745 "Processing DNS result from stub resolver\n");
746 GNUNET_assert (NULL == cls);
750 rr = &requests[dns->id];
751 if (rr->phase != RP_INTERNET_DNS)
753 /* unexpected / bogus reply */
754 GNUNET_STATISTICS_update (stats,
756 "# External DNS response discarded (no matching request)"),
758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
759 "Received DNS reply that does not match any pending request. Dropping.\n");
762 LOG (GNUNET_ERROR_TYPE_DEBUG,
763 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
764 (unsigned long long) rr->request_id);
765 GNUNET_free_non_null (rr->payload);
766 rr->payload = GNUNET_malloc (r);
767 GNUNET_memcpy (rr->payload,
770 rr->payload_length = r;
776 * We got a new client. Make sure all new DNS requests pass by its desk.
778 * @param cls the client
779 * @param reg the init message
782 handle_client_init (void *cls,
783 const struct GNUNET_DNS_Register *reg)
785 struct ClientRecord *cr = cls;
787 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
788 GNUNET_SERVICE_client_continue (cr->client);
793 * Check a response from a client.
795 * @param cls the client
796 * @param resp the response
797 * @return #GNUNET_OK (always fine)
800 check_client_response (void *cls,
801 const struct GNUNET_DNS_Response *resp)
803 return GNUNET_OK; /* any payload is acceptable */
808 * Handle a response from a client.
810 * @param cls the client
811 * @param resp the response
814 handle_client_response (void *cls,
815 const struct GNUNET_DNS_Response *resp)
817 struct ClientRecord *cr = cls;
818 struct RequestRecord *rr;
822 msize = ntohs (resp->header.size);
823 off = (uint16_t) resp->request_id;
825 LOG (GNUNET_ERROR_TYPE_DEBUG,
826 "Received DNS response with ID %llu from local client!\n",
827 (unsigned long long) resp->request_id);
828 if (rr->request_id != resp->request_id)
830 GNUNET_STATISTICS_update (stats,
832 "# Client response discarded (no matching request)"),
835 GNUNET_SERVICE_client_continue (cr->client);
838 for (unsigned int i = 0; i < rr->client_wait_list_length; i++)
840 if (NULL == rr->client_wait_list[i])
842 if (rr->client_wait_list[i] != cr)
844 rr->client_wait_list[i] = NULL;
845 switch (ntohl (resp->drop_flag))
851 case 1: /* no change */
855 msize -= sizeof(struct GNUNET_DNS_Response);
856 if ((sizeof(struct GNUNET_TUN_DnsHeader) > msize) ||
857 (RP_REQUEST_MONITOR == rr->phase) ||
858 (RP_RESPONSE_MONITOR == rr->phase))
861 GNUNET_SERVICE_client_drop (cr->client);
865 GNUNET_free_non_null (rr->payload);
866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 "Changing DNS reply according to client specifications\n");
868 rr->payload = GNUNET_malloc (msize);
869 rr->payload_length = msize;
870 GNUNET_memcpy (rr->payload, &resp[1], msize);
871 if (rr->phase == RP_QUERY)
873 /* clear wait list, we're moving to MODIFY phase next */
874 GNUNET_array_grow (rr->client_wait_list,
875 rr->client_wait_list_length,
878 /* if query changed to answer, move past DNS resolution phase... */
879 if ((RP_QUERY == rr->phase) &&
880 (rr->payload_length > sizeof(struct GNUNET_TUN_DnsHeader)) &&
881 ( ((struct GNUNET_TUN_DnsFlags*) &(((struct
882 GNUNET_TUN_DnsHeader*) rr->
884 query_or_response == 1) )
886 rr->phase = RP_INTERNET_DNS;
887 GNUNET_array_grow (rr->client_wait_list,
888 rr->client_wait_list_length,
894 GNUNET_SERVICE_client_continue (cr->client);
897 /* odd, client was not on our list for the request, that ought
900 GNUNET_SERVICE_client_drop (cr->client);
905 * Functions with this signature are called whenever a complete
906 * message is received by the tokenizer from the DNS hijack process.
909 * @param message the actual message, a DNS request we should handle
912 process_helper_messages (void *cls,
913 const struct GNUNET_MessageHeader *message)
916 const struct GNUNET_TUN_Layer2PacketHeader *tun;
917 const struct GNUNET_TUN_IPv4Header *ip4;
918 const struct GNUNET_TUN_IPv6Header *ip6;
919 const struct GNUNET_TUN_UdpHeader *udp;
920 const struct GNUNET_TUN_DnsHeader *dns;
921 struct RequestRecord *rr;
922 struct sockaddr_in *srca4;
923 struct sockaddr_in6 *srca6;
924 struct sockaddr_in *dsta4;
925 struct sockaddr_in6 *dsta6;
927 LOG (GNUNET_ERROR_TYPE_DEBUG,
928 "Intercepted message via DNS hijacker\n");
929 msize = ntohs (message->size);
930 if (msize < sizeof(struct GNUNET_MessageHeader) + sizeof(struct
931 GNUNET_TUN_Layer2PacketHeader)
932 + sizeof(struct GNUNET_TUN_IPv4Header))
934 /* non-IP packet received on TUN!? */
938 msize -= sizeof(struct GNUNET_MessageHeader);
939 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
940 msize -= sizeof(struct GNUNET_TUN_Layer2PacketHeader);
941 switch (ntohs (tun->proto))
944 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
945 ip6 = NULL; /* make compiler happy */
946 if ((msize < sizeof(struct GNUNET_TUN_IPv4Header)) ||
947 (ip4->version != 4) ||
948 (ip4->header_length != sizeof(struct GNUNET_TUN_IPv4Header) / 4) ||
949 (ntohs (ip4->total_length) != msize) ||
950 (ip4->protocol != IPPROTO_UDP))
952 /* non-IP/UDP packet received on TUN (or with options) */
953 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
954 _ ("Received malformed IPv4-UDP packet on TUN interface.\n"));
957 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
958 msize -= sizeof(struct GNUNET_TUN_IPv4Header);
962 ip4 = NULL; /* make compiler happy */
963 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
964 if ((msize < sizeof(struct GNUNET_TUN_IPv6Header)) ||
965 (ip6->version != 6) ||
966 (ntohs (ip6->payload_length) != msize - sizeof(struct
967 GNUNET_TUN_IPv6Header))
969 (ip6->next_header != IPPROTO_UDP))
971 /* non-IP/UDP packet received on TUN (or with extensions) */
972 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
973 _ ("Received malformed IPv6-UDP packet on TUN interface.\n"));
976 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
977 msize -= sizeof(struct GNUNET_TUN_IPv6Header);
981 /* non-IP packet received on TUN!? */
982 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
984 "Got non-IP packet with %u bytes and protocol %u from TUN\n"),
985 (unsigned int) msize,
989 if ((msize <= sizeof(struct GNUNET_TUN_UdpHeader) + sizeof(struct
990 GNUNET_TUN_DnsHeader))
992 (DNS_PORT != ntohs (udp->destination_port)))
994 /* non-DNS packet received on TUN, ignore */
995 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
996 _ ("DNS interceptor got non-DNS packet (dropped)\n"));
997 GNUNET_STATISTICS_update (stats,
999 "# Non-DNS UDP packet received via TUN interface"),
1003 msize -= sizeof(struct GNUNET_TUN_UdpHeader);
1004 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1005 rr = &requests[dns->id];
1007 /* clean up from previous request */
1008 GNUNET_free_non_null (rr->payload);
1010 GNUNET_array_grow (rr->client_wait_list,
1011 rr->client_wait_list_length,
1014 /* setup new request */
1015 rr->phase = RP_INIT;
1016 switch (ntohs (tun->proto))
1020 srca4 = (struct sockaddr_in*) &rr->src_addr;
1021 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1022 memset (srca4, 0, sizeof(struct sockaddr_in));
1023 memset (dsta4, 0, sizeof(struct sockaddr_in));
1024 srca4->sin_family = AF_INET;
1025 dsta4->sin_family = AF_INET;
1026 srca4->sin_addr = ip4->source_address;
1027 dsta4->sin_addr = ip4->destination_address;
1028 srca4->sin_port = udp->source_port;
1029 dsta4->sin_port = udp->destination_port;
1030 #if HAVE_SOCKADDR_IN_SIN_LEN
1031 srca4->sin_len = sizeof(struct sockaddr_in);
1032 dsta4->sin_len = sizeof(struct sockaddr_in);
1039 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1040 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1041 memset (srca6, 0, sizeof(struct sockaddr_in6));
1042 memset (dsta6, 0, sizeof(struct sockaddr_in6));
1043 srca6->sin6_family = AF_INET6;
1044 dsta6->sin6_family = AF_INET6;
1045 srca6->sin6_addr = ip6->source_address;
1046 dsta6->sin6_addr = ip6->destination_address;
1047 srca6->sin6_port = udp->source_port;
1048 dsta6->sin6_port = udp->destination_port;
1049 #if HAVE_SOCKADDR_IN_SIN_LEN
1050 srca6->sin6_len = sizeof(struct sockaddr_in6);
1051 dsta6->sin6_len = sizeof(struct sockaddr_in6);
1059 rr->payload = GNUNET_malloc (msize);
1060 rr->payload_length = msize;
1061 GNUNET_memcpy (rr->payload, dns, msize);
1062 rr->request_id = dns->id | (request_id_gen << 16);
1064 LOG (GNUNET_ERROR_TYPE_DEBUG,
1065 "Creating new DNS request %llu\n",
1066 (unsigned long long) rr->request_id);
1067 GNUNET_STATISTICS_update (stats,
1069 "# DNS requests received via TUN interface"),
1071 /* start request processing state machine */
1078 * @param cls closure
1079 * @param cfg_ configuration to use
1080 * @param service the initialized service
1084 const struct GNUNET_CONFIGURATION_Handle *cfg_,
1085 struct GNUNET_SERVICE_Handle *service)
1097 stats = GNUNET_STATISTICS_create ("dns", cfg);
1098 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1100 dnsstub = GNUNET_DNSSTUB_start (128);
1101 /* TODO: support multiple DNS_EXIT servers being configured */
1102 /* TODO: see above TODO on using DNS server from original packet.
1103 Not sure which is best... */
1106 GNUNET_CONFIGURATION_get_value_string (cfg,
1111 GNUNET_DNSSTUB_add_dns_ip (dnsstub,
1114 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1117 _ ("need a valid IPv4 or IPv6 address\n"));
1118 GNUNET_free_non_null (dns_exit);
1120 binary = GNUNET_OS_get_suid_binary_path (cfg, "gnunet-helper-dns");
1123 GNUNET_OS_check_helper_binary (binary,
1125 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1127 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1128 _ ("`%s' is not SUID or the path is invalid, "
1129 "will not run DNS interceptor\n"),
1132 GNUNET_free (binary);
1135 GNUNET_free (binary);
1137 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1138 if (GNUNET_SYSERR ==
1139 GNUNET_CONFIGURATION_get_value_string (cfg,
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 "No entry 'IFNAME' in configuration!\n");
1146 GNUNET_free (binary);
1147 GNUNET_SCHEDULER_shutdown ();
1150 helper_argv[1] = ifc_name;
1151 if ((GNUNET_SYSERR ==
1152 GNUNET_CONFIGURATION_get_value_string (cfg,
1157 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1158 "No entry 'IPV6ADDR' in configuration!\n");
1159 GNUNET_free (binary);
1160 GNUNET_SCHEDULER_shutdown ();
1163 helper_argv[2] = ipv6addr;
1164 if (GNUNET_SYSERR ==
1165 GNUNET_CONFIGURATION_get_value_string (cfg,
1170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1171 "No entry 'IPV6PREFIX' in configuration!\n");
1172 GNUNET_free (binary);
1173 GNUNET_SCHEDULER_shutdown ();
1176 helper_argv[3] = ipv6prefix;
1178 if (GNUNET_SYSERR ==
1179 GNUNET_CONFIGURATION_get_value_string (cfg,
1184 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1185 "No entry 'IPV4ADDR' in configuration!\n");
1186 GNUNET_free (binary);
1187 GNUNET_SCHEDULER_shutdown ();
1190 helper_argv[4] = ipv4addr;
1191 if (GNUNET_SYSERR ==
1192 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1195 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1196 "No entry 'IPV4MASK' in configuration!\n");
1197 GNUNET_free (binary);
1198 GNUNET_SCHEDULER_shutdown ();
1201 helper_argv[5] = ipv4mask;
1203 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1204 "SKIP_ROUTING_SETUP");
1205 if (GNUNET_YES == nortsetup)
1206 helper_argv[6] = GNUNET_strdup ("1");
1208 helper_argv[6] = GNUNET_strdup ("0");
1210 helper_argv[7] = NULL;
1211 hijacker = GNUNET_HELPER_start (GNUNET_NO,
1214 &process_helper_messages,
1216 GNUNET_free (binary);
1221 * Define "main" method using service macro.
1225 GNUNET_SERVICE_OPTION_NONE,
1228 &client_disconnect_cb,
1230 GNUNET_MQ_hd_fixed_size (client_init,
1231 GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1232 struct GNUNET_DNS_Register,
1234 GNUNET_MQ_hd_var_size (client_response,
1235 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE,
1236 struct GNUNET_DNS_Response,
1238 GNUNET_MQ_handler_end ());
1241 /* FIXME: this might need a port on systems without 'getresgid' */
1244 * Enable use of SGID capabilities on POSIX
1246 void __attribute__ ((constructor))
1253 if (-1 == getresgid (&rgid,
1258 "getresgid failed: %s\n",
1261 else if (sgid != rgid)
1263 if (-1 == setregid (sgid,
1266 "setregid failed: %s\n",
1275 /* end of gnunet-service-dns.c */