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_mesh_service.h"
49 #include "gnunet_statistics_service.h"
50 #include "gnunet_tun_lib.h"
54 * Timeout for an external (Internet-DNS) DNS resolution
56 #define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59 * How many DNS sockets do we open at most at the same time?
60 * (technical socket maximum is this number x2 for IPv4+IPv6)
62 #define DNS_SOCKET_MAX 128
65 * Phases each request goes through.
70 * Request has just been received.
75 * Showing the request to all monitor clients. If
76 * client list is empty, will enter QUERY phase.
81 * Showing the request to PRE-RESOLUTION clients to find an answer.
82 * If client list is empty, will trigger global DNS request.
87 * Global Internet query is now pending.
92 * Client (or global DNS request) has resulted in a response.
93 * Forward to all POST-RESOLUTION clients. If client list is empty,
94 * will enter RESPONSE_MONITOR phase.
99 * Showing the request to all monitor clients. If
100 * client list is empty, give the result to the hijacker (and be done).
105 * Some client has told us to drop the request.
112 * Entry we keep for each client.
117 * Kept in doubly-linked list.
119 struct ClientRecord *next;
122 * Kept in doubly-linked list.
124 struct ClientRecord *prev;
127 * Handle to the client.
129 struct GNUNET_SERVER_Client *client;
132 * Flags for the client.
134 enum GNUNET_DNS_Flags flags;
140 * UDP socket we are using for sending DNS requests to the Internet.
146 * UDP socket we use for this request for IPv4
148 struct GNUNET_NETWORK_Handle *dnsout4;
151 * UDP socket we use for this request for IPv6
153 struct GNUNET_NETWORK_Handle *dnsout6;
156 * Task for reading from dnsout4 and dnsout6.
158 GNUNET_SCHEDULER_TaskIdentifier read_task;
161 * When should this socket be closed?
163 struct GNUNET_TIME_Absolute timeout;
168 * Entry we keep for each active request.
174 * List of clients that still need to see this request (each entry
175 * is set to NULL when the client is done).
177 struct ClientRecord **client_wait_list;
180 * Payload of the UDP packet (the UDP payload), can be either query
181 * or already the response.
186 * Socket we are using to transmit this request (must match if we receive
187 * a response). Must NOT be freed as part of this request record (as it
188 * might be shared with other requests).
190 struct GNUNET_NETWORK_Handle *dnsout;
193 * Source address of the original request (for sending response).
195 struct sockaddr_storage src_addr;
198 * Destination address of the original request (for potential use as exit).
200 struct sockaddr_storage dst_addr;
203 * When should this request time out?
205 struct GNUNET_TIME_Absolute timeout;
208 * ID of this request, also basis for hashing. Lowest 16 bit will
209 * be our message ID when doing a global DNS request and our index
210 * into the 'requests' array.
215 * Number of bytes in payload.
217 size_t payload_length;
220 * Length of the client wait list.
222 unsigned int client_wait_list_length;
225 * In which phase this this request?
227 enum RequestPhase phase;
233 * State we keep for each DNS tunnel that terminates at this node.
239 * Associated MESH tunnel.
241 struct GNUNET_MESH_Tunnel *tunnel;
244 * Active request for sending a reply.
246 struct GNUNET_MESH_TransmitHandle *th;
249 * DNS reply ready for transmission.
254 * Socket we are using to transmit this request (must match if we receive
255 * a response). Must NOT be freed as part of this request record (as it
256 * might be shared with other requests).
258 struct GNUNET_NETWORK_Handle *dnsout;
261 * Address we sent the DNS request to.
263 struct sockaddr_storage addr;
266 * When should this request time out?
268 struct GNUNET_TIME_Absolute timeout;
271 * Number of bytes in 'addr'.
276 * Number of bytes in 'reply'.
281 * Original DNS request ID as used by the client.
283 uint16_t original_id;
286 * DNS request ID that we used for forwarding.
293 * Global return value from 'main'.
295 static int global_ret;
298 * The configuration to use
300 static const struct GNUNET_CONFIGURATION_Handle *cfg;
305 static struct GNUNET_STATISTICS_Handle *stats;
308 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
310 static struct GNUNET_HELPER_Handle *hijacker;
313 * Command-line arguments we are giving to the hijacker process.
315 static char *helper_argv[7];
318 * Head of DLL of clients we consult.
320 static struct ClientRecord *clients_head;
323 * Tail of DLL of clients we consult.
325 static struct ClientRecord *clients_tail;
328 * Our notification context.
330 static struct GNUNET_SERVER_NotificationContext *nc;
333 * Array of all open requests.
335 static struct RequestRecord requests[UINT16_MAX + 1];
338 * Array of all open requests from tunnels.
340 static struct TunnelState *tunnels[UINT16_MAX + 1];
343 * Array of all open sockets for DNS requests.
345 static struct RequestSocket sockets[DNS_SOCKET_MAX];
348 * Generator for unique request IDs.
350 static uint64_t request_id_gen;
353 * IP address to use for the DNS server if we are a DNS exit service
354 * (for VPN via mesh); otherwise NULL.
356 static char *dns_exit;
359 * Handle to the MESH service (for receiving DNS queries), or NULL
360 * if we are not a DNS exit.
362 static struct GNUNET_MESH_Handle *mesh;
366 * We're done with a RequestSocket, close it for now.
368 * @param rs request socket to clean up
371 cleanup_rs (struct RequestSocket *rs)
373 if (NULL != rs->dnsout4)
375 GNUNET_NETWORK_socket_close (rs->dnsout4);
378 if (NULL != rs->dnsout6)
380 GNUNET_NETWORK_socket_close (rs->dnsout6);
383 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
385 GNUNET_SCHEDULER_cancel (rs->read_task);
386 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
392 * We're done processing a DNS request, free associated memory.
394 * @param rr request to clean up
397 cleanup_rr (struct RequestRecord *rr)
399 GNUNET_free_non_null (rr->payload);
401 rr->payload_length = 0;
402 GNUNET_array_grow (rr->client_wait_list,
403 rr->client_wait_list_length,
409 * Task run during shutdown.
415 cleanup_task (void *cls GNUNET_UNUSED,
416 const struct GNUNET_SCHEDULER_TaskContext *tc)
420 GNUNET_HELPER_stop (hijacker);
423 GNUNET_free_non_null (helper_argv[i]);
424 for (i=0;i<=UINT16_MAX;i++)
425 cleanup_rr (&requests[i]);
426 GNUNET_SERVER_notification_context_destroy (nc);
430 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
433 if (NULL != dns_exit)
435 GNUNET_free (dns_exit);
440 GNUNET_MESH_disconnect(mesh);
447 * Open source port for sending DNS requests
449 * @param af AF_INET or AF_INET6
450 * @return GNUNET_OK on success
452 static struct GNUNET_NETWORK_Handle *
455 struct sockaddr_in a4;
456 struct sockaddr_in6 a6;
459 struct GNUNET_NETWORK_Handle *ret;
461 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
467 memset (&a4, 0, alen = sizeof (struct sockaddr_in));
468 sa = (struct sockaddr *) &a4;
471 memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
472 sa = (struct sockaddr *) &a6;
476 GNUNET_NETWORK_socket_close (ret);
480 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 _("Could not bind to any port: %s\n"),
487 GNUNET_NETWORK_socket_close (ret);
495 * We're done with some request, finish processing.
497 * @param rr request send to the network or just clean up.
500 request_done (struct RequestRecord *rr)
502 struct GNUNET_MessageHeader *hdr;
504 uint16_t source_port;
505 uint16_t destination_port;
507 GNUNET_array_grow (rr->client_wait_list,
508 rr->client_wait_list_length,
510 if (RP_RESPONSE_MONITOR != rr->phase)
512 /* no response, drop */
517 /* send response via hijacker */
518 reply_len = sizeof (struct GNUNET_MessageHeader);
519 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
520 switch (rr->src_addr.ss_family)
523 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
526 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
533 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
534 reply_len += rr->payload_length;
535 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
537 /* response too big, drop */
538 GNUNET_break (0); /* how can this be? */
545 struct GNUNET_TUN_IPv4Header ip4;
546 struct GNUNET_TUN_IPv6Header ip6;
548 /* first, GNUnet message header */
549 hdr = (struct GNUNET_MessageHeader*) buf;
550 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
551 hdr->size = htons ((uint16_t) reply_len);
552 off = sizeof (struct GNUNET_MessageHeader);
554 /* first, TUN header */
556 struct GNUNET_TUN_Layer2PacketHeader tun;
558 tun.flags = htons (0);
559 if (rr->src_addr.ss_family == AF_INET)
560 tun.proto = htons (ETH_P_IPV4);
562 tun.proto = htons (ETH_P_IPV6);
563 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
564 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
568 switch (rr->src_addr.ss_family)
572 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
573 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
575 source_port = dst->sin_port;
576 destination_port = src->sin_port;
577 GNUNET_TUN_initialize_ipv4_header (&ip4,
579 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
582 memcpy (&buf[off], &ip4, sizeof (ip4));
588 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
589 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
591 source_port = dst->sin6_port;
592 destination_port = src->sin6_port;
593 GNUNET_TUN_initialize_ipv6_header (&ip6,
595 reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
598 memcpy (&buf[off], &ip6, sizeof (ip6));
608 struct GNUNET_TUN_UdpHeader udp;
610 udp.source_port = source_port;
611 udp.destination_port = destination_port;
612 udp.len = htons (reply_len - off);
613 if (AF_INET == rr->src_addr.ss_family)
614 GNUNET_TUN_calculate_udp4_checksum (&ip4,
619 GNUNET_TUN_calculate_udp6_checksum (&ip6,
623 memcpy (&buf[off], &udp, sizeof (udp));
627 /* now DNS payload */
629 memcpy (&buf[off], rr->payload, rr->payload_length);
630 off += rr->payload_length;
632 /* final checks & sending */
633 GNUNET_assert (off == reply_len);
634 GNUNET_HELPER_send (hijacker,
638 GNUNET_STATISTICS_update (stats,
639 gettext_noop ("# DNS requests answered via TUN interface"),
642 /* clean up, we're done */
648 * Show the payload of the given request record to the client
649 * (and wait for a response).
651 * @param rr request to send to client
652 * @param client client to send the response to
655 send_request_to_client (struct RequestRecord *rr,
656 struct GNUNET_SERVER_Client *client)
658 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
659 struct GNUNET_DNS_Request *req;
661 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
667 req = (struct GNUNET_DNS_Request*) buf;
668 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
669 req->header.size = htons (sizeof (buf));
670 req->reserved = htonl (0);
671 req->request_id = rr->request_id;
672 memcpy (&req[1], rr->payload, rr->payload_length);
673 GNUNET_SERVER_notification_context_unicast (nc,
681 * Read a DNS response from the (unhindered) UDP-Socket
683 * @param cls socket to read from
684 * @param tc scheduler context (must be shutdown or read ready)
687 read_response (void *cls,
688 const struct GNUNET_SCHEDULER_TaskContext *tc);
692 * Get a socket of the specified address family to send out a
693 * UDP DNS request to the Internet.
695 * @param af desired address family
696 * @return NULL on error (given AF not "supported")
698 static struct GNUNET_NETWORK_Handle *
699 get_request_socket (int af)
701 struct RequestSocket *rs;
702 struct GNUNET_NETWORK_FDSet *rset;
703 static struct GNUNET_NETWORK_Handle *ret;
705 rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
707 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
711 if (NULL == rs->dnsout4)
712 rs->dnsout4 = open_socket (AF_INET);
716 if (NULL == rs->dnsout6)
717 rs->dnsout6 = open_socket (AF_INET6);
723 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
725 GNUNET_SCHEDULER_cancel (rs->read_task);
726 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
728 if ( (NULL == rs->dnsout4) &&
729 (NULL == rs->dnsout6) )
731 rset = GNUNET_NETWORK_fdset_create ();
732 if (NULL != rs->dnsout4)
733 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
734 if (NULL != rs->dnsout6)
735 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
736 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
737 GNUNET_SCHEDULER_NO_TASK,
742 GNUNET_NETWORK_fdset_destroy (rset);
748 * A client has completed its processing for this
751 * @param rr request to process further
754 next_phase (struct RequestRecord *rr)
756 struct ClientRecord *cr;
761 if (rr->phase == RP_DROP)
767 for (j=0;j<rr->client_wait_list_length;j++)
769 if (NULL != rr->client_wait_list[j])
777 send_request_to_client (rr, rr->client_wait_list[nz]->client);
780 /* done with current phase, advance! */
784 rr->phase = RP_REQUEST_MONITOR;
785 for (cr = clients_head; NULL != cr; cr = cr->next)
787 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
788 GNUNET_array_append (rr->client_wait_list,
789 rr->client_wait_list_length,
794 case RP_REQUEST_MONITOR:
795 rr->phase = RP_QUERY;
796 for (cr = clients_head; NULL != cr; cr = cr->next)
798 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
799 GNUNET_array_append (rr->client_wait_list,
800 rr->client_wait_list_length,
806 switch (rr->dst_addr.ss_family)
809 salen = sizeof (struct sockaddr_in);
812 salen = sizeof (struct sockaddr_in6);
818 rr->phase = RP_INTERNET_DNS;
819 rr->dnsout = get_request_socket (rr->dst_addr.ss_family);
820 if (NULL == rr->dnsout)
822 GNUNET_STATISTICS_update (stats,
823 gettext_noop ("# DNS exit failed (failed to open socket)"),
828 GNUNET_NETWORK_socket_sendto (rr->dnsout,
831 (struct sockaddr*) &rr->dst_addr,
833 rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
835 case RP_INTERNET_DNS:
836 rr->phase = RP_MODIFY;
837 for (cr = clients_head; NULL != cr; cr = cr->next)
839 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
840 GNUNET_array_append (rr->client_wait_list,
841 rr->client_wait_list_length,
847 rr->phase = RP_RESPONSE_MONITOR;
848 for (cr = clients_head; NULL != cr; cr = cr->next)
850 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
851 GNUNET_array_append (rr->client_wait_list,
852 rr->client_wait_list_length,
857 case RP_RESPONSE_MONITOR:
872 * A client disconnected, clean up after it.
875 * @param client handle of client that disconnected
878 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
880 struct ClientRecord *cr;
881 struct RequestRecord *rr;
885 for (cr = clients_head; NULL != cr; cr = cr->next)
887 if (cr->client == client)
889 GNUNET_SERVER_client_drop (client);
890 GNUNET_CONTAINER_DLL_remove (clients_head,
893 for (i=0;i<UINT16_MAX;i++)
896 if (0 == rr->client_wait_list_length)
897 continue; /* not in use */
898 for (j=0;j<rr->client_wait_list_length;j++)
900 if (rr->client_wait_list[j] == cr)
902 rr->client_wait_list[j] = NULL;
915 * We got a reply from DNS for a request of a MESH tunnel. Send it
916 * via the tunnel (after changing the request ID back).
918 * @param cls the 'struct TunnelState'
919 * @param size number of bytes available in buf
920 * @param buf where to copy the reply
921 * @return number of bytes written to buf
924 transmit_reply_to_mesh (void *cls,
928 struct TunnelState *ts = cls;
932 struct GNUNET_MessageHeader hdr;
933 struct GNUNET_TUN_DnsHeader dns;
936 GNUNET_assert (ts->reply != NULL);
939 ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length;
940 GNUNET_assert (ret <= size);
941 hdr.size = htons (ret);
942 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
943 memcpy (&dns, ts->reply, sizeof (dns));
944 dns.id = ts->original_id;
946 memcpy (&cbuf[off], &hdr, sizeof (hdr));
948 memcpy (&cbuf[off], &dns, sizeof (dns));
950 memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
951 off += ts->reply_length - sizeof (dns);
952 GNUNET_free (ts->reply);
954 ts->reply_length = 0;
955 GNUNET_assert (ret == off);
961 * Actually do the reading of a DNS packet from our UDP socket and see
962 * if we have a valid, matching, pending request.
964 * @param dnsout socket to read from
965 * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
968 do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
970 struct sockaddr_storage addr;
972 struct GNUNET_TUN_DnsHeader *dns;
973 struct RequestRecord *rr;
974 struct TunnelState *ts;
979 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
981 /* conservative choice: */
985 /* port the code above? */
990 unsigned char buf[len];
992 addrlen = sizeof (addr);
993 memset (&addr, 0, sizeof (addr));
994 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
996 (struct sockaddr*) &addr, &addrlen);
999 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
1000 GNUNET_NETWORK_socket_close (dnsout);
1001 return GNUNET_SYSERR;
1003 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
1005 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1006 _("Received DNS response that is too small (%u bytes)"),
1010 dns = (struct GNUNET_TUN_DnsHeader *) buf;
1011 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
1012 ts = tunnels[dns->id];
1013 if ( (NULL == ts) ||
1014 (ts->dnsout != dnsout) ||
1015 (addrlen != ts->addrlen) ||
1016 (0 != memcmp (&ts->addr,
1019 (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) )
1020 ts = NULL; /* DNS responder address missmatch */
1023 tunnels[dns->id] = NULL;
1024 GNUNET_free_non_null (ts->reply);
1025 ts->reply = GNUNET_malloc (r);
1026 ts->reply_length = r;
1027 memcpy (ts->reply, dns, r);
1029 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1030 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
1032 GNUNET_TIME_UNIT_FOREVER_REL,
1034 sizeof (struct GNUNET_MessageHeader) + r,
1035 &transmit_reply_to_mesh,
1038 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
1039 rr = &requests[dns->id];
1040 if ( (rr->phase != RP_INTERNET_DNS) ||
1041 (rr->dnsout != dnsout) ||
1042 (0 != memcmp (&rr->dst_addr,
1045 (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) )
1049 /* unexpected / bogus reply */
1050 GNUNET_STATISTICS_update (stats,
1051 gettext_noop ("# External DNS response discarded (no matching request)"),
1056 GNUNET_free_non_null (rr->payload);
1057 rr->payload = GNUNET_malloc (r);
1058 memcpy (rr->payload, buf, r);
1059 rr->payload_length = r;
1067 * Read a DNS response from the (unhindered) UDP-Socket
1069 * @param cls socket to read from
1070 * @param tc scheduler context (must be shutdown or read ready)
1073 read_response (void *cls,
1074 const struct GNUNET_SCHEDULER_TaskContext *tc)
1076 struct RequestSocket *rs = cls;
1077 struct GNUNET_NETWORK_FDSet *rset;
1079 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
1080 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1082 /* timeout or shutdown */
1086 /* read and process ready sockets */
1087 if ((NULL != rs->dnsout4) &&
1088 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
1089 (GNUNET_SYSERR == do_dns_read (rs->dnsout4)))
1091 if ((NULL != rs->dnsout6) &&
1092 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
1093 (GNUNET_SYSERR == do_dns_read (rs->dnsout6)))
1096 /* re-schedule read task */
1097 rset = GNUNET_NETWORK_fdset_create ();
1098 if (NULL != rs->dnsout4)
1099 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
1100 if (NULL != rs->dnsout6)
1101 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
1102 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1103 GNUNET_SCHEDULER_NO_TASK,
1104 GNUNET_TIME_absolute_get_remaining (rs->timeout),
1107 &read_response, rs);
1108 GNUNET_NETWORK_fdset_destroy (rset);
1113 * We got a new client. Make sure all new DNS requests pass by its desk.
1116 * @param client the new client
1117 * @param message the init message (unused)
1120 handle_client_init (void *cls GNUNET_UNUSED,
1121 struct GNUNET_SERVER_Client *client,
1122 const struct GNUNET_MessageHeader *message)
1124 struct ClientRecord *cr;
1125 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
1127 cr = GNUNET_malloc (sizeof (struct ClientRecord));
1128 cr->client = client;
1129 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
1130 GNUNET_SERVER_client_keep (client);
1131 GNUNET_CONTAINER_DLL_insert (clients_head,
1134 GNUNET_SERVER_notification_context_add (nc, client);
1135 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1140 * We got a response from a client.
1143 * @param client the client
1144 * @param message the response
1147 handle_client_response (void *cls GNUNET_UNUSED,
1148 struct GNUNET_SERVER_Client *client,
1149 const struct GNUNET_MessageHeader *message)
1151 const struct GNUNET_DNS_Response *resp;
1152 struct RequestRecord *rr;
1157 msize = ntohs (message->size);
1158 if (msize < sizeof (struct GNUNET_DNS_Response))
1161 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1164 resp = (const struct GNUNET_DNS_Response*) message;
1165 off = (uint16_t) resp->request_id;
1166 rr = &requests[off];
1167 if (rr->request_id != resp->request_id)
1169 GNUNET_STATISTICS_update (stats,
1170 gettext_noop ("# Client response discarded (no matching request)"),
1172 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1175 for (i=0;i<rr->client_wait_list_length;i++)
1177 if (NULL == rr->client_wait_list[i])
1179 if (rr->client_wait_list[i]->client != client)
1181 rr->client_wait_list[i] = NULL;
1182 switch (ntohl (resp->drop_flag))
1185 rr->phase = RP_DROP;
1187 case 1: /* no change */
1189 case 2: /* update */
1190 msize -= sizeof (struct GNUNET_DNS_Response);
1191 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
1192 (RP_REQUEST_MONITOR == rr->phase) ||
1193 (RP_RESPONSE_MONITOR == rr->phase) )
1196 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1200 GNUNET_free_non_null (rr->payload);
1202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1203 _("Changing DNS reply according to client specifications\n"));
1205 rr->payload = GNUNET_malloc (msize);
1206 rr->payload_length = msize;
1207 memcpy (rr->payload, &resp[1], msize);
1208 if (rr->phase == RP_QUERY)
1210 /* clear wait list, we're moving to MODIFY phase next */
1211 GNUNET_array_grow (rr->client_wait_list,
1212 rr->client_wait_list_length,
1215 /* if query changed to answer, move past DNS resolution phase... */
1216 if ( (RP_QUERY == rr->phase) &&
1217 (rr->payload_length > sizeof (struct GNUNET_TUN_DnsHeader)) &&
1218 ((struct GNUNET_DNSPARSER_Flags*)&(((struct GNUNET_TUN_DnsHeader*) rr->payload)->flags))->query_or_response == 1)
1220 rr->phase = RP_INTERNET_DNS;
1221 GNUNET_array_grow (rr->client_wait_list,
1222 rr->client_wait_list_length,
1228 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1231 /* odd, client was not on our list for the request, that ought
1234 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1239 * Functions with this signature are called whenever a complete
1240 * message is received by the tokenizer from the DNS hijack process.
1242 * @param cls closure
1243 * @param client identification of the client
1244 * @param message the actual message, a DNS request we should handle
1247 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1248 const struct GNUNET_MessageHeader *message)
1251 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1252 const struct GNUNET_TUN_IPv4Header *ip4;
1253 const struct GNUNET_TUN_IPv6Header *ip6;
1254 const struct GNUNET_TUN_UdpHeader *udp;
1255 const struct GNUNET_TUN_DnsHeader *dns;
1256 struct RequestRecord *rr;
1257 struct sockaddr_in *srca4;
1258 struct sockaddr_in6 *srca6;
1259 struct sockaddr_in *dsta4;
1260 struct sockaddr_in6 *dsta6;
1262 msize = ntohs (message->size);
1263 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1265 /* non-IP packet received on TUN!? */
1269 msize -= sizeof (struct GNUNET_MessageHeader);
1270 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1271 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1272 switch (ntohs (tun->proto))
1275 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1276 ip6 = NULL; /* make compiler happy */
1277 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1278 (ip4->version != 4) ||
1279 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1280 (ntohs(ip4->total_length) != msize) ||
1281 (ip4->protocol != IPPROTO_UDP) )
1283 /* non-IP/UDP packet received on TUN (or with options) */
1284 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1285 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1288 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1289 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1292 ip4 = NULL; /* make compiler happy */
1293 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1294 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1295 (ip6->version != 6) ||
1296 (ntohs (ip6->payload_length) != msize) ||
1297 (ip6->next_header != IPPROTO_UDP) )
1299 /* non-IP/UDP packet received on TUN (or with extensions) */
1300 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1301 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1304 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1305 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1308 /* non-IP packet received on TUN!? */
1309 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1310 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1311 (unsigned int) msize,
1312 ntohs (tun->proto));
1315 if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1317 /* non-DNS packet received on TUN, ignore */
1318 GNUNET_STATISTICS_update (stats,
1319 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1323 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1324 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1325 rr = &requests[dns->id];
1327 /* clean up from previous request */
1328 GNUNET_free_non_null (rr->payload);
1330 GNUNET_array_grow (rr->client_wait_list,
1331 rr->client_wait_list_length,
1334 /* setup new request */
1335 rr->phase = RP_INIT;
1336 switch (ntohs (tun->proto))
1340 srca4 = (struct sockaddr_in*) &rr->src_addr;
1341 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1342 memset (srca4, 0, sizeof (struct sockaddr_in));
1343 memset (dsta4, 0, sizeof (struct sockaddr_in));
1344 srca4->sin_family = AF_INET;
1345 dsta4->sin_family = AF_INET;
1346 srca4->sin_addr = ip4->source_address;
1347 dsta4->sin_addr = ip4->destination_address;
1348 srca4->sin_port = udp->source_port;
1349 dsta4->sin_port = udp->destination_port;
1350 #if HAVE_SOCKADDR_IN_SIN_LEN
1351 srca4->sin_len = sizeof (struct sockaddr_in);
1352 dsta4->sin_len = sizeof (struct sockaddr_in);
1358 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1359 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1360 memset (srca6, 0, sizeof (struct sockaddr_in6));
1361 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1362 srca6->sin6_family = AF_INET6;
1363 dsta6->sin6_family = AF_INET6;
1364 srca6->sin6_addr = ip6->source_address;
1365 dsta6->sin6_addr = ip6->destination_address;
1366 srca6->sin6_port = udp->source_port;
1367 dsta6->sin6_port = udp->destination_port;
1368 #if HAVE_SOCKADDR_IN_SIN_LEN
1369 srca6->sin6_len = sizeof (struct sockaddr_in6);
1370 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1377 rr->payload = GNUNET_malloc (msize);
1378 rr->payload_length = msize;
1379 memcpy (rr->payload, dns, msize);
1380 rr->request_id = dns->id | (request_id_gen << 16);
1383 GNUNET_STATISTICS_update (stats,
1384 gettext_noop ("# DNS requests received via TUN interface"),
1386 /* start request processing state machine */
1392 * Process a request via mesh to perform a DNS query.
1394 * @param cls closure, NULL
1395 * @param tunnel connection to the other end
1396 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1397 * @param sender who sent the message
1398 * @param message the actual message
1399 * @param atsi performance data for the connection
1400 * @return GNUNET_OK to keep the connection open,
1401 * GNUNET_SYSERR to close it (signal serious error)
1404 receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1406 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1407 const struct GNUNET_MessageHeader *message,
1408 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1410 struct TunnelState *ts = *tunnel_ctx;
1411 const struct GNUNET_TUN_DnsHeader *dns;
1412 size_t mlen = ntohs (message->size);
1413 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1415 struct GNUNET_TUN_DnsHeader *dout;
1416 struct sockaddr_in v4;
1417 struct sockaddr_in6 v6;
1418 struct sockaddr *so;
1421 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1423 GNUNET_break_op (0);
1424 return GNUNET_SYSERR;
1426 dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1427 ts->original_id = dns->id;
1428 if (tunnels[ts->my_id] == ts)
1429 tunnels[ts->my_id] = NULL;
1430 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1432 tunnels[ts->my_id] = ts;
1433 memcpy (buf, dns, dlen);
1434 dout = (struct GNUNET_TUN_DnsHeader*) buf;
1435 dout->id = ts->my_id;
1436 memset (&v4, 0, sizeof (v4));
1437 memset (&v6, 0, sizeof (v6));
1438 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
1440 salen = sizeof (v4);
1441 v4.sin_family = AF_INET;
1442 v4.sin_port = htons (53);
1443 #if HAVE_SOCKADDR_IN_SIN_LEN
1444 v4.sin_len = (u_char) salen;
1446 so = (struct sockaddr *) &v4;
1447 ts->dnsout = get_request_socket (AF_INET);
1449 else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1451 salen = sizeof (v6);
1452 v6.sin6_family = AF_INET6;
1453 v6.sin6_port = htons (53);
1454 #if HAVE_SOCKADDR_IN_SIN_LEN
1455 v6.sin6_len = (u_char) salen;
1457 so = (struct sockaddr *) &v6;
1458 ts->dnsout = get_request_socket (AF_INET6);
1463 return GNUNET_SYSERR;
1465 if (NULL == ts->dnsout)
1467 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1468 _("Configured DNS exit `%s' is not working / valid.\n"),
1470 return GNUNET_SYSERR;
1475 ts->addrlen = salen;
1476 GNUNET_NETWORK_socket_sendto (ts->dnsout,
1477 buf, dlen, so, salen);
1478 ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
1484 * Callback from GNUNET_MESH for new tunnels.
1486 * @param cls closure
1487 * @param tunnel new handle to the tunnel
1488 * @param initiator peer that started the tunnel
1489 * @param ats performance information for the tunnel
1490 * @return initial tunnel context for the tunnel
1493 accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1494 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1495 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1497 struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1499 GNUNET_STATISTICS_update (stats,
1500 gettext_noop ("# Inbound MESH tunnels created"),
1502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1503 "Received inbound tunnel from `%s'\n",
1504 GNUNET_i2s (initiator));
1505 ts->tunnel = tunnel;
1511 * Function called by mesh whenever an inbound tunnel is destroyed.
1512 * Should clean up any associated state.
1514 * @param cls closure (set from GNUNET_MESH_connect)
1515 * @param tunnel connection to the other end (henceforth invalid)
1516 * @param tunnel_ctx place where local state associated
1517 * with the tunnel is stored
1520 destroy_dns_tunnel (void *cls GNUNET_UNUSED,
1521 const struct GNUNET_MESH_Tunnel *tunnel,
1524 struct TunnelState *ts = tunnel_ctx;
1526 if (tunnels[ts->my_id] == ts)
1527 tunnels[ts->my_id] = NULL;
1529 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1530 GNUNET_free_non_null (ts->reply);
1536 * @param cls closure
1537 * @param server the initialized server
1538 * @param cfg_ configuration to use
1541 run (void *cls, struct GNUNET_SERVER_Handle *server,
1542 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1544 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1545 /* callback, cls, type, size */
1546 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1547 sizeof (struct GNUNET_DNS_Register)},
1548 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1556 struct in_addr dns_exit4;
1557 struct in6_addr dns_exit6;
1561 GNUNET_OS_check_helper_binary ("gnunet-helper-dns"))
1563 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1564 _("`%s' must be installed SUID, refusing to run\n"),
1565 "gnunet-helper-dns");
1570 stats = GNUNET_STATISTICS_create ("dns", cfg);
1571 nc = GNUNET_SERVER_notification_context_create (server, 1);
1572 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1575 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT")) &&
1577 GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1580 ( (1 != inet_pton (AF_INET, dns_exit, &dns_exit4)) &&
1581 (1 != inet_pton (AF_INET6, dns_exit, &dns_exit6)) ) ) )
1583 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1584 _("Configured to provide DNS exit, but no valid DNS server configured!\n"));
1585 GNUNET_free_non_null (dns_exit);
1589 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1590 if (GNUNET_SYSERR ==
1591 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1593 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1594 "No entry 'IFNAME' in configuration!\n");
1595 GNUNET_SCHEDULER_shutdown ();
1598 helper_argv[1] = ifc_name;
1599 if ( (GNUNET_SYSERR ==
1600 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1603 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1604 "No entry 'IPV6ADDR' in configuration!\n");
1605 GNUNET_SCHEDULER_shutdown ();
1608 helper_argv[2] = ipv6addr;
1609 if (GNUNET_SYSERR ==
1610 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1614 "No entry 'IPV6PREFIX' in configuration!\n");
1615 GNUNET_SCHEDULER_shutdown ();
1618 helper_argv[3] = ipv6prefix;
1620 if (GNUNET_SYSERR ==
1621 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1624 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1625 "No entry 'IPV4ADDR' in configuration!\n");
1626 GNUNET_SCHEDULER_shutdown ();
1629 helper_argv[4] = ipv4addr;
1630 if (GNUNET_SYSERR ==
1631 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1634 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1635 "No entry 'IPV4MASK' in configuration!\n");
1636 GNUNET_SCHEDULER_shutdown ();
1639 helper_argv[5] = ipv4mask;
1640 helper_argv[6] = NULL;
1642 if (NULL != dns_exit)
1644 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1645 {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1648 static GNUNET_MESH_ApplicationType mesh_types[] = {
1649 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1650 GNUNET_APPLICATION_TYPE_END
1652 mesh = GNUNET_MESH_connect (cfg,
1655 &destroy_dns_tunnel,
1659 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1661 &process_helper_messages,
1663 GNUNET_SERVER_add_handlers (server, handlers);
1664 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1669 * The main function for the dns service.
1671 * @param argc number of arguments from the command line
1672 * @param argv command line arguments
1673 * @return 0 ok, 1 on error
1676 main (int argc, char *const *argv)
1678 return (GNUNET_OK ==
1679 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1680 &run, NULL)) ? global_ret : 1;
1684 /* end of gnunet-service-dns.c */