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
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., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, 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_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;
146 * Entry we keep for each active request.
152 * List of clients that still need to see this request (each entry
153 * is set to NULL when the client is done).
155 struct ClientRecord **client_wait_list;
158 * Payload of the UDP packet (the UDP payload), can be either query
159 * or already the response.
164 * Socket we are using to transmit this request (must match if we receive
167 struct GNUNET_DNSSTUB_RequestSocket *rs;
170 * Source address of the original request (for sending response).
172 struct sockaddr_storage src_addr;
175 * Destination address of the original request (for potential use as exit).
177 struct sockaddr_storage dst_addr;
180 * ID of this request, also basis for hashing. Lowest 16 bit will
181 * be our message ID when doing a global DNS request and our index
182 * into the 'requests' array.
187 * Number of bytes in payload.
189 size_t payload_length;
192 * Length of the @e client_wait_list.
194 unsigned int client_wait_list_length;
197 * In which phase this this request?
199 enum RequestPhase phase;
205 * Global return value from 'main'.
207 static int global_ret;
210 * The configuration to use
212 static const struct GNUNET_CONFIGURATION_Handle *cfg;
217 static struct GNUNET_STATISTICS_Handle *stats;
220 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
222 static struct GNUNET_HELPER_Handle *hijacker;
225 * Command-line arguments we are giving to the hijacker process.
227 static char *helper_argv[8];
230 * Head of DLL of clients we consult.
232 static struct ClientRecord *clients_head;
235 * Tail of DLL of clients we consult.
237 static struct ClientRecord *clients_tail;
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.
278 cleanup_task (void *cls GNUNET_UNUSED)
280 if (NULL != hijacker)
282 GNUNET_HELPER_stop (hijacker, GNUNET_NO);
285 for (unsigned int i=0;i<8;i++)
286 GNUNET_free_non_null (helper_argv[i]);
287 for (unsigned int i=0;i<=UINT16_MAX;i++)
288 cleanup_rr (&requests[i]);
291 GNUNET_STATISTICS_destroy (stats,
297 GNUNET_DNSSTUB_stop (dnsstub);
304 * We're done with some request, finish processing.
306 * @param rr request send to the network or just clean up.
309 request_done (struct RequestRecord *rr)
311 struct GNUNET_MessageHeader *hdr;
313 uint16_t source_port;
314 uint16_t destination_port;
316 GNUNET_array_grow (rr->client_wait_list,
317 rr->client_wait_list_length,
319 if (RP_RESPONSE_MONITOR != rr->phase)
321 /* no response, drop */
322 LOG (GNUNET_ERROR_TYPE_DEBUG,
323 "Got no response for request %llu, dropping\n",
324 (unsigned long long) rr->request_id);
329 LOG (GNUNET_ERROR_TYPE_DEBUG,
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)
338 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
341 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
348 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
349 reply_len += rr->payload_length;
350 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
352 /* response too big, drop */
353 GNUNET_break (0); /* how can this be? */
358 char buf[reply_len] GNUNET_ALIGN;
360 struct GNUNET_TUN_IPv4Header ip4;
361 struct GNUNET_TUN_IPv6Header ip6;
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);
369 /* first, TUN header */
371 struct GNUNET_TUN_Layer2PacketHeader tun;
373 tun.flags = htons (0);
374 if (rr->src_addr.ss_family == AF_INET)
375 tun.proto = htons (ETH_P_IPV4);
377 tun.proto = htons (ETH_P_IPV6);
378 GNUNET_memcpy (&buf[off],
380 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 GNUNET_memcpy (&buf[off],
407 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
408 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
410 source_port = dst->sin6_port;
411 destination_port = src->sin6_port;
412 GNUNET_TUN_initialize_ipv6_header (&ip6,
414 reply_len - off - sizeof (struct GNUNET_TUN_IPv6Header),
417 GNUNET_memcpy (&buf[off],
429 struct GNUNET_TUN_UdpHeader udp;
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)
435 GNUNET_TUN_calculate_udp4_checksum (&ip4,
440 GNUNET_TUN_calculate_udp6_checksum (&ip6,
444 GNUNET_memcpy (&buf[off],
450 /* now DNS payload */
452 GNUNET_memcpy (&buf[off], rr->payload, rr->payload_length);
453 off += rr->payload_length;
455 /* final checks & sending */
456 GNUNET_assert (off == reply_len);
457 (void) GNUNET_HELPER_send (hijacker,
461 GNUNET_STATISTICS_update (stats,
462 gettext_noop ("# DNS requests answered via TUN interface"),
465 /* clean up, we're done */
471 * Show the payload of the given request record to the client
472 * (and wait for a response).
474 * @param rr request to send to client
475 * @param cr client to send the response to
478 send_request_to_client (struct RequestRecord *rr,
479 struct ClientRecord *cr)
481 struct GNUNET_MQ_Envelope *env;
482 struct GNUNET_DNS_Request *req;
484 if (sizeof (struct GNUNET_DNS_Request) + rr->payload_length >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
490 LOG (GNUNET_ERROR_TYPE_DEBUG,
491 "Sending information about request %llu to local client\n",
492 (unsigned long long) rr->request_id);
493 env = GNUNET_MQ_msg_extra (req,
495 GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
496 req->reserved = htonl (0);
497 req->request_id = rr->request_id;
498 GNUNET_memcpy (&req[1],
501 GNUNET_MQ_send (cr->mq,
507 * Callback called from DNSSTUB resolver when a resolution
511 * @param rs the socket that received the response
512 * @param dns the response itself
513 * @param r number of bytes in dns
516 process_dns_result (void *cls,
517 struct GNUNET_DNSSTUB_RequestSocket *rs,
518 const struct GNUNET_TUN_DnsHeader *dns,
523 * A client has completed its processing for this
526 * @param rr request to process further
529 next_phase (struct RequestRecord *rr)
531 struct ClientRecord *cr;
535 if (rr->phase == RP_DROP)
541 for (unsigned int j=0;j<rr->client_wait_list_length;j++)
543 if (NULL != rr->client_wait_list[j])
551 send_request_to_client (rr,
552 rr->client_wait_list[nz]);
555 /* done with current phase, advance! */
556 LOG (GNUNET_ERROR_TYPE_DEBUG,
557 "Request %llu now in phase %d\n",
563 rr->phase = RP_REQUEST_MONITOR;
564 for (cr = clients_head; NULL != cr; cr = cr->next)
566 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
567 GNUNET_array_append (rr->client_wait_list,
568 rr->client_wait_list_length,
573 case RP_REQUEST_MONITOR:
574 rr->phase = RP_QUERY;
575 for (cr = clients_head; NULL != cr; cr = cr->next)
577 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
578 GNUNET_array_append (rr->client_wait_list,
579 rr->client_wait_list_length,
585 switch (rr->dst_addr.ss_family)
588 salen = sizeof (struct sockaddr_in);
591 salen = sizeof (struct sockaddr_in6);
597 rr->phase = RP_INTERNET_DNS;
598 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
599 (struct sockaddr*) &rr->dst_addr,
607 GNUNET_STATISTICS_update (stats,
608 gettext_noop ("# DNS exit failed (failed to open socket)"),
615 case RP_INTERNET_DNS:
616 rr->phase = RP_MODIFY;
617 for (cr = clients_head; NULL != cr; cr = cr->next)
619 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
620 GNUNET_array_append (rr->client_wait_list,
621 rr->client_wait_list_length,
627 rr->phase = RP_RESPONSE_MONITOR;
628 for (cr = clients_head; NULL != cr; cr = cr->next)
630 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
631 GNUNET_array_append (rr->client_wait_list,
632 rr->client_wait_list_length,
637 case RP_RESPONSE_MONITOR:
652 * A client connected, setup our data structures.
655 * @param client handle of client that connected
656 * @param mq message queue to talk to @a client
657 * @return our `struct ClientRecord`
660 client_connect_cb (void *cls,
661 struct GNUNET_SERVICE_Client *client,
662 struct GNUNET_MQ_Handle *mq)
664 struct ClientRecord *cr = cls;
666 cr = GNUNET_new (struct ClientRecord);
669 GNUNET_CONTAINER_DLL_insert (clients_head,
677 * A client disconnected, clean up after it.
680 * @param client handle of client that disconnected
681 * @param app_ctx our `struct ClientRecord`
684 client_disconnect_cb (void *cls,
685 struct GNUNET_SERVICE_Client *client,
688 struct ClientRecord *cr = app_ctx;
689 struct RequestRecord *rr;
691 GNUNET_CONTAINER_DLL_remove (clients_head,
694 for (unsigned int i=0;i<UINT16_MAX;i++)
697 if (0 == rr->client_wait_list_length)
698 continue; /* not in use */
699 for (unsigned int j=0;j<rr->client_wait_list_length;j++)
701 if (rr->client_wait_list[j] == cr)
703 rr->client_wait_list[j] = NULL;
713 * Callback called from DNSSTUB resolver when a resolution
717 * @param rs the socket that received the response
718 * @param dns the response itself
719 * @param r number of bytes in dns
722 process_dns_result (void *cls,
723 struct GNUNET_DNSSTUB_RequestSocket *rs,
724 const struct GNUNET_TUN_DnsHeader *dns,
727 struct RequestRecord *rr;
729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
730 "Processing DNS result from stub resolver\n");
731 GNUNET_assert (NULL == cls);
732 rr = &requests[dns->id];
733 if ( (rr->phase != RP_INTERNET_DNS) ||
736 /* unexpected / bogus reply */
737 GNUNET_STATISTICS_update (stats,
738 gettext_noop ("# External DNS response discarded (no matching request)"),
740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
741 "Received DNS reply that does not match any pending request. Dropping.\n");
744 LOG (GNUNET_ERROR_TYPE_DEBUG,
745 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
746 (unsigned long long) rr->request_id);
747 GNUNET_free_non_null (rr->payload);
748 rr->payload = GNUNET_malloc (r);
749 GNUNET_memcpy (rr->payload,
752 rr->payload_length = r;
758 * We got a new client. Make sure all new DNS requests pass by its desk.
760 * @param cls the client
761 * @param reg the init message
764 handle_client_init (void *cls,
765 const struct GNUNET_DNS_Register *reg)
767 struct ClientRecord *cr = cls;
769 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
770 GNUNET_SERVICE_client_continue (cr->client);
775 * Check a response from a client.
777 * @param cls the client
778 * @param resp the response
779 * @return #GNUNET_OK (always fine)
782 check_client_response (void *cls,
783 const struct GNUNET_DNS_Response *resp)
785 return GNUNET_OK; /* any payload is acceptable */
790 * Handle a response from a client.
792 * @param cls the client
793 * @param resp the response
796 handle_client_response (void *cls,
797 const struct GNUNET_DNS_Response *resp)
799 struct ClientRecord *cr = cls;
800 struct RequestRecord *rr;
804 msize = ntohs (resp->header.size);
805 off = (uint16_t) resp->request_id;
807 LOG (GNUNET_ERROR_TYPE_DEBUG,
808 "Received DNS response with ID %llu from local client!\n",
809 (unsigned long long) resp->request_id);
810 if (rr->request_id != resp->request_id)
812 GNUNET_STATISTICS_update (stats,
813 gettext_noop ("# Client response discarded (no matching request)"),
816 GNUNET_SERVICE_client_continue (cr->client);
819 for (unsigned int i=0;i<rr->client_wait_list_length;i++)
821 if (NULL == rr->client_wait_list[i])
823 if (rr->client_wait_list[i] != cr)
825 rr->client_wait_list[i] = NULL;
826 switch (ntohl (resp->drop_flag))
831 case 1: /* no change */
834 msize -= sizeof (struct GNUNET_DNS_Response);
835 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
836 (RP_REQUEST_MONITOR == rr->phase) ||
837 (RP_RESPONSE_MONITOR == rr->phase) )
840 GNUNET_SERVICE_client_drop (cr->client);
844 GNUNET_free_non_null (rr->payload);
845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
846 "Changing DNS reply according to client specifications\n");
847 rr->payload = GNUNET_malloc (msize);
848 rr->payload_length = msize;
849 GNUNET_memcpy (rr->payload, &resp[1], msize);
850 if (rr->phase == RP_QUERY)
852 /* clear wait list, we're moving to MODIFY phase next */
853 GNUNET_array_grow (rr->client_wait_list,
854 rr->client_wait_list_length,
857 /* if query changed to answer, move past DNS resolution phase... */
858 if ( (RP_QUERY == rr->phase) &&
859 (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
860 ((struct GNUNET_TUN_DnsFlags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
862 rr->phase = RP_INTERNET_DNS;
863 GNUNET_array_grow (rr->client_wait_list,
864 rr->client_wait_list_length,
870 GNUNET_SERVICE_client_continue (cr->client);
873 /* odd, client was not on our list for the request, that ought
876 GNUNET_SERVICE_client_drop (cr->client);
881 * Functions with this signature are called whenever a complete
882 * message is received by the tokenizer from the DNS hijack process.
885 * @param client identification of the client
886 * @param message the actual message, a DNS request we should handle
889 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
890 const struct GNUNET_MessageHeader *message)
893 const struct GNUNET_TUN_Layer2PacketHeader *tun;
894 const struct GNUNET_TUN_IPv4Header *ip4;
895 const struct GNUNET_TUN_IPv6Header *ip6;
896 const struct GNUNET_TUN_UdpHeader *udp;
897 const struct GNUNET_TUN_DnsHeader *dns;
898 struct RequestRecord *rr;
899 struct sockaddr_in *srca4;
900 struct sockaddr_in6 *srca6;
901 struct sockaddr_in *dsta4;
902 struct sockaddr_in6 *dsta6;
904 LOG (GNUNET_ERROR_TYPE_DEBUG,
905 "Intercepted message via DNS hijacker\n");
906 msize = ntohs (message->size);
907 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
909 /* non-IP packet received on TUN!? */
913 msize -= sizeof (struct GNUNET_MessageHeader);
914 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
915 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
916 switch (ntohs (tun->proto))
919 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
920 ip6 = NULL; /* make compiler happy */
921 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
922 (ip4->version != 4) ||
923 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
924 (ntohs(ip4->total_length) != msize) ||
925 (ip4->protocol != IPPROTO_UDP) )
927 /* non-IP/UDP packet received on TUN (or with options) */
928 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
929 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
932 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
933 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
936 ip4 = NULL; /* make compiler happy */
937 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
938 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
939 (ip6->version != 6) ||
940 (ntohs (ip6->payload_length) != msize - sizeof (struct GNUNET_TUN_IPv6Header)) ||
941 (ip6->next_header != IPPROTO_UDP) )
943 /* non-IP/UDP packet received on TUN (or with extensions) */
944 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
945 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
948 udp = (const struct GNUNET_TUN_UdpHeader *) &ip6[1];
949 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
952 /* non-IP packet received on TUN!? */
953 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
954 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
955 (unsigned int) msize,
959 if ( (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader)) ||
960 (DNS_PORT != ntohs (udp->destination_port)) )
962 /* non-DNS packet received on TUN, ignore */
963 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
964 _("DNS interceptor got non-DNS packet (dropped)\n"));
965 GNUNET_STATISTICS_update (stats,
966 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
970 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
971 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
972 rr = &requests[dns->id];
974 /* clean up from previous request */
975 GNUNET_free_non_null (rr->payload);
977 GNUNET_array_grow (rr->client_wait_list,
978 rr->client_wait_list_length,
981 /* setup new request */
983 switch (ntohs (tun->proto))
987 srca4 = (struct sockaddr_in*) &rr->src_addr;
988 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
989 memset (srca4, 0, sizeof (struct sockaddr_in));
990 memset (dsta4, 0, sizeof (struct sockaddr_in));
991 srca4->sin_family = AF_INET;
992 dsta4->sin_family = AF_INET;
993 srca4->sin_addr = ip4->source_address;
994 dsta4->sin_addr = ip4->destination_address;
995 srca4->sin_port = udp->source_port;
996 dsta4->sin_port = udp->destination_port;
997 #if HAVE_SOCKADDR_IN_SIN_LEN
998 srca4->sin_len = sizeof (struct sockaddr_in);
999 dsta4->sin_len = sizeof (struct sockaddr_in);
1005 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1006 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1007 memset (srca6, 0, sizeof (struct sockaddr_in6));
1008 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1009 srca6->sin6_family = AF_INET6;
1010 dsta6->sin6_family = AF_INET6;
1011 srca6->sin6_addr = ip6->source_address;
1012 dsta6->sin6_addr = ip6->destination_address;
1013 srca6->sin6_port = udp->source_port;
1014 dsta6->sin6_port = udp->destination_port;
1015 #if HAVE_SOCKADDR_IN_SIN_LEN
1016 srca6->sin6_len = sizeof (struct sockaddr_in6);
1017 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1024 rr->payload = GNUNET_malloc (msize);
1025 rr->payload_length = msize;
1026 GNUNET_memcpy (rr->payload, dns, msize);
1027 rr->request_id = dns->id | (request_id_gen << 16);
1029 LOG (GNUNET_ERROR_TYPE_DEBUG,
1030 "Creating new DNS request %llu\n",
1031 (unsigned long long) rr->request_id);
1032 GNUNET_STATISTICS_update (stats,
1033 gettext_noop ("# DNS requests received via TUN interface"),
1035 /* start request processing state machine */
1042 * @param cls closure
1043 * @param cfg_ configuration to use
1044 * @param service the initialized service
1048 const struct GNUNET_CONFIGURATION_Handle *cfg_,
1049 struct GNUNET_SERVICE_Handle *service)
1056 struct in_addr dns_exit4;
1057 struct in6_addr dns_exit6;
1063 stats = GNUNET_STATISTICS_create ("dns", cfg);
1064 GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
1067 if ( ( (GNUNET_OK !=
1068 GNUNET_CONFIGURATION_get_value_string (cfg,
1072 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1073 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1075 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
1078 _("need a valid IPv4 or IPv6 address\n"));
1079 GNUNET_free_non_null (dns_exit);
1082 dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1083 GNUNET_free_non_null (dns_exit);
1084 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
1086 GNUNET_OS_check_helper_binary (binary,
1088 NULL)) // TODO: once we have a windows-testcase, add test parameters here
1090 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1091 _("`%s' must be installed SUID, will not run DNS interceptor\n"),
1094 GNUNET_free (binary);
1097 GNUNET_free (binary);
1099 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1100 if (GNUNET_SYSERR ==
1101 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1103 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1104 "No entry 'IFNAME' in configuration!\n");
1105 GNUNET_SCHEDULER_shutdown ();
1108 helper_argv[1] = ifc_name;
1109 if ( (GNUNET_SYSERR ==
1110 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1113 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1114 "No entry 'IPV6ADDR' in configuration!\n");
1115 GNUNET_SCHEDULER_shutdown ();
1118 helper_argv[2] = ipv6addr;
1119 if (GNUNET_SYSERR ==
1120 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1123 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1124 "No entry 'IPV6PREFIX' in configuration!\n");
1125 GNUNET_SCHEDULER_shutdown ();
1128 helper_argv[3] = ipv6prefix;
1130 if (GNUNET_SYSERR ==
1131 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1135 "No entry 'IPV4ADDR' in configuration!\n");
1136 GNUNET_SCHEDULER_shutdown ();
1139 helper_argv[4] = ipv4addr;
1140 if (GNUNET_SYSERR ==
1141 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1145 "No entry 'IPV4MASK' in configuration!\n");
1146 GNUNET_SCHEDULER_shutdown ();
1149 helper_argv[5] = ipv4mask;
1151 nortsetup = GNUNET_CONFIGURATION_get_value_yesno (cfg, "dns",
1152 "SKIP_ROUTING_SETUP");
1153 if (GNUNET_YES == nortsetup)
1154 helper_argv[6] = GNUNET_strdup("1");
1156 helper_argv[6] = GNUNET_strdup("0");
1158 helper_argv[7] = NULL;
1159 hijacker = GNUNET_HELPER_start (GNUNET_NO,
1160 "gnunet-helper-dns",
1162 &process_helper_messages,
1168 * Define "main" method using service macro.
1172 GNUNET_SERVICE_OPTION_NONE,
1175 &client_disconnect_cb,
1177 GNUNET_MQ_hd_fixed_size (client_init,
1178 GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1179 struct GNUNET_DNS_Register,
1181 GNUNET_MQ_hd_var_size (client_response,
1182 GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE,
1183 struct GNUNET_DNS_Response,
1185 GNUNET_MQ_handler_end ());
1188 /* FIXME: this might need a port on systems without 'getresgid' */
1191 * Enable use of SGID capabilities on POSIX
1193 void __attribute__ ((constructor))
1200 if (-1 == getresgid (&rgid,
1205 "getresgid failed: %s\n",
1208 else if (sgid != rgid)
1210 if (-1 == setregid (sgid,
1213 "setregid failed: %s\n",
1220 /* end of gnunet-service-dns.c */