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
27 #include "gnunet_util_lib.h"
28 #include "gnunet_applications.h"
29 #include "gnunet_constants.h"
30 #include "gnunet_protocols.h"
31 #include "gnunet_signatures.h"
33 #include "gnunet_dns_service.h"
34 #include "gnunet_mesh_service.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_tun_lib.h"
40 * Phases each request goes through.
45 * Request has just been received.
50 * Showing the request to all monitor clients. If
51 * client list is empty, will enter QUERY phase.
56 * Showing the request to PRE-RESOLUTION clients to find an answer.
57 * If client list is empty, will trigger global DNS request.
62 * Global Internet query is now pending.
67 * Client (or global DNS request) has resulted in a response.
68 * Forward to all POST-RESOLUTION clients. If client list is empty,
69 * will enter RESPONSE_MONITOR phase.
74 * Showing the request to all monitor clients. If
75 * client list is empty, give the result to the hijacker (and be done).
80 * Some client has told us to drop the request.
87 * Entry we keep for each client.
92 * Kept in doubly-linked list.
94 struct ClientRecord *next;
97 * Kept in doubly-linked list.
99 struct ClientRecord *prev;
102 * Handle to the client.
104 struct GNUNET_SERVER_Client *client;
107 * Flags for the client.
109 enum GNUNET_DNS_Flags flags;
115 * Entry we keep for each active request.
121 * List of clients that still need to see this request (each entry
122 * is set to NULL when the client is done).
124 struct ClientRecord **client_wait_list;
127 * Payload of the UDP packet (the UDP payload), can be either query
128 * or already the response.
133 * Source address of the original request (for sending response).
135 struct sockaddr_storage src_addr;
138 * Destination address of the original request (for potential use as exit).
140 struct sockaddr_storage dst_addr;
143 * ID of this request, also basis for hashing. Lowest 16 bit will
144 * be our message ID when doing a global DNS request and our index
145 * into the 'requests' array.
150 * Number of bytes in payload.
152 size_t payload_length;
155 * Length of the client wait list.
157 unsigned int client_wait_list_length;
160 * In which phase this this request?
162 enum RequestPhase phase;
168 * State we keep for each DNS tunnel that terminates at this node.
174 * Associated MESH tunnel.
176 struct GNUNET_MESH_Tunnel *tunnel;
179 * Active request for sending a reply.
181 struct GNUNET_MESH_TransmitHandle *th;
184 * DNS reply ready for transmission.
189 * Address we sent the DNS request to.
191 struct sockaddr_storage addr;
194 * Number of bytes in 'addr'.
199 * Number of bytes in 'reply'.
204 * Original DNS request ID as used by the client.
206 uint16_t original_id;
209 * DNS request ID that we used for forwarding.
216 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
217 * sent through gnunet. The port of this socket will not be hijacked.
219 static struct GNUNET_NETWORK_Handle *dnsout4;
222 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
223 * sent through gnunet. The port of this socket will not be hijacked.
225 static struct GNUNET_NETWORK_Handle *dnsout6;
228 * Task for reading from dnsout4.
230 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
233 * Task for reading from dnsout6.
235 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
238 * The configuration to use
240 static const struct GNUNET_CONFIGURATION_Handle *cfg;
245 static struct GNUNET_STATISTICS_Handle *stats;
248 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
250 static struct GNUNET_HELPER_Handle *hijacker;
253 * Command-line arguments we are giving to the hijacker process.
255 static char *helper_argv[7];
258 * Head of DLL of clients we consult.
260 static struct ClientRecord *clients_head;
263 * Tail of DLL of clients we consult.
265 static struct ClientRecord *clients_tail;
268 * Our notification context.
270 static struct GNUNET_SERVER_NotificationContext *nc;
273 * Array of all open requests.
275 static struct RequestRecord requests[UINT16_MAX + 1];
278 * Array of all open requests from tunnels.
280 static struct TunnelState *tunnels[UINT16_MAX + 1];
283 * Generator for unique request IDs.
285 static uint64_t request_id_gen;
288 * IP address to use for the DNS server if we are a DNS exit service
289 * (for VPN via mesh); otherwise NULL.
291 static char *dns_exit;
294 * Handle to the MESH service (for receiving DNS queries), or NULL
295 * if we are not a DNS exit.
297 static struct GNUNET_MESH_Handle *mesh;
300 * Number of active DNS requests.
302 static unsigned int dns_active;
306 * We're done processing a DNS request, free associated memory.
308 * @param rr request to clean up
311 cleanup_rr (struct RequestRecord *rr)
313 GNUNET_free_non_null (rr->payload);
315 rr->payload_length = 0;
316 GNUNET_array_grow (rr->client_wait_list,
317 rr->client_wait_list_length,
323 * Task run during shutdown.
329 cleanup_task (void *cls GNUNET_UNUSED,
330 const struct GNUNET_SCHEDULER_TaskContext *tc)
334 GNUNET_HELPER_stop (hijacker);
337 GNUNET_free_non_null (helper_argv[i]);
340 GNUNET_NETWORK_socket_close (dnsout4);
343 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
345 GNUNET_SCHEDULER_cancel (read4_task);
346 read4_task = GNUNET_SCHEDULER_NO_TASK;
350 GNUNET_NETWORK_socket_close (dnsout6);
353 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
355 GNUNET_SCHEDULER_cancel (read6_task);
356 read6_task = GNUNET_SCHEDULER_NO_TASK;
358 for (i=0;i<65536;i++)
359 cleanup_rr (&requests[i]);
360 GNUNET_SERVER_notification_context_destroy (nc);
364 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
367 if (NULL != dns_exit)
369 GNUNET_free (dns_exit);
376 * We're done with some request, finish processing.
378 * @param rr request send to the network or just clean up.
381 request_done (struct RequestRecord *rr)
383 struct GNUNET_MessageHeader *hdr;
385 uint16_t source_port;
386 uint16_t destination_port;
388 GNUNET_array_grow (rr->client_wait_list,
389 rr->client_wait_list_length,
391 if (RP_RESPONSE_MONITOR != rr->phase)
393 /* no response, drop */
398 /* send response via hijacker */
399 reply_len = sizeof (struct GNUNET_MessageHeader);
400 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
401 switch (rr->src_addr.ss_family)
404 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
407 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
414 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
415 reply_len += rr->payload_length;
416 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
418 /* response too big, drop */
419 GNUNET_break (0); /* how can this be? */
426 struct GNUNET_TUN_IPv4Header ip4;
427 struct GNUNET_TUN_IPv6Header ip6;
429 /* first, GNUnet message header */
430 hdr = (struct GNUNET_MessageHeader*) buf;
431 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
432 hdr->size = htons ((uint16_t) reply_len);
433 off = sizeof (struct GNUNET_MessageHeader);
435 /* first, TUN header */
437 struct GNUNET_TUN_Layer2PacketHeader tun;
439 tun.flags = htons (0);
440 if (rr->src_addr.ss_family == AF_INET)
441 tun.proto = htons (ETH_P_IPV4);
443 tun.proto = htons (ETH_P_IPV6);
444 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
445 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
449 switch (rr->src_addr.ss_family)
453 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
454 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
456 source_port = dst->sin_port;
457 destination_port = src->sin_port;
458 GNUNET_TUN_initialize_ipv4_header (&ip4,
460 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
463 memcpy (&buf[off], &ip4, sizeof (ip4));
469 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
470 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
472 source_port = dst->sin6_port;
473 destination_port = src->sin6_port;
474 GNUNET_TUN_initialize_ipv6_header (&ip6,
476 reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
479 memcpy (&buf[off], &ip6, sizeof (ip6));
489 struct GNUNET_TUN_UdpHeader udp;
491 udp.source_port = source_port;
492 udp.destination_port = destination_port;
493 udp.len = htons (reply_len - off);
494 if (AF_INET == rr->src_addr.ss_family)
495 GNUNET_TUN_calculate_udp4_checksum (&ip4,
500 GNUNET_TUN_calculate_udp6_checksum (&ip6,
504 memcpy (&buf[off], &udp, sizeof (udp));
508 /* now DNS payload */
510 memcpy (&buf[off], rr->payload, rr->payload_length);
511 off += rr->payload_length;
513 /* final checks & sending */
514 GNUNET_assert (off == reply_len);
515 GNUNET_HELPER_send (hijacker,
519 GNUNET_STATISTICS_update (stats,
520 gettext_noop ("# DNS requests answered via TUN interface"),
523 /* clean up, we're done */
529 * Show the payload of the given request record to the client
530 * (and wait for a response).
532 * @param rr request to send to client
533 * @param client client to send the response to
536 send_request_to_client (struct RequestRecord *rr,
537 struct GNUNET_SERVER_Client *client)
539 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
540 struct GNUNET_DNS_Request *req;
542 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
548 req = (struct GNUNET_DNS_Request*) buf;
549 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
550 req->header.size = htons (sizeof (buf));
551 req->reserved = htonl (0);
552 req->request_id = rr->request_id;
553 memcpy (&req[1], rr->payload, rr->payload_length);
554 GNUNET_SERVER_notification_context_unicast (nc,
562 * Try to change the source ports we are bound to.
565 change_source_ports ();
569 * A client has completed its processing for this
572 * @param rr request to process further
575 next_phase (struct RequestRecord *rr)
577 struct ClientRecord *cr;
580 struct GNUNET_NETWORK_Handle *dnsout;
583 if (rr->phase == RP_DROP)
589 for (j=0;j<rr->client_wait_list_length;j++)
591 if (NULL != rr->client_wait_list[j])
599 send_request_to_client (rr, rr->client_wait_list[nz]->client);
602 /* done with current phase, advance! */
606 rr->phase = RP_REQUEST_MONITOR;
607 for (cr = clients_head; NULL != cr; cr = cr->next)
609 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
610 GNUNET_array_append (rr->client_wait_list,
611 rr->client_wait_list_length,
616 case RP_REQUEST_MONITOR:
617 rr->phase = RP_QUERY;
618 for (cr = clients_head; NULL != cr; cr = cr->next)
620 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
621 GNUNET_array_append (rr->client_wait_list,
622 rr->client_wait_list_length,
628 rr->phase = RP_INTERNET_DNS;
630 switch (rr->dst_addr.ss_family)
634 salen = sizeof (struct GNUNET_TUN_IPv4Header);
638 salen = sizeof (struct GNUNET_TUN_IPv6Header);
647 GNUNET_STATISTICS_update (stats,
648 gettext_noop ("# DNS exit failed (address family not supported)"),
653 GNUNET_NETWORK_socket_sendto (dnsout,
656 (struct sockaddr*) &rr->dst_addr,
659 case RP_INTERNET_DNS:
662 change_source_ports ();
663 rr->phase = RP_MODIFY;
664 for (cr = clients_head; NULL != cr; cr = cr->next)
666 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
667 GNUNET_array_append (rr->client_wait_list,
668 rr->client_wait_list_length,
674 rr->phase = RP_RESPONSE_MONITOR;
675 for (cr = clients_head; NULL != cr; cr = cr->next)
677 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
678 GNUNET_array_append (rr->client_wait_list,
679 rr->client_wait_list_length,
684 case RP_RESPONSE_MONITOR:
699 * A client disconnected, clean up after it.
702 * @param client handle of client that disconnected
705 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
707 struct ClientRecord *cr;
708 struct RequestRecord *rr;
712 for (cr = clients_head; NULL != cr; cr = cr->next)
714 if (cr->client == client)
716 GNUNET_SERVER_client_drop (client);
717 GNUNET_CONTAINER_DLL_remove (clients_head,
720 for (i=0;i<UINT16_MAX;i++)
723 if (0 == rr->client_wait_list_length)
724 continue; /* not in use */
725 for (j=0;j<rr->client_wait_list_length;j++)
727 if (rr->client_wait_list[j] == cr)
729 rr->client_wait_list[j] = NULL;
742 * We got a reply from DNS for a request of a MESH tunnel. Send it
743 * via the tunnel (after changing the request ID back).
745 * @param cls the 'struct TunnelState'
746 * @param size number of bytes available in buf
747 * @param buf where to copy the reply
748 * @return number of bytes written to buf
751 transmit_reply_to_mesh (void *cls,
755 struct TunnelState *ts = cls;
759 struct GNUNET_MessageHeader hdr;
760 struct GNUNET_TUN_DnsHeader dns;
763 GNUNET_assert (ts->reply != NULL);
766 ret = sizeof (struct GNUNET_MessageHeader) + ts->reply_length;
767 GNUNET_assert (ret <= size);
768 hdr.size = htons (ret);
769 hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_FROM_INTERNET);
770 memcpy (&dns, ts->reply, sizeof (dns));
771 dns.id = ts->original_id;
773 memcpy (&cbuf[off], &hdr, sizeof (hdr));
775 memcpy (&cbuf[off], &dns, sizeof (dns));
777 memcpy (&cbuf[off], &ts->reply[sizeof (dns)], ts->reply_length - sizeof (dns));
778 off += ts->reply_length - sizeof (dns);
779 GNUNET_free (ts->reply);
781 ts->reply_length = 0;
782 GNUNET_assert (ret == off);
788 * Read a DNS response from the (unhindered) UDP-Socket
790 * @param cls socket to read from
791 * @param tc scheduler context (must be shutdown or read ready)
794 read_response (void *cls,
795 const struct GNUNET_SCHEDULER_TaskContext *tc)
797 struct GNUNET_NETWORK_Handle *dnsout = cls;
798 struct sockaddr_in addr4;
799 struct sockaddr_in6 addr6;
800 struct sockaddr *addr;
801 struct GNUNET_TUN_DnsHeader *dns;
803 struct RequestRecord *rr;
804 struct TunnelState *ts;
808 if (dnsout == dnsout4)
810 addrlen = sizeof (struct sockaddr_in);
811 addr = (struct sockaddr* ) &addr4;
812 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
819 addrlen = sizeof (struct sockaddr_in6);
820 addr = (struct sockaddr* ) &addr6;
821 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
826 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
830 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
832 /* conservative choice: */
836 /* port the code above? */
841 unsigned char buf[len];
843 memset (addr, 0, addrlen);
844 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
849 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
852 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
854 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
855 _("Received DNS response that is too small (%u bytes)"),
859 dns = (struct GNUNET_TUN_DnsHeader *) buf;
860 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
861 ts = tunnels[dns->id];
863 (addrlen != ts->addrlen) ||
864 (0 != memcmp (&ts->addr,
867 ts = NULL; /* DNS responder address missmatch */
870 tunnels[dns->id] = NULL;
871 GNUNET_free_non_null (ts->reply);
872 ts->reply = GNUNET_malloc (r);
873 ts->reply_length = r;
874 memcpy (ts->reply, dns, r);
876 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
877 ts->th = GNUNET_MESH_notify_transmit_ready (ts->tunnel,
879 GNUNET_TIME_UNIT_FOREVER_REL,
881 sizeof (struct GNUNET_MessageHeader) + r,
882 &transmit_reply_to_mesh,
885 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
886 rr = &requests[dns->id];
887 if (rr->phase != RP_INTERNET_DNS)
891 /* unexpected / bogus reply */
892 GNUNET_STATISTICS_update (stats,
893 gettext_noop ("# External DNS response discarded (no matching request)"),
898 GNUNET_free_non_null (rr->payload);
899 rr->payload = GNUNET_malloc (r);
900 memcpy (rr->payload, buf, r);
901 rr->payload_length = r;
908 * Open source port for sending DNS request on IPv4.
910 * @return GNUNET_OK on success
915 struct sockaddr_in addr;
917 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
919 return GNUNET_SYSERR;
921 memset (&addr, 0, sizeof (struct sockaddr_in));
922 addr.sin_family = AF_INET;
923 int err = GNUNET_NETWORK_socket_bind (dnsout4,
924 (struct sockaddr *) &addr,
925 sizeof (struct sockaddr_in));
927 if (err != GNUNET_OK)
929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930 _("Could not bind to any port: %s\n"),
932 GNUNET_NETWORK_socket_close (dnsout4);
934 return GNUNET_SYSERR;
936 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
938 &read_response, dnsout4);
944 * Open source port for sending DNS request on IPv6. Should be
945 * called AFTER open_port4.
947 * @return GNUNET_OK on success
952 struct sockaddr_in6 addr;
954 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
957 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
958 _("Could not create IPv6 socket: %s\n"),
960 return GNUNET_SYSERR;
962 memset (&addr, 0, sizeof (struct sockaddr_in6));
963 addr.sin6_family = AF_INET6;
964 int err = GNUNET_NETWORK_socket_bind (dnsout6,
965 (struct sockaddr *) &addr,
966 sizeof (struct sockaddr_in6));
968 if (err != GNUNET_OK)
970 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
971 _("Could not bind: %s\n"),
973 GNUNET_NETWORK_socket_close (dnsout6);
975 return GNUNET_SYSERR;
977 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
979 &read_response, dnsout6);
985 * Try to change the source ports we are bound to.
988 change_source_ports ()
990 struct GNUNET_NETWORK_Handle *old4;
991 struct GNUNET_NETWORK_Handle *old6;
993 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
995 GNUNET_SCHEDULER_cancel (read4_task);
996 read4_task = GNUNET_SCHEDULER_NO_TASK;
998 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
1000 GNUNET_SCHEDULER_cancel (read6_task);
1001 read6_task = GNUNET_SCHEDULER_NO_TASK;
1004 if (GNUNET_OK != open_port4 ())
1007 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1009 &read_response, dnsout4);
1014 GNUNET_NETWORK_socket_close (old4);
1017 if (GNUNET_OK != open_port6 ())
1020 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1022 &read_response, dnsout6);
1027 GNUNET_NETWORK_socket_close (old6);
1033 * We got a new client. Make sure all new DNS requests pass by its desk.
1036 * @param client the new client
1037 * @param message the init message (unused)
1040 handle_client_init (void *cls GNUNET_UNUSED,
1041 struct GNUNET_SERVER_Client *client,
1042 const struct GNUNET_MessageHeader *message)
1044 struct ClientRecord *cr;
1045 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
1047 cr = GNUNET_malloc (sizeof (struct ClientRecord));
1048 cr->client = client;
1049 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
1050 GNUNET_SERVER_client_keep (client);
1051 GNUNET_CONTAINER_DLL_insert (clients_head,
1054 GNUNET_SERVER_notification_context_add (nc, client);
1055 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1060 * We got a response from a client.
1063 * @param client the client
1064 * @param message the response
1067 handle_client_response (void *cls GNUNET_UNUSED,
1068 struct GNUNET_SERVER_Client *client,
1069 const struct GNUNET_MessageHeader *message)
1071 const struct GNUNET_DNS_Response *resp;
1072 struct RequestRecord *rr;
1077 msize = ntohs (message->size);
1078 if (msize < sizeof (struct GNUNET_DNS_Response))
1081 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1084 resp = (const struct GNUNET_DNS_Response*) message;
1085 off = (uint16_t) resp->request_id;
1086 rr = &requests[off];
1087 if (rr->request_id != resp->request_id)
1089 GNUNET_STATISTICS_update (stats,
1090 gettext_noop ("# Client response discarded (no matching request)"),
1092 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1095 for (i=0;i<rr->client_wait_list_length;i++)
1097 if (NULL == rr->client_wait_list[i])
1099 if (rr->client_wait_list[i]->client != client)
1101 rr->client_wait_list[i] = NULL;
1102 switch (ntohl (resp->drop_flag))
1105 rr->phase = RP_DROP;
1107 case 1: /* no change */
1109 case 2: /* update */
1110 msize -= sizeof (struct GNUNET_DNS_Response);
1111 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
1112 (RP_REQUEST_MONITOR == rr->phase) ||
1113 (RP_RESPONSE_MONITOR == rr->phase) )
1116 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1120 GNUNET_free_non_null (rr->payload);
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 _("Changing DNS reply according to client specifications\n"));
1125 rr->payload = GNUNET_malloc (msize);
1126 rr->payload_length = msize;
1127 memcpy (rr->payload, &resp[1], msize);
1128 if (rr->phase == RP_QUERY)
1130 /* clear wait list, we're moving to MODIFY phase next */
1131 GNUNET_array_grow (rr->client_wait_list,
1132 rr->client_wait_list_length,
1138 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1141 /* odd, client was not on our list for the request, that ought
1144 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1149 * Functions with this signature are called whenever a complete
1150 * message is received by the tokenizer from the DNS hijack process.
1152 * @param cls closure
1153 * @param client identification of the client
1154 * @param message the actual message, a DNS request we should handle
1157 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1158 const struct GNUNET_MessageHeader *message)
1161 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1162 const struct GNUNET_TUN_IPv4Header *ip4;
1163 const struct GNUNET_TUN_IPv6Header *ip6;
1164 const struct GNUNET_TUN_UdpHeader *udp;
1165 const struct GNUNET_TUN_DnsHeader *dns;
1166 struct RequestRecord *rr;
1167 struct sockaddr_in *srca4;
1168 struct sockaddr_in6 *srca6;
1169 struct sockaddr_in *dsta4;
1170 struct sockaddr_in6 *dsta6;
1172 msize = ntohs (message->size);
1173 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1175 /* non-IP packet received on TUN!? */
1179 msize -= sizeof (struct GNUNET_MessageHeader);
1180 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1181 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1182 switch (ntohs (tun->proto))
1185 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1186 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1187 (ip4->version != 4) ||
1188 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1189 (ntohs(ip4->total_length) != msize) ||
1190 (ip4->protocol != IPPROTO_UDP) )
1192 /* non-IP/UDP packet received on TUN (or with options) */
1193 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1194 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1197 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1198 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1201 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1202 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1203 (ip6->version != 6) ||
1204 (ntohs (ip6->payload_length) != msize) ||
1205 (ip6->next_header != IPPROTO_UDP) )
1207 /* non-IP/UDP packet received on TUN (or with extensions) */
1208 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1209 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1212 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1213 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1216 /* non-IP packet received on TUN!? */
1217 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1218 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1219 (unsigned int) msize,
1220 ntohs (tun->proto));
1223 if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1225 /* non-DNS packet received on TUN, ignore */
1226 GNUNET_STATISTICS_update (stats,
1227 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1231 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1232 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1233 rr = &requests[dns->id];
1235 /* clean up from previous request */
1236 GNUNET_free_non_null (rr->payload);
1237 if (RP_INTERNET_DNS == rr->phase)
1240 if (0 == dns_active)
1241 change_source_ports ();
1244 GNUNET_array_grow (rr->client_wait_list,
1245 rr->client_wait_list_length,
1248 /* setup new request */
1249 rr->phase = RP_INIT;
1250 switch (ntohs (tun->proto))
1254 srca4 = (struct sockaddr_in*) &rr->src_addr;
1255 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1256 memset (srca4, 0, sizeof (struct sockaddr_in));
1257 memset (dsta4, 0, sizeof (struct sockaddr_in));
1258 srca4->sin_family = AF_INET;
1259 dsta4->sin_family = AF_INET;
1260 srca4->sin_addr = ip4->source_address;
1261 dsta4->sin_addr = ip4->destination_address;
1262 srca4->sin_port = udp->source_port;
1263 dsta4->sin_port = udp->destination_port;
1264 #if HAVE_SOCKADDR_IN_SIN_LEN
1265 srca4->sin_len = sizeof (struct sockaddr_in))
1266 dsta4->sin_len = sizeof (struct sockaddr_in);
1272 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1273 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1274 memset (srca6, 0, sizeof (struct sockaddr_in6));
1275 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1276 srca6->sin6_family = AF_INET6;
1277 dsta6->sin6_family = AF_INET6;
1278 srca6->sin6_addr = ip6->source_address;
1279 dsta6->sin6_addr = ip6->destination_address;
1280 srca6->sin6_port = udp->source_port;
1281 dsta6->sin6_port = udp->destination_port;
1282 #if HAVE_SOCKADDR_IN_SIN_LEN
1283 srca6->sin6_len = sizeof (struct sockaddr_in6);
1284 dsta6->sin6_len = sizeof (struct sockaddr_in6);
1291 rr->payload = GNUNET_malloc (msize);
1292 rr->payload_length = msize;
1293 memcpy (rr->payload, dns, msize);
1294 rr->request_id = dns->id | (request_id_gen << 16);
1297 GNUNET_STATISTICS_update (stats,
1298 gettext_noop ("# DNS requests received via TUN interface"),
1300 /* start request processing state machine */
1306 * Process a request via mesh to perform a DNS query.
1308 * @param cls closure, NULL
1309 * @param tunnel connection to the other end
1310 * @param tunnel_ctx pointer to our 'struct TunnelState *'
1311 * @param sender who sent the message
1312 * @param message the actual message
1313 * @param atsi performance data for the connection
1314 * @return GNUNET_OK to keep the connection open,
1315 * GNUNET_SYSERR to close it (signal serious error)
1318 receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1320 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
1321 const struct GNUNET_MessageHeader *message,
1322 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
1324 struct TunnelState *ts = *tunnel_ctx;
1325 const struct GNUNET_TUN_DnsHeader *dns;
1326 size_t mlen = ntohs (message->size);
1327 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1329 struct GNUNET_TUN_DnsHeader *dout;
1330 struct sockaddr_in v4;
1331 struct sockaddr_in6 v6;
1332 struct sockaddr *so;
1334 struct GNUNET_NETWORK_Handle *dnsout;
1336 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1338 GNUNET_break_op (0);
1339 return GNUNET_SYSERR;
1341 dns = (const struct GNUNET_TUN_DnsHeader *) &message[1];
1342 ts->original_id = dns->id;
1343 if (tunnels[ts->my_id] == ts)
1344 tunnels[ts->my_id] = NULL;
1345 ts->my_id = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1347 tunnels[ts->my_id] = ts;
1348 memcpy (buf, dns, dlen);
1349 dout = (struct GNUNET_TUN_DnsHeader*) buf;
1350 dout->id = ts->my_id;
1352 memset (&v4, 0, sizeof (v4));
1353 memset (&v6, 0, sizeof (v6));
1355 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr))
1357 salen = sizeof (v4);
1358 v4.sin_family = AF_INET;
1359 v4.sin_port = htons (53);
1360 #if HAVE_SOCKADDR_IN_SIN_LEN
1361 v4.sin_len = (u_char) salen;
1363 so = (struct sockaddr *) &v4;
1366 if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1368 salen = sizeof (v6);
1369 v6.sin6_family = AF_INET6;
1370 v6.sin6_port = htons (53);
1371 #if HAVE_SOCKADDR_IN_SIN_LEN
1372 v6.sin6_len = (u_char) salen;
1374 so = (struct sockaddr *) &v6;
1379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1380 _("Configured DNS exit `%s' is not working / valid.\n"),
1382 return GNUNET_SYSERR;
1387 ts->addrlen = salen;
1388 GNUNET_NETWORK_socket_sendto (dnsout,
1389 buf, dlen, so, salen);
1395 * Callback from GNUNET_MESH for new tunnels.
1397 * @param cls closure
1398 * @param tunnel new handle to the tunnel
1399 * @param initiator peer that started the tunnel
1400 * @param ats performance information for the tunnel
1401 * @return initial tunnel context for the tunnel
1404 accept_dns_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1405 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
1406 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
1408 struct TunnelState *ts = GNUNET_malloc (sizeof (struct TunnelState));
1410 GNUNET_STATISTICS_update (stats,
1411 gettext_noop ("# Inbound MESH tunnels created"),
1413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414 "Received inbound tunnel from `%s'\n",
1415 GNUNET_i2s (initiator));
1416 ts->tunnel = tunnel;
1422 * Function called by mesh whenever an inbound tunnel is destroyed.
1423 * Should clean up any associated state.
1425 * @param cls closure (set from GNUNET_MESH_connect)
1426 * @param tunnel connection to the other end (henceforth invalid)
1427 * @param tunnel_ctx place where local state associated
1428 * with the tunnel is stored
1431 destroy_dns_tunnel (void *cls GNUNET_UNUSED,
1432 const struct GNUNET_MESH_Tunnel *tunnel,
1435 struct TunnelState *ts = tunnel_ctx;
1437 if (tunnels[ts->my_id] == ts)
1438 tunnels[ts->my_id] = NULL;
1440 GNUNET_MESH_notify_transmit_ready_cancel (ts->th);
1441 GNUNET_free_non_null (ts->reply);
1447 * @param cls closure
1448 * @param server the initialized server
1449 * @param cfg_ configuration to use
1452 run (void *cls, struct GNUNET_SERVER_Handle *server,
1453 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1455 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1456 /* callback, cls, type, size */
1457 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1458 sizeof (struct GNUNET_DNS_Register)},
1459 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1469 stats = GNUNET_STATISTICS_create ("dns", cfg);
1470 nc = GNUNET_SERVER_notification_context_create (server, 1);
1471 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1473 (void) GNUNET_CONFIGURATION_get_value_string (cfg, "dns",
1477 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1479 if ( (GNUNET_OK != open_port4 ()) &&
1480 (GNUNET_OK != open_port6 ()) )
1482 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1483 _("Failed to open any port to provide DNS exit\n"));
1484 GNUNET_SCHEDULER_shutdown ();
1489 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1490 if (GNUNET_SYSERR ==
1491 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1493 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1494 "No entry 'IFNAME' in configuration!\n");
1495 GNUNET_SCHEDULER_shutdown ();
1498 helper_argv[1] = ifc_name;
1499 if ( (GNUNET_SYSERR ==
1500 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1503 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1504 "No entry 'IPV6ADDR' in configuration!\n");
1505 GNUNET_SCHEDULER_shutdown ();
1508 helper_argv[2] = ipv6addr;
1509 if (GNUNET_SYSERR ==
1510 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1513 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1514 "No entry 'IPV6PREFIX' in configuration!\n");
1515 GNUNET_SCHEDULER_shutdown ();
1518 helper_argv[3] = ipv6prefix;
1520 if (GNUNET_SYSERR ==
1521 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1525 "No entry 'IPV4ADDR' in configuration!\n");
1526 GNUNET_SCHEDULER_shutdown ();
1529 helper_argv[4] = ipv4addr;
1530 if (GNUNET_SYSERR ==
1531 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1534 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1535 "No entry 'IPV4MASK' in configuration!\n");
1536 GNUNET_SCHEDULER_shutdown ();
1539 helper_argv[5] = ipv4mask;
1540 helper_argv[6] = NULL;
1542 if (NULL != dns_exit)
1544 static struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1545 {&receive_dns_request, GNUNET_MESSAGE_TYPE_VPN_DNS_TO_INTERNET, 0},
1548 static GNUNET_MESH_ApplicationType mesh_types[] = {
1549 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER,
1550 GNUNET_APPLICATION_TYPE_END
1552 mesh = GNUNET_MESH_connect (cfg,
1555 &destroy_dns_tunnel,
1559 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1561 &process_helper_messages,
1563 GNUNET_SERVER_add_handlers (server, handlers);
1564 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1569 * The main function for the dns service.
1571 * @param argc number of arguments from the command line
1572 * @param argv command line arguments
1573 * @return 0 ok, 1 on error
1576 main (int argc, char *const *argv)
1578 return (GNUNET_OK ==
1579 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1580 &run, NULL)) ? 0 : 1;
1584 /* end of gnunet-service-dns.c */