2 This file is part of GNUnet.
3 Copyright (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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_SERVER_Client *client;
133 * Flags for the client.
135 enum GNUNET_DNS_Flags flags;
141 * Entry we keep for each active request.
147 * List of clients that still need to see this request (each entry
148 * is set to NULL when the client is done).
150 struct ClientRecord **client_wait_list;
153 * Payload of the UDP packet (the UDP payload), can be either query
154 * or already the response.
159 * Socket we are using to transmit this request (must match if we receive
162 struct GNUNET_DNSSTUB_RequestSocket *rs;
165 * Source address of the original request (for sending response).
167 struct sockaddr_storage src_addr;
170 * Destination address of the original request (for potential use as exit).
172 struct sockaddr_storage dst_addr;
175 * ID of this request, also basis for hashing. Lowest 16 bit will
176 * be our message ID when doing a global DNS request and our index
177 * into the 'requests' array.
182 * Number of bytes in payload.
184 size_t payload_length;
187 * Length of the client wait list.
189 unsigned int client_wait_list_length;
192 * In which phase this this request?
194 enum RequestPhase phase;
200 * Global return value from 'main'.
202 static int global_ret;
205 * The configuration to use
207 static const struct GNUNET_CONFIGURATION_Handle *cfg;
212 static struct GNUNET_STATISTICS_Handle *stats;
215 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
217 static struct GNUNET_HELPER_Handle *hijacker;
220 * Command-line arguments we are giving to the hijacker process.
222 static char *helper_argv[7];
225 * Head of DLL of clients we consult.
227 static struct ClientRecord *clients_head;
230 * Tail of DLL of clients we consult.
232 static struct ClientRecord *clients_tail;
235 * Our notification context.
237 static struct GNUNET_SERVER_NotificationContext *nc;
240 * Array of all open requests.
242 static struct RequestRecord requests[UINT16_MAX + 1];
245 * Generator for unique request IDs.
247 static uint64_t request_id_gen;
250 * Handle to the DNS Stub resolver.
252 static struct GNUNET_DNSSTUB_Context *dnsstub;
256 * We're done processing a DNS request, free associated memory.
258 * @param rr request to clean up
261 cleanup_rr (struct RequestRecord *rr)
263 GNUNET_free_non_null (rr->payload);
265 rr->payload_length = 0;
266 GNUNET_array_grow (rr->client_wait_list,
267 rr->client_wait_list_length,
273 * Task run during shutdown.
279 cleanup_task (void *cls GNUNET_UNUSED,
280 const struct GNUNET_SCHEDULER_TaskContext *tc)
284 GNUNET_HELPER_stop (hijacker, GNUNET_NO);
287 GNUNET_free_non_null (helper_argv[i]);
288 for (i=0;i<=UINT16_MAX;i++)
289 cleanup_rr (&requests[i]);
290 GNUNET_SERVER_notification_context_destroy (nc);
294 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
299 GNUNET_DNSSTUB_stop (dnsstub);
306 * We're done with some request, finish processing.
308 * @param rr request send to the network or just clean up.
311 request_done (struct RequestRecord *rr)
313 struct GNUNET_MessageHeader *hdr;
315 uint16_t source_port;
316 uint16_t destination_port;
318 GNUNET_array_grow (rr->client_wait_list,
319 rr->client_wait_list_length,
321 if (RP_RESPONSE_MONITOR != rr->phase)
323 /* no response, drop */
324 LOG (GNUNET_ERROR_TYPE_DEBUG,
325 "Got no response for request %llu, dropping\n",
326 (unsigned long long) rr->request_id);
331 LOG (GNUNET_ERROR_TYPE_DEBUG,
332 "Transmitting response for request %llu\n",
333 (unsigned long long) rr->request_id);
334 /* send response via hijacker */
335 reply_len = sizeof (struct GNUNET_MessageHeader);
336 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
337 switch (rr->src_addr.ss_family)
340 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
343 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
350 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
351 reply_len += rr->payload_length;
352 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
354 /* response too big, drop */
355 GNUNET_break (0); /* how can this be? */
360 char buf[reply_len] GNUNET_ALIGN;
362 struct GNUNET_TUN_IPv4Header ip4;
363 struct GNUNET_TUN_IPv6Header ip6;
365 /* first, GNUnet message header */
366 hdr = (struct GNUNET_MessageHeader*) buf;
367 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
368 hdr->size = htons ((uint16_t) reply_len);
369 off = sizeof (struct GNUNET_MessageHeader);
371 /* first, TUN header */
373 struct GNUNET_TUN_Layer2PacketHeader tun;
375 tun.flags = htons (0);
376 if (rr->src_addr.ss_family == AF_INET)
377 tun.proto = htons (ETH_P_IPV4);
379 tun.proto = htons (ETH_P_IPV6);
380 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
381 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
385 switch (rr->src_addr.ss_family)
389 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
390 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
392 source_port = dst->sin_port;
393 destination_port = src->sin_port;
394 GNUNET_TUN_initialize_ipv4_header (&ip4,
396 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
399 memcpy (&buf[off], &ip4, sizeof (ip4));
405 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
406 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
408 source_port = dst->sin6_port;
409 destination_port = src->sin6_port;
410 GNUNET_TUN_initialize_ipv6_header (&ip6,
412 reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
415 memcpy (&buf[off], &ip6, sizeof (ip6));
425 struct GNUNET_TUN_UdpHeader udp;
427 udp.source_port = source_port;
428 udp.destination_port = destination_port;
429 udp.len = htons (reply_len - off);
430 if (AF_INET == rr->src_addr.ss_family)
431 GNUNET_TUN_calculate_udp4_checksum (&ip4,
436 GNUNET_TUN_calculate_udp6_checksum (&ip6,
440 memcpy (&buf[off], &udp, sizeof (udp));
444 /* now DNS payload */
446 memcpy (&buf[off], rr->payload, rr->payload_length);
447 off += rr->payload_length;
449 /* final checks & sending */
450 GNUNET_assert (off == reply_len);
451 (void) GNUNET_HELPER_send (hijacker,
455 GNUNET_STATISTICS_update (stats,
456 gettext_noop ("# DNS requests answered via TUN interface"),
459 /* clean up, we're done */
465 * Show the payload of the given request record to the client
466 * (and wait for a response).
468 * @param rr request to send to client
469 * @param client client to send the response to
472 send_request_to_client (struct RequestRecord *rr,
473 struct GNUNET_SERVER_Client *client)
475 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length] GNUNET_ALIGN;
476 struct GNUNET_DNS_Request *req;
478 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Sending information about request %llu to local client\n",
486 (unsigned long long) rr->request_id);
487 req = (struct GNUNET_DNS_Request*) buf;
488 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
489 req->header.size = htons (sizeof (buf));
490 req->reserved = htonl (0);
491 req->request_id = rr->request_id;
492 memcpy (&req[1], rr->payload, rr->payload_length);
493 GNUNET_SERVER_notification_context_unicast (nc,
502 * Callback called from DNSSTUB resolver when a resolution
506 * @param rs the socket that received the response
507 * @param dns the response itself
508 * @param r number of bytes in dns
511 process_dns_result (void *cls,
512 struct GNUNET_DNSSTUB_RequestSocket *rs,
513 const struct GNUNET_TUN_DnsHeader *dns,
518 * A client has completed its processing for this
521 * @param rr request to process further
524 next_phase (struct RequestRecord *rr)
526 struct ClientRecord *cr;
531 if (rr->phase == RP_DROP)
537 for (j=0;j<rr->client_wait_list_length;j++)
539 if (NULL != rr->client_wait_list[j])
547 send_request_to_client (rr, rr->client_wait_list[nz]->client);
550 /* done with current phase, advance! */
551 LOG (GNUNET_ERROR_TYPE_DEBUG,
552 "Request %llu now in phase %d\n",
558 rr->phase = RP_REQUEST_MONITOR;
559 for (cr = clients_head; NULL != cr; cr = cr->next)
561 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
562 GNUNET_array_append (rr->client_wait_list,
563 rr->client_wait_list_length,
568 case RP_REQUEST_MONITOR:
569 rr->phase = RP_QUERY;
570 for (cr = clients_head; NULL != cr; cr = cr->next)
572 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
573 GNUNET_array_append (rr->client_wait_list,
574 rr->client_wait_list_length,
580 switch (rr->dst_addr.ss_family)
583 salen = sizeof (struct sockaddr_in);
586 salen = sizeof (struct sockaddr_in6);
592 rr->phase = RP_INTERNET_DNS;
593 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
594 (struct sockaddr*) &rr->dst_addr,
602 GNUNET_STATISTICS_update (stats,
603 gettext_noop ("# DNS exit failed (failed to open socket)"),
609 case RP_INTERNET_DNS:
610 rr->phase = RP_MODIFY;
611 for (cr = clients_head; NULL != cr; cr = cr->next)
613 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
614 GNUNET_array_append (rr->client_wait_list,
615 rr->client_wait_list_length,
621 rr->phase = RP_RESPONSE_MONITOR;
622 for (cr = clients_head; NULL != cr; cr = cr->next)
624 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
625 GNUNET_array_append (rr->client_wait_list,
626 rr->client_wait_list_length,
631 case RP_RESPONSE_MONITOR:
646 * A client disconnected, clean up after it.
649 * @param client handle of client that disconnected
652 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
654 struct ClientRecord *cr;
655 struct RequestRecord *rr;
659 for (cr = clients_head; NULL != cr; cr = cr->next)
661 if (cr->client == client)
663 GNUNET_SERVER_client_drop (client);
664 GNUNET_CONTAINER_DLL_remove (clients_head,
667 for (i=0;i<UINT16_MAX;i++)
670 if (0 == rr->client_wait_list_length)
671 continue; /* not in use */
672 for (j=0;j<rr->client_wait_list_length;j++)
674 if (rr->client_wait_list[j] == cr)
676 rr->client_wait_list[j] = NULL;
689 * Callback called from DNSSTUB resolver when a resolution
693 * @param rs the socket that received the response
694 * @param dns the response itself
695 * @param r number of bytes in dns
698 process_dns_result (void *cls,
699 struct GNUNET_DNSSTUB_RequestSocket *rs,
700 const struct GNUNET_TUN_DnsHeader *dns,
703 struct RequestRecord *rr;
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "Processing DNS result from stub resolver\n");
707 GNUNET_assert (NULL == cls);
708 rr = &requests[dns->id];
709 if ( (rr->phase != RP_INTERNET_DNS) ||
712 /* unexpected / bogus reply */
713 GNUNET_STATISTICS_update (stats,
714 gettext_noop ("# External DNS response discarded (no matching request)"),
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "Received DNS reply that does not match any pending request. Dropping.\n");
720 LOG (GNUNET_ERROR_TYPE_DEBUG,
721 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
722 (unsigned long long) rr->request_id);
723 GNUNET_free_non_null (rr->payload);
724 rr->payload = GNUNET_malloc (r);
725 memcpy (rr->payload, dns, r);
726 rr->payload_length = r;
732 * We got a new client. Make sure all new DNS requests pass by its desk.
735 * @param client the new client
736 * @param message the init message (unused)
739 handle_client_init (void *cls GNUNET_UNUSED,
740 struct GNUNET_SERVER_Client *client,
741 const struct GNUNET_MessageHeader *message)
743 struct ClientRecord *cr;
744 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
746 cr = GNUNET_new (struct ClientRecord);
748 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
749 GNUNET_SERVER_client_keep (client);
750 GNUNET_CONTAINER_DLL_insert (clients_head,
753 GNUNET_SERVER_notification_context_add (nc, client);
754 GNUNET_SERVER_receive_done (client, GNUNET_OK);
759 * We got a response from a client.
762 * @param client the client
763 * @param message the response
766 handle_client_response (void *cls GNUNET_UNUSED,
767 struct GNUNET_SERVER_Client *client,
768 const struct GNUNET_MessageHeader *message)
770 const struct GNUNET_DNS_Response *resp;
771 struct RequestRecord *rr;
776 msize = ntohs (message->size);
777 if (msize < sizeof (struct GNUNET_DNS_Response))
780 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
783 resp = (const struct GNUNET_DNS_Response*) message;
784 off = (uint16_t) resp->request_id;
786 LOG (GNUNET_ERROR_TYPE_DEBUG,
787 "Received DNS response with ID %llu from local client!\n",
788 (unsigned long long) resp->request_id);
789 if (rr->request_id != resp->request_id)
791 GNUNET_STATISTICS_update (stats,
792 gettext_noop ("# Client response discarded (no matching request)"),
794 GNUNET_SERVER_receive_done (client, GNUNET_OK);
797 for (i=0;i<rr->client_wait_list_length;i++)
799 if (NULL == rr->client_wait_list[i])
801 if (rr->client_wait_list[i]->client != client)
803 rr->client_wait_list[i] = NULL;
804 switch (ntohl (resp->drop_flag))
809 case 1: /* no change */
812 msize -= sizeof (struct GNUNET_DNS_Response);
813 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
814 (RP_REQUEST_MONITOR == rr->phase) ||
815 (RP_RESPONSE_MONITOR == rr->phase) )
818 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
822 GNUNET_free_non_null (rr->payload);
823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
824 "Changing DNS reply according to client specifications\n");
825 rr->payload = GNUNET_malloc (msize);
826 rr->payload_length = msize;
827 memcpy (rr->payload, &resp[1], msize);
828 if (rr->phase == RP_QUERY)
830 /* clear wait list, we're moving to MODIFY phase next */
831 GNUNET_array_grow (rr->client_wait_list,
832 rr->client_wait_list_length,
835 /* if query changed to answer, move past DNS resolution phase... */
836 if ( (RP_QUERY == rr->phase) &&
837 (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
838 ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
840 rr->phase = RP_INTERNET_DNS;
841 GNUNET_array_grow (rr->client_wait_list,
842 rr->client_wait_list_length,
848 GNUNET_SERVER_receive_done (client, GNUNET_OK);
851 /* odd, client was not on our list for the request, that ought
854 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
859 * Functions with this signature are called whenever a complete
860 * message is received by the tokenizer from the DNS hijack process.
863 * @param client identification of the client
864 * @param message the actual message, a DNS request we should handle
867 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
868 const struct GNUNET_MessageHeader *message)
871 const struct GNUNET_TUN_Layer2PacketHeader *tun;
872 const struct GNUNET_TUN_IPv4Header *ip4;
873 const struct GNUNET_TUN_IPv6Header *ip6;
874 const struct GNUNET_TUN_UdpHeader *udp;
875 const struct GNUNET_TUN_DnsHeader *dns;
876 struct RequestRecord *rr;
877 struct sockaddr_in *srca4;
878 struct sockaddr_in6 *srca6;
879 struct sockaddr_in *dsta4;
880 struct sockaddr_in6 *dsta6;
882 LOG (GNUNET_ERROR_TYPE_DEBUG,
883 "Intercepted message via DNS hijacker\n");
884 msize = ntohs (message->size);
885 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
887 /* non-IP packet received on TUN!? */
891 msize -= sizeof (struct GNUNET_MessageHeader);
892 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
893 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
894 switch (ntohs (tun->proto))
897 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
898 ip6 = NULL; /* make compiler happy */
899 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
900 (ip4->version != 4) ||
901 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
902 (ntohs(ip4->total_length) != msize) ||
903 (ip4->protocol != IPPROTO_UDP) )
905 /* non-IP/UDP packet received on TUN (or with options) */
906 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
907 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
910 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
911 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
914 ip4 = NULL; /* make compiler happy */
915 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
916 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
917 (ip6->version != 6) ||
918 (ntohs (ip6->payload_length) != msize) ||
919 (ip6->next_header != IPPROTO_UDP) )
921 /* non-IP/UDP packet received on TUN (or with extensions) */
922 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
923 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
926 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
927 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
930 /* non-IP packet received on TUN!? */
931 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
932 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
933 (unsigned int) msize,
937 if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) ||
938 (DNS_PORT != ntohs (udp->destination_port)) )
940 /* non-DNS packet received on TUN, ignore */
941 GNUNET_STATISTICS_update (stats,
942 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
946 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
947 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
948 rr = &requests[dns->id];
950 /* clean up from previous request */
951 GNUNET_free_non_null (rr->payload);
953 GNUNET_array_grow (rr->client_wait_list,
954 rr->client_wait_list_length,
957 /* setup new request */
959 switch (ntohs (tun->proto))
963 srca4 = (struct sockaddr_in*) &rr->src_addr;
964 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
965 memset (srca4, 0, sizeof (struct sockaddr_in));
966 memset (dsta4, 0, sizeof (struct sockaddr_in));
967 srca4->sin_family = AF_INET;
968 dsta4->sin_family = AF_INET;
969 srca4->sin_addr = ip4->source_address;
970 dsta4->sin_addr = ip4->destination_address;
971 srca4->sin_port = udp->source_port;
972 dsta4->sin_port = udp->destination_port;
973 #if HAVE_SOCKADDR_IN_SIN_LEN
974 srca4->sin_len = sizeof (struct sockaddr_in);
975 dsta4->sin_len = sizeof (struct sockaddr_in);
981 srca6 = (struct sockaddr_in6*) &rr->src_addr;
982 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
983 memset (srca6, 0, sizeof (struct sockaddr_in6));
984 memset (dsta6, 0, sizeof (struct sockaddr_in6));
985 srca6->sin6_family = AF_INET6;
986 dsta6->sin6_family = AF_INET6;
987 srca6->sin6_addr = ip6->source_address;
988 dsta6->sin6_addr = ip6->destination_address;
989 srca6->sin6_port = udp->source_port;
990 dsta6->sin6_port = udp->destination_port;
991 #if HAVE_SOCKADDR_IN_SIN_LEN
992 srca6->sin6_len = sizeof (struct sockaddr_in6);
993 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1000 rr->payload = GNUNET_malloc (msize);
1001 rr->payload_length = msize;
1002 memcpy (rr->payload, dns, msize);
1003 rr->request_id = dns->id | (request_id_gen << 16);
1005 LOG (GNUNET_ERROR_TYPE_DEBUG,
1006 "Creating new DNS request %llu\n",
1007 (unsigned long long) rr->request_id);
1008 GNUNET_STATISTICS_update (stats,
1009 gettext_noop ("# DNS requests received via TUN interface"),
1011 /* start request processing state machine */
1018 * @param cls closure
1019 * @param server the initialized server
1020 * @param cfg_ configuration to use
1023 run (void *cls, struct GNUNET_SERVER_Handle *server,
1024 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1026 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1027 /* callback, cls, type, size */
1028 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1029 sizeof (struct GNUNET_DNS_Register)},
1030 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1038 struct in_addr dns_exit4;
1039 struct in6_addr dns_exit6;
1044 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
1046 GNUNET_OS_check_helper_binary (binary, GNUNET_YES, NULL)) // TODO: once we have a windows-testcase, add test parameters here
1048 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1049 _("`%s' must be installed SUID, refusing to run\n"),
1052 GNUNET_free (binary);
1055 GNUNET_free (binary);
1056 stats = GNUNET_STATISTICS_create ("dns", cfg);
1057 nc = GNUNET_SERVER_notification_context_create (server, 1);
1058 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1061 if ( ( (GNUNET_OK !=
1062 GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1065 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1066 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1068 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "dns", "DNS_EXIT",
1069 _("need a valid IPv4 or IPv6 address\n"));
1070 GNUNET_free_non_null (dns_exit);
1073 dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1074 GNUNET_free_non_null (dns_exit);
1075 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1076 if (GNUNET_SYSERR ==
1077 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1079 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1080 "No entry 'IFNAME' in configuration!\n");
1081 GNUNET_SCHEDULER_shutdown ();
1084 helper_argv[1] = ifc_name;
1085 if ( (GNUNET_SYSERR ==
1086 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1089 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1090 "No entry 'IPV6ADDR' in configuration!\n");
1091 GNUNET_SCHEDULER_shutdown ();
1094 helper_argv[2] = ipv6addr;
1095 if (GNUNET_SYSERR ==
1096 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1099 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1100 "No entry 'IPV6PREFIX' in configuration!\n");
1101 GNUNET_SCHEDULER_shutdown ();
1104 helper_argv[3] = ipv6prefix;
1106 if (GNUNET_SYSERR ==
1107 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1110 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1111 "No entry 'IPV4ADDR' in configuration!\n");
1112 GNUNET_SCHEDULER_shutdown ();
1115 helper_argv[4] = ipv4addr;
1116 if (GNUNET_SYSERR ==
1117 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1120 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1121 "No entry 'IPV4MASK' in configuration!\n");
1122 GNUNET_SCHEDULER_shutdown ();
1125 helper_argv[5] = ipv4mask;
1126 helper_argv[6] = NULL;
1127 hijacker = GNUNET_HELPER_start (GNUNET_NO,
1128 "gnunet-helper-dns",
1130 &process_helper_messages,
1132 GNUNET_SERVER_add_handlers (server, handlers);
1133 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1138 * The main function for the dns service.
1140 * @param argc number of arguments from the command line
1141 * @param argv command line arguments
1142 * @return 0 ok, 1 on error
1145 main (int argc, char *const *argv)
1147 /* make use of SGID capabilities on POSIX */
1148 /* FIXME: this might need a port on systems without 'getresgid' */
1154 if (-1 == getresgid (&rgid, &egid, &sgid))
1157 "getresgid failed: %s\n",
1160 else if (sgid != rgid)
1162 if (-1 == setregid (sgid, sgid))
1163 fprintf (stderr, "setregid failed: %s\n", strerror (errno));
1166 return (GNUNET_OK ==
1167 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1168 &run, NULL)) ? global_ret : 1;
1172 /* end of gnunet-service-dns.c */