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 "tcpip_tun.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 * The IPv4 UDP-Socket through which DNS-Resolves will be sent if they are not to be
169 * sent through gnunet. The port of this socket will not be hijacked.
171 static struct GNUNET_NETWORK_Handle *dnsout4;
174 * The IPv6 UDP-Socket through which DNS-Resolves will be sent if they are not to be
175 * sent through gnunet. The port of this socket will not be hijacked.
177 static struct GNUNET_NETWORK_Handle *dnsout6;
180 * Task for reading from dnsout4.
182 static GNUNET_SCHEDULER_TaskIdentifier read4_task;
185 * Task for reading from dnsout6.
187 static GNUNET_SCHEDULER_TaskIdentifier read6_task;
190 * The port bound to the socket dnsout (and/or dnsout6). We always (try) to bind
191 * both sockets to the same port.
193 static uint16_t dnsoutport;
196 * The configuration to use
198 static const struct GNUNET_CONFIGURATION_Handle *cfg;
203 static struct GNUNET_STATISTICS_Handle *stats;
206 * Handle to DNS hijacker helper process ("gnunet-helper-dns").
208 static struct GNUNET_HELPER_Handle *hijacker;
211 * Command-line arguments we are giving to the hijacker process.
213 static char *helper_argv[8];
216 * Head of DLL of clients we consult.
218 static struct ClientRecord *clients_head;
221 * Tail of DLL of clients we consult.
223 static struct ClientRecord *clients_tail;
226 * Our notification context.
228 static struct GNUNET_SERVER_NotificationContext *nc;
231 * Array of all open requests.
233 static struct RequestRecord requests[UINT16_MAX + 1];
236 * Generator for unique request IDs.
238 static uint64_t request_id_gen;
242 * We're done processing a DNS request, free associated memory.
244 * @param rr request to clean up
247 cleanup_rr (struct RequestRecord *rr)
249 GNUNET_free_non_null (rr->payload);
251 rr->payload_length = 0;
252 GNUNET_array_grow (rr->client_wait_list,
253 rr->client_wait_list_length,
259 * Task run during shutdown.
265 cleanup_task (void *cls GNUNET_UNUSED,
266 const struct GNUNET_SCHEDULER_TaskContext *tc)
270 GNUNET_HELPER_stop (hijacker);
273 GNUNET_free_non_null (helper_argv[i]);
276 GNUNET_NETWORK_socket_close (dnsout4);
279 if (GNUNET_SCHEDULER_NO_TASK != read4_task)
281 GNUNET_SCHEDULER_cancel (read4_task);
282 read4_task = GNUNET_SCHEDULER_NO_TASK;
286 GNUNET_NETWORK_socket_close (dnsout6);
289 if (GNUNET_SCHEDULER_NO_TASK != read6_task)
291 GNUNET_SCHEDULER_cancel (read6_task);
292 read6_task = GNUNET_SCHEDULER_NO_TASK;
294 for (i=0;i<65536;i++)
295 cleanup_rr (&requests[i]);
296 GNUNET_SERVER_notification_context_destroy (nc);
300 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
307 * We're done with some request, finish processing.
309 * @param rr request send to the network or just clean up.
312 request_done (struct RequestRecord *rr)
314 struct GNUNET_MessageHeader *hdr;
319 GNUNET_array_grow (rr->client_wait_list,
320 rr->client_wait_list_length,
322 if (RP_RESPONSE_MONITOR != rr->phase)
324 /* no response, drop */
329 /* send response via hijacker */
330 reply_len = sizeof (struct GNUNET_MessageHeader);
331 reply_len += sizeof (struct tun_header);
332 switch (rr->src_addr.ss_family)
335 reply_len += sizeof (struct ip4_header);
338 reply_len += sizeof (struct ip6_header);
345 reply_len += sizeof (struct udp_packet);
346 reply_len += rr->payload_length;
347 if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
349 /* response too big, drop */
350 GNUNET_break (0); /* how can this be? */
357 uint32_t udp_crc_sum;
359 /* first, GNUnet message header */
360 hdr = (struct GNUNET_MessageHeader*) buf;
361 hdr->type = htons (GNUNET_MESSAGE_TYPE_DNS_HELPER);
362 hdr->size = htons ((uint16_t) reply_len);
363 off = sizeof (struct GNUNET_MessageHeader);
365 /* first, TUN header */
367 struct tun_header tun;
369 tun.flags = htons (0);
370 if (rr->src_addr.ss_family == AF_INET)
371 tun.proto = htons (ETH_P_IPV4);
373 tun.proto = htons (ETH_P_IPV6);
374 memcpy (&buf[off], &tun, sizeof (struct tun_header));
375 off += sizeof (struct tun_header);
380 switch (rr->src_addr.ss_family)
384 struct sockaddr_in *src = (struct sockaddr_in *) &rr->src_addr;
385 struct sockaddr_in *dst = (struct sockaddr_in *) &rr->dst_addr;
386 struct ip4_header ip;
390 ip.header_length = sizeof (struct ip4_header) / 4;
391 ip.version = IPVERSION; /* aka 4 */
393 ip.total_length = htons ((uint16_t) reply_len - off);
394 ip.identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
397 ip.fragmentation_offset = 0;
398 ip.ttl = 255; /* or lower? */
399 ip.protocol = IPPROTO_UDP;
400 ip.checksum = 0; /* checksum is optional */
401 ip.source_address = dst->sin_addr;
402 ip.destination_address = src->sin_addr;
403 ip.checksum = GNUNET_CRYPTO_crc16_n (&ip, sizeof (ip));
405 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
407 sizeof (struct in_addr) * 2);
411 tmp = htons (IPPROTO_UDP);
412 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
415 tmp = htons (rr->payload_length + sizeof (struct udp_packet));
416 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
420 memcpy (&buf[off], &ip, sizeof (ip));
426 struct sockaddr_in6 *src = (struct sockaddr_in6 *) &rr->src_addr;
427 struct sockaddr_in6 *dst = (struct sockaddr_in6 *) &rr->dst_addr;
428 struct ip6_header ip;
430 spt = dst->sin6_port;
431 dpt = src->sin6_port;
432 ip.traffic_class_h = 0;
433 ip.version = 6; /* is there a named constant? I couldn't find one */
434 ip.traffic_class_l = 0;
436 ip.payload_length = htons ((uint16_t) reply_len);
437 ip.next_header = IPPROTO_UDP;
438 ip.hop_limit = 255; /* or lower? */
439 ip.source_address = dst->sin6_addr;
440 ip.destination_address = src->sin6_addr;
441 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
443 sizeof (struct in6_addr) * 2);
447 tmp = htons (rr->payload_length + sizeof (struct udp_packet));
448 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
451 tmp = htons (IPPROTO_UDP);
452 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
456 memcpy (&buf[off], &ip, sizeof (ip));
466 struct udp_packet udp;
470 udp.len = htons (reply_len - off);
472 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
475 udp_crc_sum = GNUNET_CRYPTO_crc16_step (udp_crc_sum,
478 udp.crc = GNUNET_CRYPTO_crc16_finish (udp_crc_sum);
479 memcpy (&buf[off], &udp, sizeof (udp));
482 /* now DNS payload */
484 memcpy (&buf[off], rr->payload, rr->payload_length);
485 off += rr->payload_length;
487 /* final checks & sending */
488 GNUNET_assert (off == reply_len);
489 GNUNET_HELPER_send (hijacker,
493 GNUNET_STATISTICS_update (stats,
494 gettext_noop ("# DNS requests answered via TUN interface"),
497 /* clean up, we're done */
503 * Show the payload of the given request record to the client
504 * (and wait for a response).
506 * @param rr request to send to client
507 * @param client client to send the response to
510 send_request_to_client (struct RequestRecord *rr,
511 struct GNUNET_SERVER_Client *client)
513 char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length];
514 struct GNUNET_DNS_Request *req;
516 if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
522 req = (struct GNUNET_DNS_Request*) buf;
523 req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST);
524 req->header.size = htons (sizeof (buf));
525 req->reserved = htonl (0);
526 req->request_id = rr->request_id;
527 memcpy (&req[1], rr->payload, rr->payload_length);
528 GNUNET_SERVER_notification_context_unicast (nc,
536 * A client has completed its processing for this
539 * @param rr request to process further
542 next_phase (struct RequestRecord *rr)
544 struct ClientRecord *cr;
547 struct GNUNET_NETWORK_Handle *dnsout;
550 if (rr->phase == RP_DROP)
556 for (j=0;j<rr->client_wait_list_length;j++)
558 if (NULL != rr->client_wait_list[j])
566 send_request_to_client (rr, rr->client_wait_list[nz]->client);
569 /* done with current phase, advance! */
573 rr->phase = RP_REQUEST_MONITOR;
574 for (cr = clients_head; NULL != cr; cr = cr->next)
576 if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR))
577 GNUNET_array_append (rr->client_wait_list,
578 rr->client_wait_list_length,
583 case RP_REQUEST_MONITOR:
584 rr->phase = RP_QUERY;
585 for (cr = clients_head; NULL != cr; cr = cr->next)
587 if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION))
588 GNUNET_array_append (rr->client_wait_list,
589 rr->client_wait_list_length,
595 rr->phase = RP_INTERNET_DNS;
596 switch (rr->dst_addr.ss_family)
600 salen = sizeof (struct ip4_header);
604 salen = sizeof (struct ip6_header);
613 GNUNET_STATISTICS_update (stats,
614 gettext_noop ("# DNS exit failed (address family not supported)"),
619 GNUNET_NETWORK_socket_sendto (dnsout,
622 (struct sockaddr*) &rr->dst_addr,
625 case RP_INTERNET_DNS:
626 rr->phase = RP_MODIFY;
627 for (cr = clients_head; NULL != cr; cr = cr->next)
629 if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION))
630 GNUNET_array_append (rr->client_wait_list,
631 rr->client_wait_list_length,
637 rr->phase = RP_RESPONSE_MONITOR;
638 for (cr = clients_head; NULL != cr; cr = cr->next)
640 if (0 != (cr->flags & GNUNET_DNS_FLAG_RESPONSE_MONITOR))
641 GNUNET_array_append (rr->client_wait_list,
642 rr->client_wait_list_length,
647 case RP_RESPONSE_MONITOR:
662 * A client disconnected, clean up after it.
665 * @param client handle of client that disconnected
668 client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
670 struct ClientRecord *cr;
671 struct RequestRecord *rr;
675 for (cr = clients_head; NULL != cr; cr = cr->next)
677 if (cr->client == client)
679 GNUNET_SERVER_client_drop (client);
680 GNUNET_CONTAINER_DLL_remove (clients_head,
683 for (i=0;i<UINT16_MAX;i++)
686 if (0 == rr->client_wait_list_length)
687 continue; /* not in use */
688 for (j=0;j<rr->client_wait_list_length;j++)
690 if (rr->client_wait_list[j] == cr)
692 rr->client_wait_list[j] = NULL;
705 * Read a DNS response from the (unhindered) UDP-Socket
707 * @param cls socket to read from
708 * @param tc scheduler context (must be shutdown or read ready)
711 read_response (void *cls,
712 const struct GNUNET_SCHEDULER_TaskContext *tc)
714 struct GNUNET_NETWORK_Handle *dnsout = cls;
715 struct sockaddr_in addr4;
716 struct sockaddr_in6 addr6;
717 struct sockaddr *addr;
718 struct dns_header *dns;
720 struct RequestRecord *rr;
724 if (dnsout == dnsout4)
726 addrlen = sizeof (struct sockaddr_in);
727 addr = (struct sockaddr* ) &addr4;
728 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
735 addrlen = sizeof (struct sockaddr_in6);
736 addr = (struct sockaddr* ) &addr6;
737 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
742 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
746 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
748 /* conservative choice: */
752 /* port the code above? */
757 unsigned char buf[len];
759 memset (addr, 0, addrlen);
760 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
765 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
768 if (sizeof (struct dns_header) > r)
770 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
771 _("Received DNS response that is too small (%u bytes)"),
775 dns = (struct dns_header *) buf;
776 rr = &requests[dns->id];
777 if (rr->phase != RP_INTERNET_DNS)
779 /* unexpected / bogus reply */
780 GNUNET_STATISTICS_update (stats,
781 gettext_noop ("# External DNS response discarded (no matching request)"),
785 GNUNET_free_non_null (rr->payload);
786 rr->payload = GNUNET_malloc (len);
787 memcpy (rr->payload, buf, len);
788 rr->payload_length = len;
795 * Open source port for sending DNS request on IPv4.
797 * @return GNUNET_OK on success
802 struct sockaddr_in addr;
805 dnsout4 = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
807 return GNUNET_SYSERR;
809 memset (&addr, 0, sizeof (struct sockaddr_in));
810 addr.sin_family = AF_INET;
811 int err = GNUNET_NETWORK_socket_bind (dnsout4,
812 (struct sockaddr *) &addr,
813 sizeof (struct sockaddr_in));
815 if (err != GNUNET_OK)
817 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
818 _("Could not bind to any port: %s\n"),
820 GNUNET_NETWORK_socket_close (dnsout4);
822 return GNUNET_SYSERR;
825 /* Read the port we bound to */
826 addrlen = sizeof (struct sockaddr_in);
827 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout4),
828 (struct sockaddr *) &addr,
831 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
832 _("Could not determine port I got: %s\n"),
834 GNUNET_NETWORK_socket_close (dnsout4);
836 return GNUNET_SYSERR;
838 dnsoutport = htons (addr.sin_port);
840 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
841 _("GNUnet DNS will exit on source port %u\n"),
842 (unsigned int) dnsoutport);
843 read4_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
845 &read_response, dnsout4);
851 * Open source port for sending DNS request on IPv6. Should be
852 * called AFTER open_port4.
854 * @return GNUNET_OK on success
859 struct sockaddr_in6 addr;
862 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
865 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
866 _("Could not create IPv6 socket: %s\n"),
868 return GNUNET_SYSERR;
870 memset (&addr, 0, sizeof (struct sockaddr_in6));
871 addr.sin6_family = AF_INET6;
872 addr.sin6_port = htons (dnsoutport);
873 int err = GNUNET_NETWORK_socket_bind (dnsout6,
874 (struct sockaddr *) &addr,
875 sizeof (struct sockaddr_in6));
877 if (err != GNUNET_OK)
879 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
880 _("Could not bind to port %u: %s\n"),
881 (unsigned int) dnsoutport,
883 GNUNET_NETWORK_socket_close (dnsout6);
885 return GNUNET_SYSERR;
889 addrlen = sizeof (struct sockaddr_in6);
890 if (0 != getsockname (GNUNET_NETWORK_get_fd (dnsout6),
891 (struct sockaddr *) &addr,
894 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
895 _("Could not determine port I got: %s\n"),
897 GNUNET_NETWORK_socket_close (dnsout6);
899 return GNUNET_SYSERR;
902 dnsoutport = htons (addr.sin6_port);
903 read6_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
905 &read_response, dnsout6);
911 * We got a new client. Make sure all new DNS requests pass by its desk.
914 * @param client the new client
915 * @param message the init message (unused)
918 handle_client_init (void *cls GNUNET_UNUSED,
919 struct GNUNET_SERVER_Client *client,
920 const struct GNUNET_MessageHeader *message)
922 struct ClientRecord *cr;
923 const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message;
925 cr = GNUNET_malloc (sizeof (struct ClientRecord));
927 cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags);
928 GNUNET_SERVER_client_keep (client);
929 GNUNET_CONTAINER_DLL_insert (clients_head,
932 GNUNET_SERVER_notification_context_add (nc, client);
933 GNUNET_SERVER_receive_done (client, GNUNET_OK);
938 * We got a response from a client.
941 * @param client the client
942 * @param message the response
945 handle_client_response (void *cls GNUNET_UNUSED,
946 struct GNUNET_SERVER_Client *client,
947 const struct GNUNET_MessageHeader *message)
949 const struct GNUNET_DNS_Response *resp;
950 struct RequestRecord *rr;
955 msize = ntohs (message->size);
956 if (msize < sizeof (struct GNUNET_DNS_Response))
959 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
962 resp = (const struct GNUNET_DNS_Response*) message;
963 off = (uint16_t) resp->request_id;
965 if (rr->request_id != resp->request_id)
967 GNUNET_STATISTICS_update (stats,
968 gettext_noop ("# Client response discarded (no matching request)"),
970 GNUNET_SERVER_receive_done (client, GNUNET_OK);
973 for (i=0;i<rr->client_wait_list_length;i++)
975 if (NULL == rr->client_wait_list[i])
977 if (rr->client_wait_list[i]->client != client)
979 rr->client_wait_list[i] = NULL;
980 switch (ntohl (resp->drop_flag))
985 case 1: /* no change */
988 msize -= sizeof (struct GNUNET_DNS_Response);
989 if ( (sizeof (struct dns_header) > msize) ||
990 (RP_REQUEST_MONITOR == rr->phase) ||
991 (RP_RESPONSE_MONITOR == rr->phase) )
994 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
998 GNUNET_free_non_null (rr->payload);
1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1001 _("Changing DNS reply according to client specifications\n"));
1003 rr->payload = GNUNET_malloc (msize);
1004 rr->payload_length = msize;
1005 memcpy (rr->payload, &resp[1], msize);
1006 if (rr->phase == RP_QUERY)
1008 /* clear wait list, we're moving to MODIFY phase next */
1009 GNUNET_array_grow (rr->client_wait_list,
1010 rr->client_wait_list_length,
1016 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1019 /* odd, client was not on our list for the request, that ought
1022 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1027 * Functions with this signature are called whenever a complete
1028 * message is received by the tokenizer from the DNS hijack process.
1030 * @param cls closure
1031 * @param client identification of the client
1032 * @param message the actual message, a DNS request we should handle
1035 process_helper_messages (void *cls GNUNET_UNUSED, void *client,
1036 const struct GNUNET_MessageHeader *message)
1039 const struct tun_header *tun;
1040 const struct ip4_header *ip4;
1041 const struct ip6_header *ip6;
1042 const struct udp_packet *udp;
1043 const struct dns_header *dns;
1044 struct RequestRecord *rr;
1045 struct sockaddr_in *srca4;
1046 struct sockaddr_in6 *srca6;
1047 struct sockaddr_in *dsta4;
1048 struct sockaddr_in6 *dsta6;
1050 msize = ntohs (message->size);
1051 if (msize < sizeof (struct GNUNET_MessageHeader) + sizeof (struct tun_header) + sizeof (struct ip4_header))
1053 /* non-IP packet received on TUN!? */
1057 msize -= sizeof (struct GNUNET_MessageHeader);
1058 tun = (const struct tun_header *) &message[1];
1059 msize -= sizeof (struct tun_header);
1060 switch (ntohs (tun->proto))
1063 ip4 = (const struct ip4_header *) &tun[1];
1064 if ( (msize < sizeof (struct ip4_header)) ||
1065 (ip4->version != IPVERSION) ||
1066 (ip4->header_length != sizeof (struct ip4_header) / 4) ||
1067 (ntohs(ip4->total_length) != msize) ||
1068 (ip4->protocol != IPPROTO_UDP) )
1070 /* non-IP/UDP packet received on TUN (or with options) */
1071 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1072 _("Received malformed IPv4-UDP packet on TUN interface.\n"));
1075 udp = (const struct udp_packet*) &ip4[1];
1076 msize -= sizeof (struct ip4_header);
1079 ip6 = (const struct ip6_header *) &tun[1];
1080 if ( (msize < sizeof (struct ip6_header)) ||
1081 (ip6->version != 6) ||
1082 (ntohs (ip6->payload_length) != msize) ||
1083 (ip6->next_header != IPPROTO_UDP) )
1085 /* non-IP/UDP packet received on TUN (or with extensions) */
1086 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1087 _("Received malformed IPv6-UDP packet on TUN interface.\n"));
1090 udp = (const struct udp_packet*) &ip6[1];
1091 msize -= sizeof (struct ip6_header);
1094 /* non-IP packet received on TUN!? */
1095 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1096 _("Got non-IP packet with %u bytes and protocol %u from TUN\n"),
1097 (unsigned int) msize,
1098 ntohs (tun->proto));
1101 if (msize <= sizeof (struct udp_packet) + sizeof (struct dns_header))
1103 /* non-DNS packet received on TUN, ignore */
1104 GNUNET_STATISTICS_update (stats,
1105 gettext_noop ("# Non-DNS UDP packet received via TUN interface"),
1109 msize -= sizeof (struct udp_packet);
1110 dns = (const struct dns_header*) &udp[1];
1111 rr = &requests[dns->id];
1113 /* clean up from previous request */
1114 GNUNET_free_non_null (rr->payload);
1116 GNUNET_array_grow (rr->client_wait_list,
1117 rr->client_wait_list_length,
1120 /* setup new request */
1121 rr->phase = RP_INIT;
1122 if (ip4->version == IPVERSION)
1124 srca4 = (struct sockaddr_in*) &rr->src_addr;
1125 dsta4 = (struct sockaddr_in*) &rr->dst_addr;
1126 memset (srca4, 0, sizeof (struct sockaddr_in));
1127 memset (dsta4, 0, sizeof (struct sockaddr_in));
1128 srca4->sin_family = AF_INET;
1129 dsta4->sin_family = AF_INET;
1130 srca4->sin_addr = ip4->source_address;
1131 dsta4->sin_addr = ip4->destination_address;
1132 srca4->sin_port = udp->spt;
1133 dsta4->sin_port = udp->dpt;
1134 #if HAVE_SOCKADDR_IN_SIN_LEN
1135 srca4->sin_len = sizeof (sizeof (struct sockaddr_in));
1136 dsta4->sin_len = sizeof (sizeof (struct sockaddr_in));
1141 srca6 = (struct sockaddr_in6*) &rr->src_addr;
1142 dsta6 = (struct sockaddr_in6*) &rr->dst_addr;
1143 memset (srca6, 0, sizeof (struct sockaddr_in6));
1144 memset (dsta6, 0, sizeof (struct sockaddr_in6));
1145 srca6->sin6_family = AF_INET6;
1146 dsta6->sin6_family = AF_INET6;
1147 srca6->sin6_addr = ip6->source_address;
1148 dsta6->sin6_addr = ip6->destination_address;
1149 srca6->sin6_port = udp->spt;
1150 dsta6->sin6_port = udp->dpt;
1151 #if HAVE_SOCKADDR_IN_SIN_LEN
1152 srca6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1153 dsta6->sin6_len = sizeof (sizeof (struct sockaddr_in6));
1156 rr->payload = GNUNET_malloc (msize);
1157 rr->payload_length = msize;
1158 memcpy (rr->payload, dns, msize);
1159 rr->request_id = dns->id | (request_id_gen << 16);
1162 GNUNET_STATISTICS_update (stats,
1163 gettext_noop ("# DNS requests received via TUN interface"),
1165 /* start request processing state machine */
1171 * @param cls closure
1172 * @param server the initialized server
1173 * @param cfg_ configuration to use
1176 run (void *cls, struct GNUNET_SERVER_Handle *server,
1177 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1179 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1180 /* callback, cls, type, size */
1181 {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT,
1182 sizeof (struct GNUNET_DNS_Register)},
1183 {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0},
1194 stats = GNUNET_STATISTICS_create ("dns", cfg);
1195 nc = GNUNET_SERVER_notification_context_create (server, 1);
1196 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1199 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1201 if ( (GNUNET_OK != open_port4 ()) &&
1202 (GNUNET_OK != open_port6 ()) )
1204 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1205 _("Failed to open any port to provide DNS exit\n"));
1206 GNUNET_SCHEDULER_shutdown ();
1211 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1212 if (GNUNET_SYSERR ==
1213 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
1215 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1216 "No entry 'IFNAME' in configuration!\n");
1217 GNUNET_SCHEDULER_shutdown ();
1220 helper_argv[1] = ifc_name;
1221 if ( (GNUNET_SYSERR ==
1222 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6ADDR",
1225 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1226 "No entry 'IPV6ADDR' in configuration!\n");
1227 GNUNET_SCHEDULER_shutdown ();
1230 helper_argv[2] = ipv6addr;
1231 if (GNUNET_SYSERR ==
1232 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV6PREFIX",
1235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1236 "No entry 'IPV6PREFIX' in configuration!\n");
1237 GNUNET_SCHEDULER_shutdown ();
1240 helper_argv[3] = ipv6prefix;
1242 if (GNUNET_SYSERR ==
1243 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4ADDR",
1246 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1247 "No entry 'IPV4ADDR' in configuration!\n");
1248 GNUNET_SCHEDULER_shutdown ();
1251 helper_argv[4] = ipv4addr;
1252 if (GNUNET_SYSERR ==
1253 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IPV4MASK",
1256 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1257 "No entry 'IPV4MASK' in configuration!\n");
1258 GNUNET_SCHEDULER_shutdown ();
1261 helper_argv[5] = ipv4mask;
1262 GNUNET_snprintf (port_s,
1265 (unsigned int) dnsoutport);
1266 helper_argv[6] = GNUNET_strdup (port_s);
1267 helper_argv[7] = NULL;
1268 hijacker = GNUNET_HELPER_start ("gnunet-helper-dns",
1270 &process_helper_messages,
1272 GNUNET_SERVER_add_handlers (server, handlers);
1273 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1278 * The main function for the dns service.
1280 * @param argc number of arguments from the command line
1281 * @param argv command line arguments
1282 * @return 0 ok, 1 on error
1285 main (int argc, char *const *argv)
1287 return (GNUNET_OK ==
1288 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1289 &run, NULL)) ? 0 : 1;
1293 /* end of gnunet-service-dns_new.c */