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_new.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-new.h"
33 /* see http://www.iana.org/assignments/ethernet-numbers */
35 #define ETH_P_IPV4 0x0800
39 #define ETH_P_IPV6 0x86DD
42 GNUNET_NETWORK_STRUCT_BEGIN
44 * Header from Linux TUN interface.
49 * Some flags (unused).
54 * Here we get an ETH_P_-number.
60 * Standard IPv4 header.
64 unsigned header_length:4 GNUNET_PACKED;
65 unsigned version:4 GNUNET_PACKED;
67 uint16_t total_length GNUNET_PACKED;
68 uint16_t identification GNUNET_PACKED;
69 unsigned flags:3 GNUNET_PACKED;
70 unsigned fragmentation_offset:13 GNUNET_PACKED;
73 uint16_t checksum GNUNET_PACKED;
74 struct in_addr source_address GNUNET_PACKED;
75 struct in_addr destination_address GNUNET_PACKED;
79 * Standard IPv6 header.
83 unsigned traffic_class_h:4 GNUNET_PACKED;
84 unsigned version:4 GNUNET_PACKED;
85 unsigned traffic_class_l:4 GNUNET_PACKED;
86 unsigned flow_label:20 GNUNET_PACKED;
87 uint16_t payload_length GNUNET_PACKED;
90 struct in6_addr source_address GNUNET_PACKED;
91 struct in6_addr destination_address GNUNET_PACKED;
99 uint16_t spt GNUNET_PACKED;
100 uint16_t dpt GNUNET_PACKED;
101 uint16_t len GNUNET_PACKED;
102 uint16_t crc GNUNET_PACKED;
110 uint16_t id GNUNET_PACKED;
111 uint16_t flags GNUNET_PACKED;
112 uint16_t qdcount GNUNET_PACKED;
113 uint16_t ancount GNUNET_PACKED;
114 uint16_t nscount GNUNET_PACKED;
115 uint16_t arcount GNUNET_PACKED;
117 GNUNET_NETWORK_STRUCT_END
121 * Phases each request goes through.
126 * Request has just been received.
131 * Showing the request to all monitor clients. If
132 * client list is empty, will enter QUERY phase.
137 * Showing the request to PRE-RESOLUTION clients to find an answer.
138 * If client list is empty, will trigger global DNS request.
143 * Global Internet query is now pending.
148 * Client (or global DNS request) has resulted in a response.
149 * Forward to all POST-RESOLUTION clients. If client list is empty,
150 * will enter RESPONSE_MONITOR phase.
155 * Showing the request to all monitor clients. If
156 * client list is empty, give the result to the hijacker (and be done).
161 * Some client has told us to drop the request.
168 * Entry we keep for each client.
173 * Kept in doubly-linked list.
175 struct ClientRecord *next;
178 * Kept in doubly-linked list.
180 struct ClientRecord *prev;
183 * Handle to the client.
185 struct GNUNET_SERVER_Client *client;
188 * Flags for the client.
190 enum GNUNET_DNS_Flags flags;
196 * Entry we keep for each active request.
202 * List of clients that still need to see this request (each entry
203 * is set to NULL when the client is done).
205 struct ClientRecord **client_wait_list;
208 * Payload of the UDP packet (the UDP payload), can be either query
209 * or already the response.
214 * Source address of the original request (for sending response).
216 struct sockaddr_storage src_addr;
219 * Destination address of the original request (for potential use as exit).
221 struct sockaddr_storage dst_addr;
224 * ID of this request, also basis for hashing. Lowest 16 bit will
225 * be our message ID when doing a global DNS request and our index
226 * into the 'requests' array.
231 * Number of bytes in payload.
233 size_t payload_length;
236 * Length of the client wait list.
238 unsigned int client_wait_list_length;
241 * In which phase this this request?
243 enum RequestPhase phase;
249 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
250 * sent through gnunet. The port of this socket will not be hijacked.
252 static struct GNUNET_NETWORK_Handle *dnsout4;
255 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
256 * sent through gnunet. The port of this socket will not be hijacked.
258 static struct GNUNET_NETWORK_Handle *dnsout6;
261 * Task for reading from dnsout4.
263 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
266 * Task for reading from dnsout6.
268 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
271 * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind
272 * both sockets to the same port.
274 static uint16_t dnsoutport;
277 * The configuration to use
279 static const struct GNUNET_CONFIGURATION_Handle *cfg;
282 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
284 static struct GNUNET_HELPER_Handle *hijacker;
287 * Command-line arguments we are giving to the hijacker process.
289 static char *helper_argv[8];
292 * Head of DLL of clients we consult.
294 static struct ClientRecord *clients_head;
297 * Tail of DLL of clients we consult.
299 static struct ClientRecord *clients_tail;
302 * Our notification context.
304 static struct GNUNET_SERVER_NotificationContext *nc;
307 * Array of all open requests.
309 static struct RequestRecord requests[UINT16_MAX + 1];
312 * Generator for unique request IDs.
314 static uint64_t request_id_gen;
318 * We're done processing a DNS request, free associated memory.
320 * @param rr request to clean up
323 cleanup_rr (struct RequestRecord *rr)
325 GNUNET_free_non_null (rr->payload);
327 rr->payload_length = 0;
328 GNUNET_array_grow (rr->client_wait_list,
329 rr->client_wait_list_length,
335 * Task run during shutdown.
341 cleanup_task (void *cls GNUNET_UNUSED,
342 const struct GNUNET_SCHEDULER_TaskContext *tc)
346 GNUNET_HELPER_stop (hijacker);
349 GNUNET_free_non_null (helper_argv[i]);
352 GNUNET_NETWORK_socket_close (dnsout4);
355 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
357 GNUNET_SCHEDULER_cancel (read4_task);
358 read4_task = GNUNET_SCHEDULER_NO_TASK;
362 GNUNET_NETWORK_socket_close (dnsout6);
365 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
367 GNUNET_SCHEDULER_cancel (read6_task);
368 read6_task = GNUNET_SCHEDULER_NO_TASK;
370 for (i=0;i<65536;i++)
371 cleanup_rr (&requests[i]);
372 GNUNET_SERVER_notification_context_destroy (nc);
378 * We're done with some request, finish processing.
380 * @param rr request send to the network or just clean up.
383 request_done (struct RequestRecord *rr)
385 struct GNUNET_MessageHeader *hdr;
390 GNUNET_array_grow (rr->client_wait_list,
391 rr->client_wait_list_length,
393 if (RP_RESPONSE_MONITOR != rr->phase)
395 /* no response, drop */
400 /* send response via hijacker */
401 reply_len = sizeof (struct GNUNET_MessageHeader);
402 reply_len += sizeof (struct tun_header);
403 switch (rr->src_addr.ss_family)
406 reply_len += sizeof (struct ip4_header);
409 reply_len += sizeof (struct ip6_header);
416 reply_len += sizeof (struct udp_packet);
417 reply_len += rr->payload_length;
418 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
420 /* response too big, drop */
421 GNUNET_break (0); /* how can this be? */
428 uint32_t udp_crc_sum;
430 /* first, GNUnet message header */
431 hdr = (struct GNUNET_MessageHeader*) buf;
432 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
433 hdr->size = htons ((uint16_t) reply_len);
434 off = sizeof (struct GNUNET_MessageHeader);
436 /* first, TUN header */
438 struct tun_header tun;
440 tun.flags = htons (0);
441 if (rr->src_addr.ss_family == AF_INET)
442 tun.proto = htons (ETH_P_IPV4);
444 tun.proto = htons (ETH_P_IPV6);
445 memcpy (&buf[off], &tun, sizeof (struct tun_header));
446 off += sizeof (struct tun_header);
451 switch (rr->src_addr.ss_family)
455 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
456 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
457 struct ip4_header ip;
461 ip.header_length = sizeof (struct ip4_header) / 4;
462 ip.version = IPVERSION; /* aka 4 */
464 ip.total_length = htons ((uint16_t) reply_len - off);
465 ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
468 ip.fragmentation_offset = 0;
469 ip.ttl = 255; /* or lower? */
470 ip.protocol = IPPROTO_UDP;
471 ip.checksum = 0; /* checksum is optional */
472 ip.source_address = dst->sin_addr;
473 ip.destination_address = src->sin_addr;
474 ip.checksum = GNUNET_CRYPTO_crc16_n ((uint16_t*) &ip, sizeof (ip));
476 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
477 (uint16_t *) &ip.source_address,
478 sizeof (struct in_addr) * 2);
482 tmp = htons (IPPROTO_UDP);
483 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
486 tmp = htons (rr->payload_length + sizeof (struct udp_packet));
487 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
491 memcpy (&buf[off], &ip, sizeof (ip));
497 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
498 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
499 struct ip6_header ip;
501 spt = dst->sin6_port;
502 dpt = src->sin6_port;
503 ip.traffic_class_h = 0;
504 ip.version = 6; /* is there a named constant? I couldn't find one */
505 ip.traffic_class_l = 0;
507 ip.payload_length = htons ((uint16_t) reply_len);
508 ip.next_header = IPPROTO_UDP;
509 ip.hop_limit = 255; /* or lower? */
510 ip.source_address = dst->sin6_addr;
511 ip.destination_address = src->sin6_addr;
512 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
513 (uint16_t *) &ip.source_address,
514 sizeof (struct in6_addr) * 2);
518 tmp = htons (rr->payload_length + sizeof (struct udp_packet));
519 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
522 tmp = htons (IPPROTO_UDP);
523 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
527 memcpy (&buf[off], &ip, sizeof (ip));
537 struct udp_packet udp;
541 udp.len = htons (reply_len - off);
543 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
546 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
547 (uint16_t *) rr->payload,
549 udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum);
550 memcpy (&buf[off], &udp, sizeof (udp));
553 /* now DNS payload */
555 memcpy (&buf[off], rr->payload, rr->payload_length);
556 off += rr->payload_length;
558 /* final checks & sending */
559 GNUNET_assert (off == reply_len);
560 GNUNET_HELPER_send (hijacker,
565 /* clean up, we're done */
571 * Show the payload of the given request record to the client
572 * (and wait for a response).
574 * @param rr request to send to client
575 * @param client client to send the response to
578 send_request_to_client (struct RequestRecord *rr,
579 struct GNUNET_SERVER_Client *client)
581 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
582 struct GNUNET_DNS_Request *req;
584 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
590 req = (struct GNUNET_DNS_Request*) buf;
591 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
592 req->header.size = htons (sizeof (buf));
593 req->reserved = htonl (0);
594 req->request_id = rr->request_id;
595 memcpy (&req[1], rr->payload, rr->payload_length);
596 GNUNET_SERVER_notification_context_unicast (nc,
604 * A client has completed its processing for this
607 * @param rr request to process further
610 next_phase (struct RequestRecord *rr)
612 struct ClientRecord *cr;
615 struct GNUNET_NETWORK_Handle *dnsout;
618 if (rr->phase == RP_DROP)
624 for (j=0;j<rr->client_wait_list_length;j++)
626 if (NULL != rr->client_wait_list[j])
634 send_request_to_client (rr, rr->client_wait_list[nz]->client);
637 /* done with current phase, advance! */
641 rr->phase = RP_REQUEST_MONITOR;
642 for (cr = clients_head; NULL != cr; cr = cr->next)
644 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
645 GNUNET_array_append (rr->client_wait_list,
646 rr->client_wait_list_length,
651 case RP_REQUEST_MONITOR:
652 rr->phase = RP_QUERY;
653 for (cr = clients_head; NULL != cr; cr = cr->next)
655 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
656 GNUNET_array_append (rr->client_wait_list,
657 rr->client_wait_list_length,
663 rr->phase = RP_INTERNET_DNS;
664 switch (rr->dst_addr.ss_family)
668 salen = sizeof (struct ip4_header);
672 salen = sizeof (struct ip6_header);
681 /* fail, FIXME: case for statistics! */
685 GNUNET_NETWORK_socket_sendto (dnsout,
688 (struct sockaddr*) &rr->dst_addr,
691 case RP_INTERNET_DNS:
692 rr->phase = RP_MODIFY;
693 for (cr = clients_head; NULL != cr; cr = cr->next)
695 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
696 GNUNET_array_append (rr->client_wait_list,
697 rr->client_wait_list_length,
703 rr->phase = RP_RESPONSE_MONITOR;
704 for (cr = clients_head; NULL != cr; cr = cr->next)
706 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
707 GNUNET_array_append (rr->client_wait_list,
708 rr->client_wait_list_length,
713 case RP_RESPONSE_MONITOR:
728 * A client disconnected, clean up after it.
731 * @param client handle of client that disconnected
734 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
736 struct ClientRecord *cr;
737 struct RequestRecord *rr;
741 for (cr = clients_head; NULL != cr; cr = cr->next)
743 if (cr->client == client)
745 GNUNET_SERVER_client_drop (client);
746 GNUNET_CONTAINER_DLL_remove (clients_head,
749 for (i=0;i<UINT16_MAX;i++)
752 if (0 == rr->client_wait_list_length)
753 continue; /* not in use */
754 for (j=0;j<rr->client_wait_list_length;j++)
756 if (rr->client_wait_list[j] == cr)
758 rr->client_wait_list[j] = NULL;
771 * Read a DNS response from the (unhindered) UDP-Socket
773 * @param cls socket to read from
774 * @param tc scheduler context (must be shutdown or read ready)
777 read_response (void *cls,
778 const struct GNUNET_SCHEDULER_TaskContext *tc)
780 struct GNUNET_NETWORK_Handle *dnsout = cls;
781 struct sockaddr_in addr4;
782 struct sockaddr_in6 addr6;
783 struct sockaddr *addr;
784 struct dns_header *dns;
786 struct RequestRecord *rr;
790 if (dnsout == dnsout4)
792 addrlen = sizeof (struct sockaddr_in);
793 addr = (struct sockaddr* ) &addr4;
794 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
801 addrlen = sizeof (struct sockaddr_in6);
802 addr = (struct sockaddr* ) &addr6;
803 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
808 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
812 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
814 /* conservative choice: */
818 /* port the code above? */
823 unsigned char buf[len];
825 memset (addr, 0, addrlen);
826 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
831 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
834 if (sizeof (struct dns_header) > r)
836 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
837 _("Received DNS response that is too small (%u bytes)"),
841 dns = (struct dns_header *) buf;
842 rr = &requests[dns->id];
843 if (rr->phase != RP_INTERNET_DNS)
845 /* FIXME: case for statistics */
846 /* unexpected / bogus reply */
849 GNUNET_free_non_null (rr->payload);
850 rr->payload = GNUNET_malloc (len);
851 memcpy (rr->payload, buf, len);
852 rr->payload_length = len;
859 * Open source port for sending DNS request on IPv4.
861 * @return GNUNET_OK on success
866 struct sockaddr_in addr;
869 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
871 return GNUNET_SYSERR;
873 memset (&addr, 0, sizeof (struct sockaddr_in));
874 addr.sin_family = AF_INET;
875 int err = GNUNET_NETWORK_socket_bind (dnsout4,
876 (struct sockaddr *) &addr,
877 sizeof (struct sockaddr_in));
879 if (err != GNUNET_OK)
881 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
882 _("Could not bind to any port: %s\n"),
884 GNUNET_NETWORK_socket_close (dnsout4);
886 return GNUNET_SYSERR;
889 /* Read the port we bound to */
890 addrlen = sizeof (struct sockaddr_in);
891 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4),
892 (struct sockaddr *) &addr,
895 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
896 _("Could not determine port I got: %s\n"),
898 GNUNET_NETWORK_socket_close (dnsout4);
900 return GNUNET_SYSERR;
902 dnsoutport = htons (addr.sin_port);
904 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
905 _("GNUnet DNS will exit on source port %u\n"),
906 (unsigned int) dnsoutport);
907 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
909 &read_response, dnsout4);
915 * Open source port for sending DNS request on IPv6. Should be
916 * called AFTER open_port4.
918 * @return GNUNET_OK on success
923 struct sockaddr_in6 addr;
926 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
929 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
930 _("Could not create IPv6 socket: %s\n"),
932 return GNUNET_SYSERR;
934 memset (&addr, 0, sizeof (struct sockaddr_in6));
935 addr.sin6_family = AF_INET6;
936 addr.sin6_port = htons (dnsoutport);
937 int err = GNUNET_NETWORK_socket_bind (dnsout6,
938 (struct sockaddr *) &addr,
939 sizeof (struct sockaddr_in6));
941 if (err != GNUNET_OK)
943 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
944 _("Could not bind to port %u: %s\n"),
945 (unsigned int) dnsoutport,
947 GNUNET_NETWORK_socket_close (dnsout6);
949 return GNUNET_SYSERR;
953 addrlen = sizeof (struct sockaddr_in6);
954 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6),
955 (struct sockaddr *) &addr,
958 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
959 _("Could not determine port I got: %s\n"),
961 GNUNET_NETWORK_socket_close (dnsout6);
963 return GNUNET_SYSERR;
966 dnsoutport = htons (addr.sin6_port);
967 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
969 &read_response, dnsout6);
975 * We got a new client. Make sure all new DNS requests pass by its desk.
978 * @param client the new client
979 * @param message the init message (unused)
982 handle_client_init (void *cls GNUNET_UNUSED,
983 struct GNUNET_SERVER_Client *client,
984 const struct GNUNET_MessageHeader *message)
986 struct ClientRecord *cr;
987 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
989 cr = GNUNET_malloc (sizeof (struct ClientRecord));
991 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
992 GNUNET_SERVER_client_keep (client);
993 GNUNET_CONTAINER_DLL_insert (clients_head,
996 GNUNET_SERVER_notification_context_add (nc, client);
997 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1002 * We got a response from a client.
1005 * @param client the client
1006 * @param message the response
1009 handle_client_response (void *cls GNUNET_UNUSED,
1010 struct GNUNET_SERVER_Client *client,
1011 const struct GNUNET_MessageHeader *message)
1013 const struct GNUNET_DNS_Response *resp;
1014 struct RequestRecord *rr;
1019 msize = ntohs (message->size);
1020 if (msize < sizeof (struct GNUNET_DNS_Response))
1023 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1026 resp = (const struct GNUNET_DNS_Response*) message;
1027 off = (uint16_t) resp->request_id;
1028 rr = &requests[off];
1029 if (rr->request_id != resp->request_id)
1031 // FIXME: this is a case for calling statistics...
1032 // (client is answering a request that we've lost
1033 // track of -- more than 64k requests ago or so...)
1034 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1037 for (i=0;i<rr->client_wait_list_length;i++)
1039 if (NULL == rr->client_wait_list[i])
1041 if (rr->client_wait_list[i]->client != client)
1043 rr->client_wait_list[i] = NULL;
1044 switch (ntohl (resp->drop_flag))
1047 rr->phase = RP_DROP;
1049 case 1: /* no change */
1051 case 2: /* update */
1052 msize -= sizeof (struct GNUNET_DNS_Response);
1053 if ( (sizeof (struct dns_header) > msize) ||
1054 (RP_REQUEST_MONITOR == rr->phase) ||
1055 (RP_RESPONSE_MONITOR == rr->phase) )
1058 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1062 GNUNET_free_non_null (rr->payload);
1063 rr->payload = GNUNET_malloc (msize);
1064 memcpy (rr->payload, &resp[1], msize);
1065 if (rr->phase == RP_QUERY)
1067 /* clear wait list, we're moving to MODIFY phase next */
1068 GNUNET_array_grow (rr->client_wait_list,
1069 rr->client_wait_list_length,
1075 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1078 /* odd, client was not on our list for the request, that ought
1081 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1086 * Functions with this signature are called whenever a complete
1087 * message is received by the tokenizer from the DNS hijack process.
1089 * @param cls closure
1090 * @param client identification of the client
1091 * @param message the actual message, a DNS request we should handle
1094 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1095 const struct GNUNET_MessageHeader *message)
1098 const struct tun_header *tun;
1099 const struct ip4_header *ip4;
1100 const struct ip6_header *ip6;
1101 const struct udp_packet *udp;
1102 const struct dns_header *dns;
1103 struct RequestRecord *rr;
1104 struct sockaddr_in *srca4;
1105 struct sockaddr_in6 *srca6;
1106 struct sockaddr_in *dsta4;
1107 struct sockaddr_in6 *dsta6;
1109 msize = ntohs (message->size);
1110 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header))
1112 /* non-IP packet received on TUN!? */
1116 msize -= sizeof (struct GNUNET_MessageHeader);
1117 tun = (const struct tun_header *) &message[1];
1118 msize -= sizeof (struct tun_header);
1119 switch (ntohs (tun->proto))
1122 ip4 = (const struct ip4_header *) &tun[1];
1123 if ( (msize < sizeof (struct ip4_header)) ||
1124 (ip4->version != IPVERSION) ||
1125 (ip4->header_length != sizeof (struct ip4_header) / 4) ||
1126 (ntohs(ip4->total_length) != msize) ||
1127 (ip4->protocol != IPPROTO_UDP) )
1129 /* non-IP/UDP packet received on TUN (or with options) */
1130 // FIXME: maybe just log with stats?
1134 udp = (const struct udp_packet*) &ip4[1];
1135 msize -= sizeof (struct ip4_header);
1138 ip6 = (const struct ip6_header *) &tun[1];
1139 if ( (msize < sizeof (struct ip6_header)) ||
1140 (ip6->version != 6) ||
1141 (ntohs (ip6->payload_length) != msize) ||
1142 (ip6->next_header != IPPROTO_UDP) )
1144 /* non-IP/UDP packet received on TUN (or with extensions) */
1145 // FIXME: maybe just log with stats?
1149 udp = (const struct udp_packet*) &ip6[1];
1150 msize -= sizeof (struct ip6_header);
1153 /* non-IP packet received on TUN!? */
1154 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1155 _("Got packet with %u bytes and protocol %u from TUN\n"),
1156 (unsigned int) msize,
1157 ntohs (tun->proto));
1161 if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header))
1163 /* non-DNS packet received on TUN, ignore */
1164 /* FIXME: case for statistics... */
1167 msize -= sizeof (struct udp_packet);
1168 dns = (const struct dns_header*) &udp[1];
1169 rr = &requests[dns->id];
1171 /* clean up from previous request */
1172 GNUNET_free_non_null (rr->payload);
1174 GNUNET_array_grow (rr->client_wait_list,
1175 rr->client_wait_list_length,
1178 /* setup new request */
1179 rr->phase = RP_INIT;
1180 if (ip4->version == IPVERSION)
1182 srca4 = (struct sockaddr_in*) &rr->src_addr;
1183 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1184 memset (srca4, 0, sizeof (struct sockaddr_in));
1185 memset (dsta4, 0, sizeof (struct sockaddr_in));
1186 srca4->sin_family = AF_INET;
1187 dsta4->sin_family = AF_INET;
1188 srca4->sin_addr = ip4->source_address;
1189 dsta4->sin_addr = ip4->destination_address;
1190 srca4->sin_port = udp->spt;
1191 dsta4->sin_port = udp->dpt;
1192 /* FIXME: bother with FreeBSD sin_len crap? */
1196 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1197 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1198 memset (srca6, 0, sizeof (struct sockaddr_in6));
1199 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1200 srca6->sin6_family = AF_INET6;
1201 dsta6->sin6_family = AF_INET6;
1202 srca6->sin6_addr = ip6->source_address;
1203 dsta6->sin6_addr = ip6->destination_address;
1204 srca6->sin6_port = udp->spt;
1205 dsta6->sin6_port = udp->dpt;
1206 /* FIXME: bother with FreeBSD sin_len crap? */
1208 rr->payload = GNUNET_malloc (msize);
1209 rr->payload_length = msize;
1210 memcpy (rr->payload, dns, msize);
1211 rr->request_id = dns->id | (request_id_gen << 16);
1214 /* FIXME: case for statistics... */
1215 /* start request processing state machine */
1221 * @param cls closure
1222 * @param server the initialized server
1223 * @param cfg_ configuration to use
1226 run (void *cls, struct GNUNET_SERVER_Handle *server,
1227 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1229 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1230 /* callback, cls, type, size */
1231 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1232 sizeof (struct GNUNET_DNS_Register)},
1233 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1244 nc = GNUNET_SERVER_notification_context_create (server, 1);
1245 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1248 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1250 if ( (GNUNET_OK != open_port4 ()) &&
1251 (GNUNET_OK != open_port6 ()) )
1253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1254 _("Failed to open any port to provide DNS exit\n"));
1255 GNUNET_SCHEDULER_shutdown ();
1260 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1261 if (GNUNET_SYSERR ==
1262 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1264 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1265 "No entry 'IFNAME' in configuration!\n");
1266 GNUNET_SCHEDULER_shutdown ();
1269 helper_argv[1] = ifc_name;
1270 if ( (GNUNET_SYSERR ==
1271 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1274 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1275 "No entry 'IPV6ADDR' in configuration!\n");
1276 GNUNET_SCHEDULER_shutdown ();
1279 helper_argv[2] = ipv6addr;
1280 if (GNUNET_SYSERR ==
1281 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1284 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1285 "No entry 'IPV6PREFIX' in configuration!\n");
1286 GNUNET_SCHEDULER_shutdown ();
1289 helper_argv[3] = ipv6prefix;
1291 if (GNUNET_SYSERR ==
1292 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1295 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1296 "No entry 'IPV4ADDR' in configuration!\n");
1297 GNUNET_SCHEDULER_shutdown ();
1300 helper_argv[4] = ipv4addr;
1301 if (GNUNET_SYSERR ==
1302 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1305 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1306 "No entry 'IPV4MASK' in configuration!\n");
1307 GNUNET_SCHEDULER_shutdown ();
1310 helper_argv[5] = ipv4mask;
1311 GNUNET_snprintf (port_s,
1314 (unsigned int) dnsoutport);
1315 helper_argv[6] = GNUNET_strdup (port_s);
1316 helper_argv[7] = NULL;
1317 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1319 &process_helper_messages,
1321 GNUNET_SERVER_add_handlers (server, handlers);
1322 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1327 * The main function for the dns service.
1329 * @param argc number of arguments from the command line
1330 * @param argv command line arguments
1331 * @return 0 ok, 1 on error
1334 main (int argc, char *const *argv)
1336 return (GNUNET_OK ==
1337 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1338 &run, NULL)) ? 0 : 1;
1342 /* end of gnunet-service-dns_new.c */