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_constants.h"
29 #include "gnunet_protocols.h"
30 #include "gnunet_signatures.h"
32 #include "gnunet_dns_service.h"
33 #include "gnunet_statistics_service.h"
34 #include "gnunet_tun_lib.h"
38 * Phases each request goes through.
43 * Request has just been received.
48 * Showing the request to all monitor clients. If
49 * client list is empty, will enter QUERY phase.
54 * Showing the request to PRE-RESOLUTION clients to find an answer.
55 * If client list is empty, will trigger global DNS request.
60 * Global Internet query is now pending.
65 * Client (or global DNS request) has resulted in a response.
66 * Forward to all POST-RESOLUTION clients. If client list is empty,
67 * will enter RESPONSE_MONITOR phase.
72 * Showing the request to all monitor clients. If
73 * client list is empty, give the result to the hijacker (and be done).
78 * Some client has told us to drop the request.
85 * Entry we keep for each client.
90 * Kept in doubly-linked list.
92 struct ClientRecord *next;
95 * Kept in doubly-linked list.
97 struct ClientRecord *prev;
100 * Handle to the client.
102 struct GNUNET_SERVER_Client *client;
105 * Flags for the client.
107 enum GNUNET_DNS_Flags flags;
113 * Entry we keep for each active request.
119 * List of clients that still need to see this request (each entry
120 * is set to NULL when the client is done).
122 struct ClientRecord **client_wait_list;
125 * Payload of the UDP packet (the UDP payload), can be either query
126 * or already the response.
131 * Source address of the original request (for sending response).
133 struct sockaddr_storage src_addr;
136 * Destination address of the original request (for potential use as exit).
138 struct sockaddr_storage dst_addr;
141 * ID of this request, also basis for hashing. Lowest 16 bit will
142 * be our message ID when doing a global DNS request and our index
143 * into the 'requests' array.
148 * Number of bytes in payload.
150 size_t payload_length;
153 * Length of the client wait list.
155 unsigned int client_wait_list_length;
158 * In which phase this this request?
160 enum RequestPhase phase;
166 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
167 * sent through gnunet. The port of this socket will not be hijacked.
169 static struct GNUNET_NETWORK_Handle *dnsout4;
172 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
173 * sent through gnunet. The port of this socket will not be hijacked.
175 static struct GNUNET_NETWORK_Handle *dnsout6;
178 * Task for reading from dnsout4.
180 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
183 * Task for reading from dnsout6.
185 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
188 * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind
189 * both sockets to the same port.
191 static uint16_t dnsoutport;
194 * The configuration to use
196 static const struct GNUNET_CONFIGURATION_Handle *cfg;
201 static struct GNUNET_STATISTICS_Handle *stats;
204 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
206 static struct GNUNET_HELPER_Handle *hijacker;
209 * Command-line arguments we are giving to the hijacker process.
211 static char *helper_argv[8];
214 * Head of DLL of clients we consult.
216 static struct ClientRecord *clients_head;
219 * Tail of DLL of clients we consult.
221 static struct ClientRecord *clients_tail;
224 * Our notification context.
226 static struct GNUNET_SERVER_NotificationContext *nc;
229 * Array of all open requests.
231 static struct RequestRecord requests[UINT16_MAX + 1];
234 * Generator for unique request IDs.
236 static uint64_t request_id_gen;
240 * We're done processing a DNS request, free associated memory.
242 * @param rr request to clean up
245 cleanup_rr (struct RequestRecord *rr)
247 GNUNET_free_non_null (rr->payload);
249 rr->payload_length = 0;
250 GNUNET_array_grow (rr->client_wait_list,
251 rr->client_wait_list_length,
257 * Task run during shutdown.
263 cleanup_task (void *cls GNUNET_UNUSED,
264 const struct GNUNET_SCHEDULER_TaskContext *tc)
268 GNUNET_HELPER_stop (hijacker);
271 GNUNET_free_non_null (helper_argv[i]);
274 GNUNET_NETWORK_socket_close (dnsout4);
277 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
279 GNUNET_SCHEDULER_cancel (read4_task);
280 read4_task = GNUNET_SCHEDULER_NO_TASK;
284 GNUNET_NETWORK_socket_close (dnsout6);
287 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
289 GNUNET_SCHEDULER_cancel (read6_task);
290 read6_task = GNUNET_SCHEDULER_NO_TASK;
292 for (i=0;i<65536;i++)
293 cleanup_rr (&requests[i]);
294 GNUNET_SERVER_notification_context_destroy (nc);
298 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
305 * We're done with some request, finish processing.
307 * @param rr request send to the network or just clean up.
310 request_done (struct RequestRecord *rr)
312 struct GNUNET_MessageHeader *hdr;
317 GNUNET_array_grow (rr->client_wait_list,
318 rr->client_wait_list_length,
320 if (RP_RESPONSE_MONITOR != rr->phase)
322 /* no response, drop */
327 /* send response via hijacker */
328 reply_len = sizeof (struct GNUNET_MessageHeader);
329 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
330 switch (rr->src_addr.ss_family)
333 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
336 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
343 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
344 reply_len += rr->payload_length;
345 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
347 /* response too big, drop */
348 GNUNET_break (0); /* how can this be? */
355 struct GNUNET_TUN_IPv4Header ip4;
356 struct GNUNET_TUN_IPv6Header ip6;
358 /* first, GNUnet message header */
359 hdr = (struct GNUNET_MessageHeader*) buf;
360 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
361 hdr->size = htons ((uint16_t) reply_len);
362 off = sizeof (struct GNUNET_MessageHeader);
364 /* first, TUN header */
366 struct GNUNET_TUN_Layer2PacketHeader tun;
368 tun.flags = htons (0);
369 if (rr->src_addr.ss_family == AF_INET)
370 tun.proto = htons (ETH_P_IPV4);
372 tun.proto = htons (ETH_P_IPV6);
373 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
374 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
378 switch (rr->src_addr.ss_family)
382 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
383 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
387 GNUNET_TUN_initialize_ipv4_header (&ip4,
389 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
392 memcpy (&buf[off], &ip4, sizeof (ip4));
398 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
399 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
401 spt = dst->sin6_port;
402 dpt = src->sin6_port;
403 GNUNET_TUN_initialize_ipv6_header (&ip6,
405 reply_len - sizeof (struct GNUNET_TUN_IPv6Header),
408 memcpy (&buf[off], &ip6, sizeof (ip6));
418 struct GNUNET_TUN_UdpHeader udp;
422 udp.len = htons (reply_len - off);
423 if (AF_INET == rr->src_addr.ss_family)
424 GNUNET_TUN_calculate_udp4_checksum (&ip4,
429 GNUNET_TUN_calculate_udp6_checksum (&ip6,
433 memcpy (&buf[off], &udp, sizeof (udp));
437 /* now DNS payload */
439 memcpy (&buf[off], rr->payload, rr->payload_length);
440 off += rr->payload_length;
442 /* final checks & sending */
443 GNUNET_assert (off == reply_len);
444 GNUNET_HELPER_send (hijacker,
448 GNUNET_STATISTICS_update (stats,
449 gettext_noop ("# DNS requests answered via TUN interface"),
452 /* clean up, we're done */
458 * Show the payload of the given request record to the client
459 * (and wait for a response).
461 * @param rr request to send to client
462 * @param client client to send the response to
465 send_request_to_client (struct RequestRecord *rr,
466 struct GNUNET_SERVER_Client *client)
468 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
469 struct GNUNET_DNS_Request *req;
471 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
477 req = (struct GNUNET_DNS_Request*) buf;
478 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
479 req->header.size = htons (sizeof (buf));
480 req->reserved = htonl (0);
481 req->request_id = rr->request_id;
482 memcpy (&req[1], rr->payload, rr->payload_length);
483 GNUNET_SERVER_notification_context_unicast (nc,
491 * A client has completed its processing for this
494 * @param rr request to process further
497 next_phase (struct RequestRecord *rr)
499 struct ClientRecord *cr;
502 struct GNUNET_NETWORK_Handle *dnsout;
505 if (rr->phase == RP_DROP)
511 for (j=0;j<rr->client_wait_list_length;j++)
513 if (NULL != rr->client_wait_list[j])
521 send_request_to_client (rr, rr->client_wait_list[nz]->client);
524 /* done with current phase, advance! */
528 rr->phase = RP_REQUEST_MONITOR;
529 for (cr = clients_head; NULL != cr; cr = cr->next)
531 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
532 GNUNET_array_append (rr->client_wait_list,
533 rr->client_wait_list_length,
538 case RP_REQUEST_MONITOR:
539 rr->phase = RP_QUERY;
540 for (cr = clients_head; NULL != cr; cr = cr->next)
542 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
543 GNUNET_array_append (rr->client_wait_list,
544 rr->client_wait_list_length,
550 rr->phase = RP_INTERNET_DNS;
551 switch (rr->dst_addr.ss_family)
555 salen = sizeof (struct GNUNET_TUN_IPv4Header);
559 salen = sizeof (struct GNUNET_TUN_IPv6Header);
568 GNUNET_STATISTICS_update (stats,
569 gettext_noop ("# DNS exit failed (address family not supported)"),
574 GNUNET_NETWORK_socket_sendto (dnsout,
577 (struct sockaddr*) &rr->dst_addr,
580 case RP_INTERNET_DNS:
581 rr->phase = RP_MODIFY;
582 for (cr = clients_head; NULL != cr; cr = cr->next)
584 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
585 GNUNET_array_append (rr->client_wait_list,
586 rr->client_wait_list_length,
592 rr->phase = RP_RESPONSE_MONITOR;
593 for (cr = clients_head; NULL != cr; cr = cr->next)
595 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
596 GNUNET_array_append (rr->client_wait_list,
597 rr->client_wait_list_length,
602 case RP_RESPONSE_MONITOR:
617 * A client disconnected, clean up after it.
620 * @param client handle of client that disconnected
623 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
625 struct ClientRecord *cr;
626 struct RequestRecord *rr;
630 for (cr = clients_head; NULL != cr; cr = cr->next)
632 if (cr->client == client)
634 GNUNET_SERVER_client_drop (client);
635 GNUNET_CONTAINER_DLL_remove (clients_head,
638 for (i=0;i<UINT16_MAX;i++)
641 if (0 == rr->client_wait_list_length)
642 continue; /* not in use */
643 for (j=0;j<rr->client_wait_list_length;j++)
645 if (rr->client_wait_list[j] == cr)
647 rr->client_wait_list[j] = NULL;
660 * Read a DNS response from the (unhindered) UDP-Socket
662 * @param cls socket to read from
663 * @param tc scheduler context (must be shutdown or read ready)
666 read_response (void *cls,
667 const struct GNUNET_SCHEDULER_TaskContext *tc)
669 struct GNUNET_NETWORK_Handle *dnsout = cls;
670 struct sockaddr_in addr4;
671 struct sockaddr_in6 addr6;
672 struct sockaddr *addr;
673 struct GNUNET_TUN_DnsHeader *dns;
675 struct RequestRecord *rr;
679 if (dnsout == dnsout4)
681 addrlen = sizeof (struct sockaddr_in);
682 addr = (struct sockaddr* ) &addr4;
683 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
690 addrlen = sizeof (struct sockaddr_in6);
691 addr = (struct sockaddr* ) &addr6;
692 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
697 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
701 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
703 /* conservative choice: */
707 /* port the code above? */
712 unsigned char buf[len];
714 memset (addr, 0, addrlen);
715 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
720 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
723 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
725 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
726 _("Received DNS response that is too small (%u bytes)"),
730 dns = (struct GNUNET_TUN_DnsHeader *) buf;
731 rr = &requests[dns->id];
732 if (rr->phase != RP_INTERNET_DNS)
734 /* unexpected / bogus reply */
735 GNUNET_STATISTICS_update (stats,
736 gettext_noop ("# External DNS response discarded (no matching request)"),
740 GNUNET_free_non_null (rr->payload);
741 rr->payload = GNUNET_malloc (len);
742 memcpy (rr->payload, buf, len);
743 rr->payload_length = len;
750 * Open source port for sending DNS request on IPv4.
752 * @return GNUNET_OK on success
757 struct sockaddr_in addr;
760 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
762 return GNUNET_SYSERR;
764 memset (&addr, 0, sizeof (struct sockaddr_in));
765 addr.sin_family = AF_INET;
766 int err = GNUNET_NETWORK_socket_bind (dnsout4,
767 (struct sockaddr *) &addr,
768 sizeof (struct sockaddr_in));
770 if (err != GNUNET_OK)
772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773 _("Could not bind to any port: %s\n"),
775 GNUNET_NETWORK_socket_close (dnsout4);
777 return GNUNET_SYSERR;
780 /* Read the port we bound to */
781 addrlen = sizeof (struct sockaddr_in);
782 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4),
783 (struct sockaddr *) &addr,
786 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
787 _("Could not determine port I got: %s\n"),
789 GNUNET_NETWORK_socket_close (dnsout4);
791 return GNUNET_SYSERR;
793 dnsoutport = htons (addr.sin_port);
795 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
796 _("GNUnet DNS will exit on source port %u\n"),
797 (unsigned int) dnsoutport);
798 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
800 &read_response, dnsout4);
806 * Open source port for sending DNS request on IPv6. Should be
807 * called AFTER open_port4.
809 * @return GNUNET_OK on success
814 struct sockaddr_in6 addr;
817 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
820 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
821 _("Could not create IPv6 socket: %s\n"),
823 return GNUNET_SYSERR;
825 memset (&addr, 0, sizeof (struct sockaddr_in6));
826 addr.sin6_family = AF_INET6;
827 addr.sin6_port = htons (dnsoutport);
828 int err = GNUNET_NETWORK_socket_bind (dnsout6,
829 (struct sockaddr *) &addr,
830 sizeof (struct sockaddr_in6));
832 if (err != GNUNET_OK)
834 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
835 _("Could not bind to port %u: %s\n"),
836 (unsigned int) dnsoutport,
838 GNUNET_NETWORK_socket_close (dnsout6);
840 return GNUNET_SYSERR;
844 addrlen = sizeof (struct sockaddr_in6);
845 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6),
846 (struct sockaddr *) &addr,
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
850 _("Could not determine port I got: %s\n"),
852 GNUNET_NETWORK_socket_close (dnsout6);
854 return GNUNET_SYSERR;
857 dnsoutport = htons (addr.sin6_port);
858 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
860 &read_response, dnsout6);
866 * We got a new client. Make sure all new DNS requests pass by its desk.
869 * @param client the new client
870 * @param message the init message (unused)
873 handle_client_init (void *cls GNUNET_UNUSED,
874 struct GNUNET_SERVER_Client *client,
875 const struct GNUNET_MessageHeader *message)
877 struct ClientRecord *cr;
878 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
880 cr = GNUNET_malloc (sizeof (struct ClientRecord));
882 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
883 GNUNET_SERVER_client_keep (client);
884 GNUNET_CONTAINER_DLL_insert (clients_head,
887 GNUNET_SERVER_notification_context_add (nc, client);
888 GNUNET_SERVER_receive_done (client, GNUNET_OK);
893 * We got a response from a client.
896 * @param client the client
897 * @param message the response
900 handle_client_response (void *cls GNUNET_UNUSED,
901 struct GNUNET_SERVER_Client *client,
902 const struct GNUNET_MessageHeader *message)
904 const struct GNUNET_DNS_Response *resp;
905 struct RequestRecord *rr;
910 msize = ntohs (message->size);
911 if (msize < sizeof (struct GNUNET_DNS_Response))
914 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
917 resp = (const struct GNUNET_DNS_Response*) message;
918 off = (uint16_t) resp->request_id;
920 if (rr->request_id != resp->request_id)
922 GNUNET_STATISTICS_update (stats,
923 gettext_noop ("# Client response discarded (no matching request)"),
925 GNUNET_SERVER_receive_done (client, GNUNET_OK);
928 for (i=0;i<rr->client_wait_list_length;i++)
930 if (NULL == rr->client_wait_list[i])
932 if (rr->client_wait_list[i]->client != client)
934 rr->client_wait_list[i] = NULL;
935 switch (ntohl (resp->drop_flag))
940 case 1: /* no change */
943 msize -= sizeof (struct GNUNET_DNS_Response);
944 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
945 (RP_REQUEST_MONITOR == rr->phase) ||
946 (RP_RESPONSE_MONITOR == rr->phase) )
949 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
953 GNUNET_free_non_null (rr->payload);
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956 _("Changing DNS reply according to client specifications\n"));
958 rr->payload = GNUNET_malloc (msize);
959 rr->payload_length = msize;
960 memcpy (rr->payload, &resp[1], msize);
961 if (rr->phase == RP_QUERY)
963 /* clear wait list, we're moving to MODIFY phase next */
964 GNUNET_array_grow (rr->client_wait_list,
965 rr->client_wait_list_length,
971 GNUNET_SERVER_receive_done (client, GNUNET_OK);
974 /* odd, client was not on our list for the request, that ought
977 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
982 * Functions with this signature are called whenever a complete
983 * message is received by the tokenizer from the DNS hijack process.
986 * @param client identification of the client
987 * @param message the actual message, a DNS request we should handle
990 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
991 const struct GNUNET_MessageHeader *message)
994 const struct GNUNET_TUN_Layer2PacketHeader *tun;
995 const struct GNUNET_TUN_IPv4Header *ip4;
996 const struct GNUNET_TUN_IPv6Header *ip6;
997 const struct GNUNET_TUN_UdpHeader *udp;
998 const struct GNUNET_TUN_DnsHeader *dns;
999 struct RequestRecord *rr;
1000 struct sockaddr_in *srca4;
1001 struct sockaddr_in6 *srca6;
1002 struct sockaddr_in *dsta4;
1003 struct sockaddr_in6 *dsta6;
1005 msize = ntohs (message->size);
1006 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1008 /* non-IP packet received on TUN!? */
1012 msize -= sizeof (struct GNUNET_MessageHeader);
1013 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1014 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1015 switch (ntohs (tun->proto))
1018 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1019 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1020 (ip4->version != 4) ||
1021 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1022 (ntohs(ip4->total_length) != msize) ||
1023 (ip4->protocol != IPPROTO_UDP) )
1025 /* non-IP/UDP packet received on TUN (or with options) */
1026 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1027 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1030 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1031 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1034 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1035 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1036 (ip6->version != 6) ||
1037 (ntohs (ip6->payload_length) != msize) ||
1038 (ip6->next_header != IPPROTO_UDP) )
1040 /* non-IP/UDP packet received on TUN (or with extensions) */
1041 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1042 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1045 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1046 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1049 /* non-IP packet received on TUN!? */
1050 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1051 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1052 (unsigned int) msize,
1053 ntohs (tun->proto));
1056 if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1058 /* non-DNS packet received on TUN, ignore */
1059 GNUNET_STATISTICS_update (stats,
1060 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1064 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1065 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1066 rr = &requests[dns->id];
1068 /* clean up from previous request */
1069 GNUNET_free_non_null (rr->payload);
1071 GNUNET_array_grow (rr->client_wait_list,
1072 rr->client_wait_list_length,
1075 /* setup new request */
1076 rr->phase = RP_INIT;
1077 if (ip4->version == 4)
1079 srca4 = (struct sockaddr_in*) &rr->src_addr;
1080 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1081 memset (srca4, 0, sizeof (struct sockaddr_in));
1082 memset (dsta4, 0, sizeof (struct sockaddr_in));
1083 srca4->sin_family = AF_INET;
1084 dsta4->sin_family = AF_INET;
1085 srca4->sin_addr = ip4->source_address;
1086 dsta4->sin_addr = ip4->destination_address;
1087 srca4->sin_port = udp->spt;
1088 dsta4->sin_port = udp->dpt;
1089 #if HAVE_SOCKADDR_IN_SIN_LEN
1090 srca4->sin_len = sizeof (sizeof (struct sockaddr_in));
1091 dsta4->sin_len = sizeof (sizeof (struct sockaddr_in));
1096 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1097 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1098 memset (srca6, 0, sizeof (struct sockaddr_in6));
1099 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1100 srca6->sin6_family = AF_INET6;
1101 dsta6->sin6_family = AF_INET6;
1102 srca6->sin6_addr = ip6->source_address;
1103 dsta6->sin6_addr = ip6->destination_address;
1104 srca6->sin6_port = udp->spt;
1105 dsta6->sin6_port = udp->dpt;
1106 #if HAVE_SOCKADDR_IN_SIN_LEN
1107 srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1108 dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1111 rr->payload = GNUNET_malloc (msize);
1112 rr->payload_length = msize;
1113 memcpy (rr->payload, dns, msize);
1114 rr->request_id = dns->id | (request_id_gen << 16);
1117 GNUNET_STATISTICS_update (stats,
1118 gettext_noop ("# DNS requests received via TUN interface"),
1120 /* start request processing state machine */
1126 * @param cls closure
1127 * @param server the initialized server
1128 * @param cfg_ configuration to use
1131 run (void *cls, struct GNUNET_SERVER_Handle *server,
1132 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1134 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1135 /* callback, cls, type, size */
1136 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1137 sizeof (struct GNUNET_DNS_Register)},
1138 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1149 stats = GNUNET_STATISTICS_create ("dns", cfg);
1150 nc = GNUNET_SERVER_notification_context_create (server, 1);
1151 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1154 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1156 if ( (GNUNET_OK != open_port4 ()) &&
1157 (GNUNET_OK != open_port6 ()) )
1159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1160 _("Failed to open any port to provide DNS exit\n"));
1161 GNUNET_SCHEDULER_shutdown ();
1166 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1167 if (GNUNET_SYSERR ==
1168 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1171 "No entry 'IFNAME' in configuration!\n");
1172 GNUNET_SCHEDULER_shutdown ();
1175 helper_argv[1] = ifc_name;
1176 if ( (GNUNET_SYSERR ==
1177 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1180 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1181 "No entry 'IPV6ADDR' in configuration!\n");
1182 GNUNET_SCHEDULER_shutdown ();
1185 helper_argv[2] = ipv6addr;
1186 if (GNUNET_SYSERR ==
1187 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1191 "No entry 'IPV6PREFIX' in configuration!\n");
1192 GNUNET_SCHEDULER_shutdown ();
1195 helper_argv[3] = ipv6prefix;
1197 if (GNUNET_SYSERR ==
1198 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1201 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1202 "No entry 'IPV4ADDR' in configuration!\n");
1203 GNUNET_SCHEDULER_shutdown ();
1206 helper_argv[4] = ipv4addr;
1207 if (GNUNET_SYSERR ==
1208 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1212 "No entry 'IPV4MASK' in configuration!\n");
1213 GNUNET_SCHEDULER_shutdown ();
1216 helper_argv[5] = ipv4mask;
1217 GNUNET_snprintf (port_s,
1220 (unsigned int) dnsoutport);
1221 helper_argv[6] = GNUNET_strdup (port_s);
1222 helper_argv[7] = NULL;
1223 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1225 &process_helper_messages,
1227 GNUNET_SERVER_add_handlers (server, handlers);
1228 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1233 * The main function for the dns service.
1235 * @param argc number of arguments from the command line
1236 * @param argv command line arguments
1237 * @return 0 ok, 1 on error
1240 main (int argc, char *const *argv)
1242 return (GNUNET_OK ==
1243 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1244 &run, NULL)) ? 0 : 1;
1248 /* end of gnunet-service-dns.c */