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 * @author Christian Grothoff
26 #include "gnunet_util_lib.h"
27 #include "gnunet_constants.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_signatures.h"
31 #include "gnunet_dns_service.h"
32 #include "gnunet_statistics_service.h"
33 #include "gnunet_tun_lib.h"
37 * Phases each request goes through.
42 * Request has just been received.
47 * Showing the request to all monitor clients. If
48 * client list is empty, will enter QUERY phase.
53 * Showing the request to PRE-RESOLUTION clients to find an answer.
54 * If client list is empty, will trigger global DNS request.
59 * Global Internet query is now pending.
64 * Client (or global DNS request) has resulted in a response.
65 * Forward to all POST-RESOLUTION clients. If client list is empty,
66 * will enter RESPONSE_MONITOR phase.
71 * Showing the request to all monitor clients. If
72 * client list is empty, give the result to the hijacker (and be done).
77 * Some client has told us to drop the request.
84 * Entry we keep for each client.
89 * Kept in doubly-linked list.
91 struct ClientRecord *next;
94 * Kept in doubly-linked list.
96 struct ClientRecord *prev;
99 * Handle to the client.
101 struct GNUNET_SERVER_Client *client;
104 * Flags for the client.
106 enum GNUNET_DNS_Flags flags;
112 * Entry we keep for each active request.
118 * List of clients that still need to see this request (each entry
119 * is set to NULL when the client is done).
121 struct ClientRecord **client_wait_list;
124 * Payload of the UDP packet (the UDP payload), can be either query
125 * or already the response.
130 * Source address of the original request (for sending response).
132 struct sockaddr_storage src_addr;
135 * Destination address of the original request (for potential use as exit).
137 struct sockaddr_storage dst_addr;
140 * ID of this request, also basis for hashing. Lowest 16 bit will
141 * be our message ID when doing a global DNS request and our index
142 * into the 'requests' array.
147 * Number of bytes in payload.
149 size_t payload_length;
152 * Length of the client wait list.
154 unsigned int client_wait_list_length;
157 * In which phase this this request?
159 enum RequestPhase phase;
165 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
166 * sent through gnunet. The port of this socket will not be hijacked.
168 static struct GNUNET_NETWORK_Handle *dnsout4;
171 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
172 * sent through gnunet. The port of this socket will not be hijacked.
174 static struct GNUNET_NETWORK_Handle *dnsout6;
177 * Task for reading from dnsout4.
179 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
182 * Task for reading from dnsout6.
184 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
187 * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind
188 * both sockets to the same port.
190 static uint16_t dnsoutport;
193 * The configuration to use
195 static const struct GNUNET_CONFIGURATION_Handle *cfg;
200 static struct GNUNET_STATISTICS_Handle *stats;
203 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
205 static struct GNUNET_HELPER_Handle *hijacker;
208 * Command-line arguments we are giving to the hijacker process.
210 static char *helper_argv[8];
213 * Head of DLL of clients we consult.
215 static struct ClientRecord *clients_head;
218 * Tail of DLL of clients we consult.
220 static struct ClientRecord *clients_tail;
223 * Our notification context.
225 static struct GNUNET_SERVER_NotificationContext *nc;
228 * Array of all open requests.
230 static struct RequestRecord requests[UINT16_MAX + 1];
233 * Generator for unique request IDs.
235 static uint64_t request_id_gen;
239 * We're done processing a DNS request, free associated memory.
241 * @param rr request to clean up
244 cleanup_rr (struct RequestRecord *rr)
246 GNUNET_free_non_null (rr->payload);
248 rr->payload_length = 0;
249 GNUNET_array_grow (rr->client_wait_list,
250 rr->client_wait_list_length,
256 * Task run during shutdown.
262 cleanup_task (void *cls GNUNET_UNUSED,
263 const struct GNUNET_SCHEDULER_TaskContext *tc)
267 GNUNET_HELPER_stop (hijacker);
270 GNUNET_free_non_null (helper_argv[i]);
273 GNUNET_NETWORK_socket_close (dnsout4);
276 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
278 GNUNET_SCHEDULER_cancel (read4_task);
279 read4_task = GNUNET_SCHEDULER_NO_TASK;
283 GNUNET_NETWORK_socket_close (dnsout6);
286 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
288 GNUNET_SCHEDULER_cancel (read6_task);
289 read6_task = GNUNET_SCHEDULER_NO_TASK;
291 for (i=0;i<65536;i++)
292 cleanup_rr (&requests[i]);
293 GNUNET_SERVER_notification_context_destroy (nc);
297 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
304 * We're done with some request, finish processing.
306 * @param rr request send to the network or just clean up.
309 request_done (struct RequestRecord *rr)
311 struct GNUNET_MessageHeader *hdr;
316 GNUNET_array_grow (rr->client_wait_list,
317 rr->client_wait_list_length,
319 if (RP_RESPONSE_MONITOR != rr->phase)
321 /* no response, drop */
326 /* send response via hijacker */
327 reply_len = sizeof (struct GNUNET_MessageHeader);
328 reply_len += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
329 switch (rr->src_addr.ss_family)
332 reply_len += sizeof (struct GNUNET_TUN_IPv4Header);
335 reply_len += sizeof (struct GNUNET_TUN_IPv6Header);
342 reply_len += sizeof (struct GNUNET_TUN_UdpHeader);
343 reply_len += rr->payload_length;
344 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
346 /* response too big, drop */
347 GNUNET_break (0); /* how can this be? */
354 uint32_t udp_crc_sum;
356 /* first, GNUnet message header */
357 hdr = (struct GNUNET_MessageHeader*) buf;
358 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
359 hdr->size = htons ((uint16_t) reply_len);
360 off = sizeof (struct GNUNET_MessageHeader);
362 /* first, TUN header */
364 struct GNUNET_TUN_Layer2PacketHeader tun;
366 tun.flags = htons (0);
367 if (rr->src_addr.ss_family == AF_INET)
368 tun.proto = htons (ETH_P_IPV4);
370 tun.proto = htons (ETH_P_IPV6);
371 memcpy (&buf[off], &tun, sizeof (struct GNUNET_TUN_Layer2PacketHeader));
372 off += sizeof (struct GNUNET_TUN_Layer2PacketHeader);
377 switch (rr->src_addr.ss_family)
381 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
382 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
383 struct GNUNET_TUN_IPv4Header ip;
387 GNUNET_TUN_initialize_ipv4_header (&ip,
389 reply_len - off - sizeof (struct GNUNET_TUN_IPv4Header),
395 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
397 sizeof (struct in_addr) * 2);
401 tmp = htons (IPPROTO_UDP);
402 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
405 tmp = htons (rr->payload_length + sizeof (struct GNUNET_TUN_UdpHeader));
406 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
410 memcpy (&buf[off], &ip, sizeof (ip));
416 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
417 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
418 struct GNUNET_TUN_IPv6Header ip;
420 spt = dst->sin6_port;
421 dpt = src->sin6_port;
422 ip.traffic_class_h = 0;
423 ip.version = 6; /* is there a named constant? I couldn't find one */
424 ip.traffic_class_l = 0;
426 ip.payload_length = htons ((uint16_t) reply_len);
427 ip.next_header = IPPROTO_UDP;
428 ip.hop_limit = 255; /* or lower? */
429 ip.source_address = dst->sin6_addr;
430 ip.destination_address = src->sin6_addr;
431 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
433 sizeof (struct in6_addr) * 2);
437 tmp = htons (rr->payload_length + sizeof (struct GNUNET_TUN_UdpHeader));
438 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
441 tmp = htons (IPPROTO_UDP);
442 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
446 memcpy (&buf[off], &ip, sizeof (ip));
456 struct GNUNET_TUN_UdpHeader udp;
460 udp.len = htons (reply_len - off);
462 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
465 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
468 udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum);
469 memcpy (&buf[off], &udp, sizeof (udp));
472 /* now DNS payload */
474 memcpy (&buf[off], rr->payload, rr->payload_length);
475 off += rr->payload_length;
477 /* final checks & sending */
478 GNUNET_assert (off == reply_len);
479 GNUNET_HELPER_send (hijacker,
483 GNUNET_STATISTICS_update (stats,
484 gettext_noop ("# DNS requests answered via TUN interface"),
487 /* clean up, we're done */
493 * Show the payload of the given request record to the client
494 * (and wait for a response).
496 * @param rr request to send to client
497 * @param client client to send the response to
500 send_request_to_client (struct RequestRecord *rr,
501 struct GNUNET_SERVER_Client *client)
503 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
504 struct GNUNET_DNS_Request *req;
506 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
512 req = (struct GNUNET_DNS_Request*) buf;
513 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
514 req->header.size = htons (sizeof (buf));
515 req->reserved = htonl (0);
516 req->request_id = rr->request_id;
517 memcpy (&req[1], rr->payload, rr->payload_length);
518 GNUNET_SERVER_notification_context_unicast (nc,
526 * A client has completed its processing for this
529 * @param rr request to process further
532 next_phase (struct RequestRecord *rr)
534 struct ClientRecord *cr;
537 struct GNUNET_NETWORK_Handle *dnsout;
540 if (rr->phase == RP_DROP)
546 for (j=0;j<rr->client_wait_list_length;j++)
548 if (NULL != rr->client_wait_list[j])
556 send_request_to_client (rr, rr->client_wait_list[nz]->client);
559 /* done with current phase, advance! */
563 rr->phase = RP_REQUEST_MONITOR;
564 for (cr = clients_head; NULL != cr; cr = cr->next)
566 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
567 GNUNET_array_append (rr->client_wait_list,
568 rr->client_wait_list_length,
573 case RP_REQUEST_MONITOR:
574 rr->phase = RP_QUERY;
575 for (cr = clients_head; NULL != cr; cr = cr->next)
577 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
578 GNUNET_array_append (rr->client_wait_list,
579 rr->client_wait_list_length,
585 rr->phase = RP_INTERNET_DNS;
586 switch (rr->dst_addr.ss_family)
590 salen = sizeof (struct GNUNET_TUN_IPv4Header);
594 salen = sizeof (struct GNUNET_TUN_IPv6Header);
603 GNUNET_STATISTICS_update (stats,
604 gettext_noop ("# DNS exit failed (address family not supported)"),
609 GNUNET_NETWORK_socket_sendto (dnsout,
612 (struct sockaddr*) &rr->dst_addr,
615 case RP_INTERNET_DNS:
616 rr->phase = RP_MODIFY;
617 for (cr = clients_head; NULL != cr; cr = cr->next)
619 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
620 GNUNET_array_append (rr->client_wait_list,
621 rr->client_wait_list_length,
627 rr->phase = RP_RESPONSE_MONITOR;
628 for (cr = clients_head; NULL != cr; cr = cr->next)
630 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
631 GNUNET_array_append (rr->client_wait_list,
632 rr->client_wait_list_length,
637 case RP_RESPONSE_MONITOR:
652 * A client disconnected, clean up after it.
655 * @param client handle of client that disconnected
658 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
660 struct ClientRecord *cr;
661 struct RequestRecord *rr;
665 for (cr = clients_head; NULL != cr; cr = cr->next)
667 if (cr->client == client)
669 GNUNET_SERVER_client_drop (client);
670 GNUNET_CONTAINER_DLL_remove (clients_head,
673 for (i=0;i<UINT16_MAX;i++)
676 if (0 == rr->client_wait_list_length)
677 continue; /* not in use */
678 for (j=0;j<rr->client_wait_list_length;j++)
680 if (rr->client_wait_list[j] == cr)
682 rr->client_wait_list[j] = NULL;
695 * Read a DNS response from the (unhindered) UDP-Socket
697 * @param cls socket to read from
698 * @param tc scheduler context (must be shutdown or read ready)
701 read_response (void *cls,
702 const struct GNUNET_SCHEDULER_TaskContext *tc)
704 struct GNUNET_NETWORK_Handle *dnsout = cls;
705 struct sockaddr_in addr4;
706 struct sockaddr_in6 addr6;
707 struct sockaddr *addr;
708 struct GNUNET_TUN_DnsHeader *dns;
710 struct RequestRecord *rr;
714 if (dnsout == dnsout4)
716 addrlen = sizeof (struct sockaddr_in);
717 addr = (struct sockaddr* ) &addr4;
718 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
725 addrlen = sizeof (struct sockaddr_in6);
726 addr = (struct sockaddr* ) &addr6;
727 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
732 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
736 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
738 /* conservative choice: */
742 /* port the code above? */
747 unsigned char buf[len];
749 memset (addr, 0, addrlen);
750 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
755 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
758 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
761 _("Received DNS response that is too small (%u bytes)"),
765 dns = (struct GNUNET_TUN_DnsHeader *) buf;
766 rr = &requests[dns->id];
767 if (rr->phase != RP_INTERNET_DNS)
769 /* unexpected / bogus reply */
770 GNUNET_STATISTICS_update (stats,
771 gettext_noop ("# External DNS response discarded (no matching request)"),
775 GNUNET_free_non_null (rr->payload);
776 rr->payload = GNUNET_malloc (len);
777 memcpy (rr->payload, buf, len);
778 rr->payload_length = len;
785 * Open source port for sending DNS request on IPv4.
787 * @return GNUNET_OK on success
792 struct sockaddr_in addr;
795 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
797 return GNUNET_SYSERR;
799 memset (&addr, 0, sizeof (struct sockaddr_in));
800 addr.sin_family = AF_INET;
801 int err = GNUNET_NETWORK_socket_bind (dnsout4,
802 (struct sockaddr *) &addr,
803 sizeof (struct sockaddr_in));
805 if (err != GNUNET_OK)
807 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
808 _("Could not bind to any port: %s\n"),
810 GNUNET_NETWORK_socket_close (dnsout4);
812 return GNUNET_SYSERR;
815 /* Read the port we bound to */
816 addrlen = sizeof (struct sockaddr_in);
817 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4),
818 (struct sockaddr *) &addr,
821 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
822 _("Could not determine port I got: %s\n"),
824 GNUNET_NETWORK_socket_close (dnsout4);
826 return GNUNET_SYSERR;
828 dnsoutport = htons (addr.sin_port);
830 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
831 _("GNUnet DNS will exit on source port %u\n"),
832 (unsigned int) dnsoutport);
833 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
835 &read_response, dnsout4);
841 * Open source port for sending DNS request on IPv6. Should be
842 * called AFTER open_port4.
844 * @return GNUNET_OK on success
849 struct sockaddr_in6 addr;
852 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
855 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
856 _("Could not create IPv6 socket: %s\n"),
858 return GNUNET_SYSERR;
860 memset (&addr, 0, sizeof (struct sockaddr_in6));
861 addr.sin6_family = AF_INET6;
862 addr.sin6_port = htons (dnsoutport);
863 int err = GNUNET_NETWORK_socket_bind (dnsout6,
864 (struct sockaddr *) &addr,
865 sizeof (struct sockaddr_in6));
867 if (err != GNUNET_OK)
869 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
870 _("Could not bind to port %u: %s\n"),
871 (unsigned int) dnsoutport,
873 GNUNET_NETWORK_socket_close (dnsout6);
875 return GNUNET_SYSERR;
879 addrlen = sizeof (struct sockaddr_in6);
880 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6),
881 (struct sockaddr *) &addr,
884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
885 _("Could not determine port I got: %s\n"),
887 GNUNET_NETWORK_socket_close (dnsout6);
889 return GNUNET_SYSERR;
892 dnsoutport = htons (addr.sin6_port);
893 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
895 &read_response, dnsout6);
901 * We got a new client. Make sure all new DNS requests pass by its desk.
904 * @param client the new client
905 * @param message the init message (unused)
908 handle_client_init (void *cls GNUNET_UNUSED,
909 struct GNUNET_SERVER_Client *client,
910 const struct GNUNET_MessageHeader *message)
912 struct ClientRecord *cr;
913 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
915 cr = GNUNET_malloc (sizeof (struct ClientRecord));
917 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
918 GNUNET_SERVER_client_keep (client);
919 GNUNET_CONTAINER_DLL_insert (clients_head,
922 GNUNET_SERVER_notification_context_add (nc, client);
923 GNUNET_SERVER_receive_done (client, GNUNET_OK);
928 * We got a response from a client.
931 * @param client the client
932 * @param message the response
935 handle_client_response (void *cls GNUNET_UNUSED,
936 struct GNUNET_SERVER_Client *client,
937 const struct GNUNET_MessageHeader *message)
939 const struct GNUNET_DNS_Response *resp;
940 struct RequestRecord *rr;
945 msize = ntohs (message->size);
946 if (msize < sizeof (struct GNUNET_DNS_Response))
949 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
952 resp = (const struct GNUNET_DNS_Response*) message;
953 off = (uint16_t) resp->request_id;
955 if (rr->request_id != resp->request_id)
957 GNUNET_STATISTICS_update (stats,
958 gettext_noop ("# Client response discarded (no matching request)"),
960 GNUNET_SERVER_receive_done (client, GNUNET_OK);
963 for (i=0;i<rr->client_wait_list_length;i++)
965 if (NULL == rr->client_wait_list[i])
967 if (rr->client_wait_list[i]->client != client)
969 rr->client_wait_list[i] = NULL;
970 switch (ntohl (resp->drop_flag))
975 case 1: /* no change */
978 msize -= sizeof (struct GNUNET_DNS_Response);
979 if ( (sizeof (struct GNUNET_TUN_DnsHeader) > msize) ||
980 (RP_REQUEST_MONITOR == rr->phase) ||
981 (RP_RESPONSE_MONITOR == rr->phase) )
984 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
988 GNUNET_free_non_null (rr->payload);
990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
991 _("Changing DNS reply according to client specifications\n"));
993 rr->payload = GNUNET_malloc (msize);
994 rr->payload_length = msize;
995 memcpy (rr->payload, &resp[1], msize);
996 if (rr->phase == RP_QUERY)
998 /* clear wait list, we're moving to MODIFY phase next */
999 GNUNET_array_grow (rr->client_wait_list,
1000 rr->client_wait_list_length,
1006 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1009 /* odd, client was not on our list for the request, that ought
1012 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1017 * Functions with this signature are called whenever a complete
1018 * message is received by the tokenizer from the DNS hijack process.
1020 * @param cls closure
1021 * @param client identification of the client
1022 * @param message the actual message, a DNS request we should handle
1025 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1026 const struct GNUNET_MessageHeader *message)
1029 const struct GNUNET_TUN_Layer2PacketHeader *tun;
1030 const struct GNUNET_TUN_IPv4Header *ip4;
1031 const struct GNUNET_TUN_IPv6Header *ip6;
1032 const struct GNUNET_TUN_UdpHeader *udp;
1033 const struct GNUNET_TUN_DnsHeader *dns;
1034 struct RequestRecord *rr;
1035 struct sockaddr_in *srca4;
1036 struct sockaddr_in6 *srca6;
1037 struct sockaddr_in *dsta4;
1038 struct sockaddr_in6 *dsta6;
1040 msize = ntohs (message->size);
1041 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct GNUNET_TUN_Layer2PacketHeader) + sizeof (struct GNUNET_TUN_IPv4Header))
1043 /* non-IP packet received on TUN!? */
1047 msize -= sizeof (struct GNUNET_MessageHeader);
1048 tun = (const struct GNUNET_TUN_Layer2PacketHeader *) &message[1];
1049 msize -= sizeof (struct GNUNET_TUN_Layer2PacketHeader);
1050 switch (ntohs (tun->proto))
1053 ip4 = (const struct GNUNET_TUN_IPv4Header *) &tun[1];
1054 if ( (msize < sizeof (struct GNUNET_TUN_IPv4Header)) ||
1055 (ip4->version != 4) ||
1056 (ip4->header_length != sizeof (struct GNUNET_TUN_IPv4Header) / 4) ||
1057 (ntohs(ip4->total_length) != msize) ||
1058 (ip4->protocol != IPPROTO_UDP) )
1060 /* non-IP/UDP packet received on TUN (or with options) */
1061 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1062 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1065 udp = (const struct GNUNET_TUN_UdpHeader*) &ip4[1];
1066 msize -= sizeof (struct GNUNET_TUN_IPv4Header);
1069 ip6 = (const struct GNUNET_TUN_IPv6Header *) &tun[1];
1070 if ( (msize < sizeof (struct GNUNET_TUN_IPv6Header)) ||
1071 (ip6->version != 6) ||
1072 (ntohs (ip6->payload_length) != msize) ||
1073 (ip6->next_header != IPPROTO_UDP) )
1075 /* non-IP/UDP packet received on TUN (or with extensions) */
1076 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1077 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1080 udp = (const struct GNUNET_TUN_UdpHeader*) &ip6[1];
1081 msize -= sizeof (struct GNUNET_TUN_IPv6Header);
1084 /* non-IP packet received on TUN!? */
1085 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1086 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1087 (unsigned int) msize,
1088 ntohs (tun->proto));
1091 if (msize <= sizeof (struct GNUNET_TUN_UdpHeader) + sizeof (struct GNUNET_TUN_DnsHeader))
1093 /* non-DNS packet received on TUN, ignore */
1094 GNUNET_STATISTICS_update (stats,
1095 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1099 msize -= sizeof (struct GNUNET_TUN_UdpHeader);
1100 dns = (const struct GNUNET_TUN_DnsHeader*) &udp[1];
1101 rr = &requests[dns->id];
1103 /* clean up from previous request */
1104 GNUNET_free_non_null (rr->payload);
1106 GNUNET_array_grow (rr->client_wait_list,
1107 rr->client_wait_list_length,
1110 /* setup new request */
1111 rr->phase = RP_INIT;
1112 if (ip4->version == 4)
1114 srca4 = (struct sockaddr_in*) &rr->src_addr;
1115 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1116 memset (srca4, 0, sizeof (struct sockaddr_in));
1117 memset (dsta4, 0, sizeof (struct sockaddr_in));
1118 srca4->sin_family = AF_INET;
1119 dsta4->sin_family = AF_INET;
1120 srca4->sin_addr = ip4->source_address;
1121 dsta4->sin_addr = ip4->destination_address;
1122 srca4->sin_port = udp->spt;
1123 dsta4->sin_port = udp->dpt;
1124 #if HAVE_SOCKADDR_IN_SIN_LEN
1125 srca4->sin_len = sizeof (sizeof (struct sockaddr_in));
1126 dsta4->sin_len = sizeof (sizeof (struct sockaddr_in));
1131 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1132 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1133 memset (srca6, 0, sizeof (struct sockaddr_in6));
1134 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1135 srca6->sin6_family = AF_INET6;
1136 dsta6->sin6_family = AF_INET6;
1137 srca6->sin6_addr = ip6->source_address;
1138 dsta6->sin6_addr = ip6->destination_address;
1139 srca6->sin6_port = udp->spt;
1140 dsta6->sin6_port = udp->dpt;
1141 #if HAVE_SOCKADDR_IN_SIN_LEN
1142 srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1143 dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1146 rr->payload = GNUNET_malloc (msize);
1147 rr->payload_length = msize;
1148 memcpy (rr->payload, dns, msize);
1149 rr->request_id = dns->id | (request_id_gen << 16);
1152 GNUNET_STATISTICS_update (stats,
1153 gettext_noop ("# DNS requests received via TUN interface"),
1155 /* start request processing state machine */
1161 * @param cls closure
1162 * @param server the initialized server
1163 * @param cfg_ configuration to use
1166 run (void *cls, struct GNUNET_SERVER_Handle *server,
1167 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1169 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1170 /* callback, cls, type, size */
1171 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1172 sizeof (struct GNUNET_DNS_Register)},
1173 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1184 stats = GNUNET_STATISTICS_create ("dns", cfg);
1185 nc = GNUNET_SERVER_notification_context_create (server, 1);
1186 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1189 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1191 if ( (GNUNET_OK != open_port4 ()) &&
1192 (GNUNET_OK != open_port6 ()) )
1194 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1195 _("Failed to open any port to provide DNS exit\n"));
1196 GNUNET_SCHEDULER_shutdown ();
1201 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1202 if (GNUNET_SYSERR ==
1203 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1205 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1206 "No entry 'IFNAME' in configuration!\n");
1207 GNUNET_SCHEDULER_shutdown ();
1210 helper_argv[1] = ifc_name;
1211 if ( (GNUNET_SYSERR ==
1212 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1215 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1216 "No entry 'IPV6ADDR' in configuration!\n");
1217 GNUNET_SCHEDULER_shutdown ();
1220 helper_argv[2] = ipv6addr;
1221 if (GNUNET_SYSERR ==
1222 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1225 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1226 "No entry 'IPV6PREFIX' in configuration!\n");
1227 GNUNET_SCHEDULER_shutdown ();
1230 helper_argv[3] = ipv6prefix;
1232 if (GNUNET_SYSERR ==
1233 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1236 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1237 "No entry 'IPV4ADDR' in configuration!\n");
1238 GNUNET_SCHEDULER_shutdown ();
1241 helper_argv[4] = ipv4addr;
1242 if (GNUNET_SYSERR ==
1243 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1247 "No entry 'IPV4MASK' in configuration!\n");
1248 GNUNET_SCHEDULER_shutdown ();
1251 helper_argv[5] = ipv4mask;
1252 GNUNET_snprintf (port_s,
1255 (unsigned int) dnsoutport);
1256 helper_argv[6] = GNUNET_strdup (port_s);
1257 helper_argv[7] = NULL;
1258 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1260 &process_helper_messages,
1262 GNUNET_SERVER_add_handlers (server, handlers);
1263 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1268 * The main function for the dns service.
1270 * @param argc number of arguments from the command line
1271 * @param argv command line arguments
1272 * @return 0 ok, 1 on error
1275 main (int argc, char *const *argv)
1277 return (GNUNET_OK ==
1278 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1279 &run, NULL)) ? 0 : 1;
1283 /* end of gnunet-service-dns_new.c */