2 This file is part of GNUnet.
3 (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_mesh_service.h"
50 #include "gnunet_statistics_service.h"
51 #include "gnunet_tun_lib.h"
55 * Generic logging shorthand
57 #define LOG(kind, ...) \
58 GNUNET_log_from (kind, "dns", __VA_ARGS__);
62 * Phases each request goes through.
67 * Request has just been received.
72 * Showing the request to all monitor clients. If
73 * client list is empty, will enter QUERY phase.
78 * Showing the request to PRE-RESOLUTION clients to find an answer.
79 * If client list is empty, will trigger global DNS request.
84 * Global Internet query is now pending.
89 * Client (or global DNS request) has resulted in a response.
90 * Forward to all POST-RESOLUTION clients. If client list is empty,
91 * will enter RESPONSE_MONITOR phase.
96 * Showing the request to all monitor clients. If
97 * client list is empty, give the result to the hijacker (and be done).
102 * Some client has told us to drop the request.
109 * Entry we keep for each client.
114 * Kept in doubly-linked list.
116 struct ClientRecord *next;
119 * Kept in doubly-linked list.
121 struct ClientRecord *prev;
124 * Handle to the client.
126 struct GNUNET_SERVER_Client *client;
129 * Flags for the client.
131 enum GNUNET_DNS_Flags flags;
137 * Entry we keep for each active request.
143 * List of clients that still need to see this request (each entry
144 * is set to NULL when the client is done).
146 struct ClientRecord **client_wait_list;
149 * Payload of the UDP packet (the UDP payload), can be either query
150 * or already the response.
155 * Socket we are using to transmit this request (must match if we receive
158 struct GNUNET_DNSSTUB_RequestSocket *rs;
161 * Source address of the original request (for sending response).
163 struct sockaddr_storage src_addr;
166 * Destination address of the original request (for potential use as exit).
168 struct sockaddr_storage dst_addr;
171 * ID of this request, also basis for hashing. Lowest 16 bit will
172 * be our message ID when doing a global DNS request and our index
173 * into the 'requests' array.
178 * Number of bytes in payload.
180 size_t payload_length;
183 * Length of the client wait list.
185 unsigned int client_wait_list_length;
188 * In which phase this this request?
190 enum RequestPhase phase;
196 * State we keep for each DNS tunnel that terminates at this node.
202 * Associated MESH tunnel.
204 struct GNUNET_MESH_Tunnel *tunnel;
207 * Active request for sending a reply.
209 struct GNUNET_MESH_TransmitHandle *th;
212 * DNS reply ready for transmission.
217 * Socket we are using to transmit this request (must match if we receive
220 struct GNUNET_DNSSTUB_RequestSocket *rs;
223 * Number of bytes in 'reply'.
228 * Original DNS request ID as used by the client.
230 uint16_t original_id;
233 * DNS request ID that we used for forwarding.
240 * Global return value from 'main'.
242 static int global_ret;
245 * The configuration to use
247 static const struct GNUNET_CONFIGURATION_Handle *cfg;
252 static struct GNUNET_STATISTICS_Handle *stats;
255 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
257 static struct GNUNET_HELPER_Handle *hijacker;
260 * Command-line arguments we are giving to the hijacker process.
262 static char *helper_argv[7];
265 * Head of DLL of clients we consult.
267 static struct ClientRecord *clients_head;
270 * Tail of DLL of clients we consult.
272 static struct ClientRecord *clients_tail;
275 * Our notification context.
277 static struct GNUNET_SERVER_NotificationContext *nc;
280 * Array of all open requests from tunnels.
282 static struct TunnelState *tunnels[UINT16_MAX + 1];
285 * Array of all open requests.
287 static struct RequestRecord requests[UINT16_MAX + 1];
290 * Generator for unique request IDs.
292 static uint64_t request_id_gen;
295 * Handle to the MESH service (for receiving DNS queries), or NULL
296 * if we are not a DNS exit.
298 static struct GNUNET_MESH_Handle *mesh;
301 * Handle to the DNS Stub resolver.
303 static struct GNUNET_DNSSTUB_Context *dnsstub;
307 * We're done processing a DNS request, free associated memory.
309 * @param rr request to clean up
312 cleanup_rr (struct RequestRecord *rr)
314 GNUNET_free_non_null (rr->payload);
316 rr->payload_length = 0;
317 GNUNET_array_grow (rr->client_wait_list,
318 rr->client_wait_list_length,
324 * Task run during shutdown.
330 cleanup_task (void *cls GNUNET_UNUSED,
331 const struct GNUNET_SCHEDULER_TaskContext *tc)
335 GNUNET_HELPER_stop (hijacker);
338 GNUNET_free_non_null (helper_argv[i]);
339 for (i=0;i<=UINT16_MAX;i++)
340 cleanup_rr (&requests[i]);
341 GNUNET_SERVER_notification_context_destroy (nc);
345 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
350 GNUNET_DNSSTUB_stop (dnsstub);
355 GNUNET_MESH_disconnect(mesh);
362 * We're done with some request, finish processing.
364 * @param rr request send to the network or just clean up.
367 request_done (struct RequestRecord *rr)
369 struct GNUNET_MessageHeader *hdr;
371 uint16_t source_port;
372 uint16_t destination_port;
374 GNUNET_array_grow (rr->client_wait_list,
375 rr->client_wait_list_length,
377 if (RP_RESPONSE_MONITOR != rr->phase)
379 /* no response, drop */
380 LOG (GNUNET_ERROR_TYPE_DEBUG,
381 "Got no response for request %llu, dropping\n",
382 (unsigned long long) rr->request_id);
387 LOG (GNUNET_ERROR_TYPE_DEBUG,
388 "Transmitting response for request %llu\n",
389 (unsigned long long) rr->request_id);
390 /* send response via hijacker */
391 reply_len = sizeof (struct GNUNET_MessageHeader);
392 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
393 switch (rr->src_addr.ss_family)
396 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
399 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
406 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
407 reply_len += rr->payload_length;
408 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
410 /* response too big, drop */
411 GNUNET_break (0); /* how can this be? */
416 char buf[reply_len] GNUNET_ALIGN;
418 struct GNUNET_TUN_IPv4Header ip4;
419 struct GNUNET_TUN_IPv6Header ip6;
421 /* first, GNUnet message header */
422 hdr = (struct GNUNET_MessageHeader*) buf;
423 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
424 hdr->size = htons ((uint16_t) reply_len);
425 off = sizeof (struct GNUNET_MessageHeader);
427 /* first, TUN header */
429 struct GNUNET_TUN_Layer2PacketHeader tun;
431 tun.flags = htons (0);
432 if (rr->src_addr.ss_family == AF_INET)
433 tun.proto = htons (ETH_P_IPV4);
435 tun.proto = htons (ETH_P_IPV6);
436 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
437 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
441 switch (rr->src_addr.ss_family)
445 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
446 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
448 source_port = dst->sin_port;
449 destination_port = src->sin_port;
450 GNUNET_TUN_initialize_ipv4_header (&ip4,
452 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
455 memcpy (&buf[off], &ip4, sizeof (ip4));
461 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
462 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
464 source_port = dst->sin6_port;
465 destination_port = src->sin6_port;
466 GNUNET_TUN_initialize_ipv6_header (&ip6,
468 reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
471 memcpy (&buf[off], &ip6, sizeof (ip6));
481 struct GNUNET_TUN_UdpHeader udp;
483 udp.source_port = source_port;
484 udp.destination_port = destination_port;
485 udp.len = htons (reply_len - off);
486 if (AF_INET == rr->src_addr.ss_family)
487 GNUNET_TUN_calculate_udp4_checksum (&ip4,
492 GNUNET_TUN_calculate_udp6_checksum (&ip6,
496 memcpy (&buf[off], &udp, sizeof (udp));
500 /* now DNS payload */
502 memcpy (&buf[off], rr->payload, rr->payload_length);
503 off += rr->payload_length;
505 /* final checks & sending */
506 GNUNET_assert (off == reply_len);
507 (void) GNUNET_HELPER_send (hijacker,
511 GNUNET_STATISTICS_update (stats,
512 gettext_noop ("# DNS requests answered via TUN interface"),
515 /* clean up, we're done */
521 * Show the payload of the given request record to the client
522 * (and wait for a response).
524 * @param rr request to send to client
525 * @param client client to send the response to
528 send_request_to_client (struct RequestRecord *rr,
529 struct GNUNET_SERVER_Client *client)
531 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length] GNUNET_ALIGN;
532 struct GNUNET_DNS_Request *req;
534 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Sending information about request %llu to local client\n",
542 (unsigned long long) rr->request_id);
543 req = (struct GNUNET_DNS_Request*) buf;
544 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
545 req->header.size = htons (sizeof (buf));
546 req->reserved = htonl (0);
547 req->request_id = rr->request_id;
548 memcpy (&req[1], rr->payload, rr->payload_length);
549 GNUNET_SERVER_notification_context_unicast (nc,
558 * Callback called from DNSSTUB resolver when a resolution
562 * @param rs the socket that received the response
563 * @param dns the response itself
564 * @param r number of bytes in dns
567 process_dns_result (void *cls,
568 struct GNUNET_DNSSTUB_RequestSocket *rs,
569 const struct GNUNET_TUN_DnsHeader *dns,
574 * A client has completed its processing for this
577 * @param rr request to process further
580 next_phase (struct RequestRecord *rr)
582 struct ClientRecord *cr;
587 if (rr->phase == RP_DROP)
593 for (j=0;j<rr->client_wait_list_length;j++)
595 if (NULL != rr->client_wait_list[j])
603 send_request_to_client (rr, rr->client_wait_list[nz]->client);
606 /* done with current phase, advance! */
607 LOG (GNUNET_ERROR_TYPE_DEBUG,
608 "Request %llu now in phase %d\n",
614 rr->phase = RP_REQUEST_MONITOR;
615 for (cr = clients_head; NULL != cr; cr = cr->next)
617 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
618 GNUNET_array_append (rr->client_wait_list,
619 rr->client_wait_list_length,
624 case RP_REQUEST_MONITOR:
625 rr->phase = RP_QUERY;
626 for (cr = clients_head; NULL != cr; cr = cr->next)
628 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
629 GNUNET_array_append (rr->client_wait_list,
630 rr->client_wait_list_length,
636 switch (rr->dst_addr.ss_family)
639 salen = sizeof (struct sockaddr_in);
642 salen = sizeof (struct sockaddr_in6);
648 rr->phase = RP_INTERNET_DNS;
649 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
650 (struct sockaddr*) &rr->dst_addr,
658 GNUNET_STATISTICS_update (stats,
659 gettext_noop ("# DNS exit failed (failed to open socket)"),
665 case RP_INTERNET_DNS:
666 rr->phase = RP_MODIFY;
667 for (cr = clients_head; NULL != cr; cr = cr->next)
669 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
670 GNUNET_array_append (rr->client_wait_list,
671 rr->client_wait_list_length,
677 rr->phase = RP_RESPONSE_MONITOR;
678 for (cr = clients_head; NULL != cr; cr = cr->next)
680 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
681 GNUNET_array_append (rr->client_wait_list,
682 rr->client_wait_list_length,
687 case RP_RESPONSE_MONITOR:
702 * A client disconnected, clean up after it.
705 * @param client handle of client that disconnected
708 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
710 struct ClientRecord *cr;
711 struct RequestRecord *rr;
715 for (cr = clients_head; NULL != cr; cr = cr->next)
717 if (cr->client == client)
719 GNUNET_SERVER_client_drop (client);
720 GNUNET_CONTAINER_DLL_remove (clients_head,
723 for (i=0;i<UINT16_MAX;i++)
726 if (0 == rr->client_wait_list_length)
727 continue; /* not in use */
728 for (j=0;j<rr->client_wait_list_length;j++)
730 if (rr->client_wait_list[j] == cr)
732 rr->client_wait_list[j] = NULL;
745 * We got a reply from DNS for a request of a MESH tunnel. Send it
746 * via the tunnel (after changing the request ID back).
748 * @param cls the 'struct TunnelState'
749 * @param size number of bytes available in buf
750 * @param buf where to copy the reply
751 * @return number of bytes written to buf
754 transmit_reply_to_mesh (void *cls,
758 struct TunnelState *ts = cls;
762 struct GNUNET_MessageHeader hdr;
763 struct GNUNET_TUN_DnsHeader dns;
766 GNUNET_assert (ts->reply != NULL);
769 ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length;
770 GNUNET_assert (ret <= size);
771 hdr.size = htons (ret);
772 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
773 memcpy (&dns, ts->reply, sizeof (dns));
774 dns.id = ts->original_id;
776 memcpy (&cbuf[off], &hdr, sizeof (hdr));
778 memcpy (&cbuf[off], &dns, sizeof (dns));
780 memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
781 off += ts->reply_length - sizeof (dns);
782 GNUNET_free (ts->reply);
784 ts->reply_length = 0;
785 GNUNET_assert (ret == off);
792 * Callback called from DNSSTUB resolver when a resolution
796 * @param rs the socket that received the response
797 * @param dns the response itself
798 * @param r number of bytes in dns
801 process_dns_result (void *cls,
802 struct GNUNET_DNSSTUB_RequestSocket *rs,
803 const struct GNUNET_TUN_DnsHeader *dns,
806 struct RequestRecord *rr;
807 struct TunnelState *ts;
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 "Processing DNS result from stub resolver\n");
811 GNUNET_assert (NULL == cls);
812 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
813 ts = tunnels[dns->id];
816 ts = NULL; /* DNS responder address missmatch */
819 LOG (GNUNET_ERROR_TYPE_DEBUG,
820 "Got a response from the stub resolver for DNS request received via MESH!\n");
821 tunnels[dns->id] = NULL;
822 GNUNET_free_non_null (ts->reply);
823 ts->reply = GNUNET_malloc (r);
824 ts->reply_length = r;
825 memcpy (ts->reply, dns, r);
827 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
828 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
830 GNUNET_TIME_UNIT_FOREVER_REL,
832 sizeof (struct GNUNET_MessageHeader) + r,
833 &transmit_reply_to_mesh,
836 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
837 rr = &requests[dns->id];
838 if ( (rr->phase != RP_INTERNET_DNS) ||
843 /* unexpected / bogus reply */
844 GNUNET_STATISTICS_update (stats,
845 gettext_noop ("# External DNS response discarded (no matching request)"),
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 "Received DNS reply that does not match any pending request. Dropping.\n");
852 LOG (GNUNET_ERROR_TYPE_DEBUG,
853 "Got a response from the stub resolver for DNS request %llu intercepted locally!\n",
854 (unsigned long long) rr->request_id);
855 GNUNET_free_non_null (rr->payload);
856 rr->payload = GNUNET_malloc (r);
857 memcpy (rr->payload, dns, r);
858 rr->payload_length = r;
864 * We got a new client. Make sure all new DNS requests pass by its desk.
867 * @param client the new client
868 * @param message the init message (unused)
871 handle_client_init (void *cls GNUNET_UNUSED,
872 struct GNUNET_SERVER_Client *client,
873 const struct GNUNET_MessageHeader *message)
875 struct ClientRecord *cr;
876 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
878 cr = GNUNET_malloc (sizeof (struct ClientRecord));
880 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
881 GNUNET_SERVER_client_keep (client);
882 GNUNET_CONTAINER_DLL_insert (clients_head,
885 GNUNET_SERVER_notification_context_add (nc, client);
886 GNUNET_SERVER_receive_done (client, GNUNET_OK);
891 * We got a response from a client.
894 * @param client the client
895 * @param message the response
898 handle_client_response (void *cls GNUNET_UNUSED,
899 struct GNUNET_SERVER_Client *client,
900 const struct GNUNET_MessageHeader *message)
902 const struct GNUNET_DNS_Response *resp;
903 struct RequestRecord *rr;
908 msize = ntohs (message->size);
909 if (msize < sizeof (struct GNUNET_DNS_Response))
912 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
915 resp = (const struct GNUNET_DNS_Response*) message;
916 off = (uint16_t) resp->request_id;
918 LOG (GNUNET_ERROR_TYPE_DEBUG,
919 "Received DNS response with ID %llu from local client!\n",
920 (unsigned long long) resp->request_id);
921 if (rr->request_id != resp->request_id)
923 GNUNET_STATISTICS_update (stats,
924 gettext_noop ("# Client response discarded (no matching request)"),
926 GNUNET_SERVER_receive_done (client, GNUNET_OK);
929 for (i=0;i<rr->client_wait_list_length;i++)
931 if (NULL == rr->client_wait_list[i])
933 if (rr->client_wait_list[i]->client != client)
935 rr->client_wait_list[i] = NULL;
936 switch (ntohl (resp->drop_flag))
941 case 1: /* no change */
944 msize -= sizeof (struct GNUNET_DNS_Response);
945 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
946 (RP_REQUEST_MONITOR == rr->phase) ||
947 (RP_RESPONSE_MONITOR == rr->phase) )
950 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
954 GNUNET_free_non_null (rr->payload);
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956 "Changing DNS reply according to client specifications\n");
957 rr->payload = GNUNET_malloc (msize);
958 rr->payload_length = msize;
959 memcpy (rr->payload, &resp[1], msize);
960 if (rr->phase == RP_QUERY)
962 /* clear wait list, we're moving to MODIFY phase next */
963 GNUNET_array_grow (rr->client_wait_list,
964 rr->client_wait_list_length,
967 /* if query changed to answer, move past DNS resolution phase... */
968 if ( (RP_QUERY == rr->phase) &&
969 (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
970 ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
972 rr->phase = RP_INTERNET_DNS;
973 GNUNET_array_grow (rr->client_wait_list,
974 rr->client_wait_list_length,
980 GNUNET_SERVER_receive_done (client, GNUNET_OK);
983 /* odd, client was not on our list for the request, that ought
986 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
991 * Functions with this signature are called whenever a complete
992 * message is received by the tokenizer from the DNS hijack process.
995 * @param client identification of the client
996 * @param message the actual message, a DNS request we should handle
999 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1000 const struct GNUNET_MessageHeader *message)
1003 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1004 const struct GNUNET_TUN_IPv4Header *ip4;
1005 const struct GNUNET_TUN_IPv6Header *ip6;
1006 const struct GNUNET_TUN_UdpHeader *udp;
1007 const struct GNUNET_TUN_DnsHeader *dns;
1008 struct RequestRecord *rr;
1009 struct sockaddr_in *srca4;
1010 struct sockaddr_in6 *srca6;
1011 struct sockaddr_in *dsta4;
1012 struct sockaddr_in6 *dsta6;
1014 LOG (GNUNET_ERROR_TYPE_DEBUG,
1015 "Intercepted message via DNS hijacker\n");
1016 msize = ntohs (message->size);
1017 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1019 /* non-IP packet received on TUN!? */
1023 msize -= sizeof (struct GNUNET_MessageHeader);
1024 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1025 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1026 switch (ntohs (tun->proto))
1029 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1030 ip6 = NULL; /* make compiler happy */
1031 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1032 (ip4->version != 4) ||
1033 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1034 (ntohs(ip4->total_length) != msize) ||
1035 (ip4->protocol != IPPROTO_UDP) )
1037 /* non-IP/UDP packet received on TUN (or with options) */
1038 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1039 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1042 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1043 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1046 ip4 = NULL; /* make compiler happy */
1047 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1048 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1049 (ip6->version != 6) ||
1050 (ntohs (ip6->payload_length) != msize) ||
1051 (ip6->next_header != IPPROTO_UDP) )
1053 /* non-IP/UDP packet received on TUN (or with extensions) */
1054 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1055 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1058 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1059 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1062 /* non-IP packet received on TUN!? */
1063 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1064 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1065 (unsigned int) msize,
1066 ntohs (tun->proto));
1069 if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1071 /* non-DNS packet received on TUN, ignore */
1072 GNUNET_STATISTICS_update (stats,
1073 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1077 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1078 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1079 rr = &requests[dns->id];
1081 /* clean up from previous request */
1082 GNUNET_free_non_null (rr->payload);
1084 GNUNET_array_grow (rr->client_wait_list,
1085 rr->client_wait_list_length,
1088 /* setup new request */
1089 rr->phase = RP_INIT;
1090 switch (ntohs (tun->proto))
1094 srca4 = (struct sockaddr_in*) &rr->src_addr;
1095 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1096 memset (srca4, 0, sizeof (struct sockaddr_in));
1097 memset (dsta4, 0, sizeof (struct sockaddr_in));
1098 srca4->sin_family = AF_INET;
1099 dsta4->sin_family = AF_INET;
1100 srca4->sin_addr = ip4->source_address;
1101 dsta4->sin_addr = ip4->destination_address;
1102 srca4->sin_port = udp->source_port;
1103 dsta4->sin_port = udp->destination_port;
1104 #if HAVE_SOCKADDR_IN_SIN_LEN
1105 srca4->sin_len = sizeof (struct sockaddr_in);
1106 dsta4->sin_len = sizeof (struct sockaddr_in);
1112 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1113 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1114 memset (srca6, 0, sizeof (struct sockaddr_in6));
1115 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1116 srca6->sin6_family = AF_INET6;
1117 dsta6->sin6_family = AF_INET6;
1118 srca6->sin6_addr = ip6->source_address;
1119 dsta6->sin6_addr = ip6->destination_address;
1120 srca6->sin6_port = udp->source_port;
1121 dsta6->sin6_port = udp->destination_port;
1122 #if HAVE_SOCKADDR_IN_SIN_LEN
1123 srca6->sin6_len = sizeof (struct sockaddr_in6);
1124 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1131 rr->payload = GNUNET_malloc (msize);
1132 rr->payload_length = msize;
1133 memcpy (rr->payload, dns, msize);
1134 rr->request_id = dns->id | (request_id_gen << 16);
1136 LOG (GNUNET_ERROR_TYPE_DEBUG,
1137 "Creating new DNS request %llu\n",
1138 (unsigned long long) rr->request_id);
1139 GNUNET_STATISTICS_update (stats,
1140 gettext_noop ("# DNS requests received via TUN interface"),
1142 /* start request processing state machine */
1149 * Process a request via mesh to perform a DNS query.
1151 * @param cls closure, NULL
1152 * @param tunnel connection to the other end
1153 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1154 * @param sender who sent the message
1155 * @param message the actual message
1156 * @param atsi performance data for the connection
1157 * @return GNUNET_OK to keep the connection open,
1158 * GNUNET_SYSERR to close it (signal serious error)
1161 receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1163 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1164 const struct GNUNET_MessageHeader *message,
1165 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1167 struct TunnelState *ts = *tunnel_ctx;
1168 const struct GNUNET_TUN_DnsHeader *dns;
1169 size_t mlen = ntohs (message->size);
1170 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1171 char buf[dlen] GNUNET_ALIGN;
1172 struct GNUNET_TUN_DnsHeader *dout;
1174 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1176 GNUNET_break_op (0);
1177 return GNUNET_SYSERR;
1179 dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1180 ts->original_id = dns->id;
1181 if (tunnels[ts->my_id] == ts)
1182 tunnels[ts->my_id] = NULL;
1183 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1185 tunnels[ts->my_id] = ts;
1186 memcpy (buf, dns, dlen);
1187 dout = (struct GNUNET_TUN_DnsHeader *) buf;
1188 dout->id = ts->my_id;
1189 ts->rs = GNUNET_DNSSTUB_resolve2 (dnsstub,
1191 &process_dns_result,
1194 return GNUNET_SYSERR;
1200 * Callback from GNUNET_MESH for new tunnels.
1202 * @param cls closure
1203 * @param tunnel new handle to the tunnel
1204 * @param initiator peer that started the tunnel
1205 * @param ats performance information for the tunnel
1206 * @return initial tunnel context for the tunnel
1209 accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1210 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1211 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1213 struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1215 GNUNET_STATISTICS_update (stats,
1216 gettext_noop ("# Inbound MESH tunnels created"),
1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1219 "Received inbound tunnel from `%s'\n",
1220 GNUNET_i2s (initiator));
1221 ts->tunnel = tunnel;
1227 * Function called by mesh whenever an inbound tunnel is destroyed.
1228 * Should clean up any associated state.
1230 * @param cls closure (set from GNUNET_MESH_connect)
1231 * @param tunnel connection to the other end (henceforth invalid)
1232 * @param tunnel_ctx place where local state associated
1233 * with the tunnel is stored
1236 destroy_dns_tunnel (void *cls GNUNET_UNUSED,
1237 const struct GNUNET_MESH_Tunnel *tunnel,
1240 struct TunnelState *ts = tunnel_ctx;
1242 if (tunnels[ts->my_id] == ts)
1243 tunnels[ts->my_id] = NULL;
1245 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1246 GNUNET_free_non_null (ts->reply);
1252 * @param cls closure
1253 * @param server the initialized server
1254 * @param cfg_ configuration to use
1257 run (void *cls, struct GNUNET_SERVER_Handle *server,
1258 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1260 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1261 /* callback, cls, type, size */
1262 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1263 sizeof (struct GNUNET_DNS_Register)},
1264 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1272 struct in_addr dns_exit4;
1273 struct in6_addr dns_exit6;
1278 GNUNET_OS_check_helper_binary ("gnunet-helper-dns"))
1280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1281 _("`%s' must be installed SUID, refusing to run\n"),
1282 "gnunet-helper-dns");
1287 stats = GNUNET_STATISTICS_create ("dns", cfg);
1288 nc = GNUNET_SERVER_notification_context_create (server, 1);
1289 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1293 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) &&
1295 GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1298 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1299 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1301 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "dns", "DNS_EXIT",
1302 _("need a valid IPv4 or IPv6 address\n"));
1303 GNUNET_free_non_null (dns_exit);
1306 dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1307 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1308 if (GNUNET_SYSERR ==
1309 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1311 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1312 "No entry 'IFNAME' in configuration!\n");
1313 GNUNET_SCHEDULER_shutdown ();
1316 helper_argv[1] = ifc_name;
1317 if ( (GNUNET_SYSERR ==
1318 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1321 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1322 "No entry 'IPV6ADDR' in configuration!\n");
1323 GNUNET_SCHEDULER_shutdown ();
1326 helper_argv[2] = ipv6addr;
1327 if (GNUNET_SYSERR ==
1328 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1331 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1332 "No entry 'IPV6PREFIX' in configuration!\n");
1333 GNUNET_SCHEDULER_shutdown ();
1336 helper_argv[3] = ipv6prefix;
1338 if (GNUNET_SYSERR ==
1339 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1342 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1343 "No entry 'IPV4ADDR' in configuration!\n");
1344 GNUNET_SCHEDULER_shutdown ();
1347 helper_argv[4] = ipv4addr;
1348 if (GNUNET_SYSERR ==
1349 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1352 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1353 "No entry 'IPV4MASK' in configuration!\n");
1354 GNUNET_SCHEDULER_shutdown ();
1357 helper_argv[5] = ipv4mask;
1358 helper_argv[6] = NULL;
1360 if (NULL != dns_exit)
1362 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1363 {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1366 static GNUNET_MESH_ApplicationType mesh_types[] = {
1367 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1368 GNUNET_APPLICATION_TYPE_END
1370 mesh = GNUNET_MESH_connect (cfg,
1373 &destroy_dns_tunnel,
1377 hijacker = GNUNET_HELPER_start (GNUNET_NO,
1378 "gnunet-helper-dns",
1380 &process_helper_messages,
1382 GNUNET_SERVER_add_handlers (server, handlers);
1383 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1388 * The main function for the dns service.
1390 * @param argc number of arguments from the command line
1391 * @param argv command line arguments
1392 * @return 0 ok, 1 on error
1395 main (int argc, char *const *argv)
1397 /* make use of SGID capabilities on POSIX */
1398 /* FIXME: this might need a port on systems without 'getresgid' */
1404 if (-1 == getresgid (&rgid, &egid, &sgid))
1407 "getresgid failed: %s\n",
1410 else if (sgid != rgid)
1412 if (-1 == setregid (sgid, sgid))
1413 fprintf (stderr, "setregid failed: %s\n", strerror (errno));
1416 return (GNUNET_OK ==
1417 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1418 &run, NULL)) ? global_ret : 1;
1422 /* end of gnunet-service-dns.c */