2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff
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.
24 * @author Philipp Toelke
27 #include <gnunet_common.h>
28 #include <gnunet_client_lib.h>
29 #include <gnunet_os_lib.h>
30 #include <gnunet_mesh_service.h>
31 #include <gnunet_protocols.h>
32 #include <gnunet_server_lib.h>
33 #include <gnunet_container_lib.h>
34 #include <block_dns.h>
36 #include "gnunet_dns_service.h"
39 struct query_packet_list
41 struct query_packet_list *next;
42 struct query_packet_list *prev;
43 struct query_packet pkt;
47 struct GNUNET_DNS_Handle
49 struct query_packet_list *head;
50 struct query_packet_list *tail;
51 struct GNUNET_CLIENT_Connection *dns_connection;
52 unsigned char restart_hijack;
54 struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle;
56 const struct GNUNET_CONFIGURATION_Handle *cfg;
58 GNUNET_DNS_ResponseCallback process_answer_cb;
60 void *process_answer_cb_cls;
65 * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages
70 send_query (void *cls GNUNET_UNUSED, size_t size, void *buf)
72 struct GNUNET_DNS_Handle *h = cls;
76 h->dns_transmit_handle = NULL;
79 * Send the rehijack-message
81 if (h->restart_hijack == 1)
83 h->restart_hijack = 0;
85 * The message is just a header
87 GNUNET_assert (sizeof (struct GNUNET_MessageHeader) <= size);
88 struct GNUNET_MessageHeader *hdr = buf;
90 len = sizeof (struct GNUNET_MessageHeader);
91 hdr->size = htons (len);
92 hdr->type = htons (GNUNET_MESSAGE_TYPE_REHIJACK);
94 else if (h->head != NULL)
96 struct query_packet_list *query = h->head;
98 len = ntohs (query->pkt.hdr.size);
100 GNUNET_assert (len <= size);
102 memcpy (buf, &query->pkt.hdr, len);
104 GNUNET_CONTAINER_DLL_remove (h->head, h->tail, query);
115 * Check whether more data is to be sent
119 h->dns_transmit_handle =
120 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
121 ntohs (h->head->pkt.hdr.size),
122 GNUNET_TIME_UNIT_FOREVER_REL,
123 GNUNET_YES, &send_query, h);
125 else if (h->restart_hijack == 1)
127 h->dns_transmit_handle =
128 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
130 GNUNET_MessageHeader),
131 GNUNET_TIME_UNIT_FOREVER_REL,
132 GNUNET_YES, &send_query, h);
143 * This receives packets from the service-dns and schedules process_answer to
147 dns_answer_handler (void *cls,
148 const struct GNUNET_MessageHeader *msg)
150 struct GNUNET_DNS_Handle *h = cls;
152 /* the service disconnected, reconnect after short wait */
155 if (h->dns_transmit_handle != NULL)
156 GNUNET_CLIENT_notify_transmit_ready_cancel (h->dns_transmit_handle);
157 h->dns_transmit_handle = NULL;
158 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
159 h->dns_connection = NULL;
162 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
163 &connect_to_service_dns, h);
168 /* the service did something strange, reconnect immediately */
169 if (msg->type != htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS))
172 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
173 h->dns_connection = NULL;
175 conn_task = GNUNET_SCHEDULER_add_now (&connect_to_service_dns, NULL);
179 h->process_answer_cb (h->process_answer_cb_cls,
180 (const struct answer_packet*) msg);
181 GNUNET_CLIENT_receive (h->dns_connection, &dns_answer_handler, h,
182 GNUNET_TIME_UNIT_FOREVER_REL);
187 * Connect to the service-dns
189 struct GNUNET_DNS_Handle *
190 GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
191 GNUNET_DNS_ResponseCallback cb,
194 struct GNUNET_DNS_Handle *h;
196 h = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle));
198 h->process_answer_cb = cb;
199 h->process_answer_cb_cls = cb_cls;
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to service-dns\n");
201 h->dns_connection = GNUNET_CLIENT_connect ("dns", h->cfg);
202 /* This would most likely be a misconfiguration */
203 GNUNET_assert (NULL != h->dns_connection);
204 GNUNET_CLIENT_receive (h->dns_connection,
205 &dns_answer_handler, NULL,
206 GNUNET_TIME_UNIT_FOREVER_REL);
207 /* If a packet is already in the list, schedule to send it */
208 if (h->dns_transmit_handle == NULL && h->head != NULL)
209 h->dns_transmit_handle =
210 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
211 ntohs (h->head->pkt.hdr.size),
212 GNUNET_TIME_UNIT_FOREVER_REL,
213 GNUNET_YES, &send_query, h);
214 else if (h->dns_transmit_handle == NULL && h->restart_hijack == 1)
216 h->dns_transmit_handle =
217 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
219 GNUNET_MessageHeader),
220 GNUNET_TIME_UNIT_FOREVER_REL,
221 GNUNET_YES, &send_query, NULL);
228 GNUNET_DNS_restart_hijack (struct GNUNET_DNS_Handle *h)
230 h->restart_hijack = 1;
231 if (NULL != h->dns_connection && h->dns_transmit_handle == NULL)
232 h->dns_transmit_handle =
233 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
235 GNUNET_MessageHeader),
236 GNUNET_TIME_UNIT_FOREVER_REL,
237 GNUNET_YES, &send_query, h);
242 * FIXME: we should not expost our internal structures like this.
243 * Just a quick initial hack.
246 queue_request (struct GNUNET_DNS_Handle *h,
247 struct query_packet_list *q)
249 GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, q);
250 if (h->dns_connection != NULL && h->dns_transmit_handle == NULL)
251 h->dns_transmit_handle =
252 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, ntohs(q->pkt.hdr.size),
253 GNUNET_TIME_UNIT_FOREVER_REL,
254 GNUNET_YES, &send_query,
261 * Process a DNS request sent to an IPv4 resolver. Pass it
262 * to the DNS service for resolution.
264 * @param h DNS handle
265 * @param dst_ip destination IPv4 address
266 * @param src_ip source IPv4 address (usually local machine)
267 * @param src_port source port (to be used for reply)
268 * @param udp_packet_len length of the UDP payload in bytes
269 * @param udp_packet UDP payload
272 GNUNET_DNS_queue_request_v4 (struct GNUNET_DNS_Handle *h,
273 const struct in_addr *dst_ip,
274 const struct in_addr *src_ip,
276 size_t udp_packet_len,
277 const char *udp_packet)
279 size_t len = sizeof (struct query_packet) + udp_packet_len - 1;
280 struct query_packet_list *query =
281 GNUNET_malloc (len + sizeof (struct query_packet_list) -
282 sizeof (struct query_packet));
283 query->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS);
284 query->pkt.hdr.size = htons (len);
285 memcpy (query->pkt.orig_to, dst_ip, 4);
286 memcpy (query->pkt.orig_from, src_ip, 4);
287 query->pkt.addrlen = 4;
288 query->pkt.src_port = htons (src_port);
289 memcpy (query->pkt.data, udp_packet, udp_packet_len);
290 queue_request (h, query);
295 * Process a DNS request sent to an IPv6 resolver. Pass it
296 * to the DNS service for resolution.
298 * @param h DNS handle
299 * @param dst_ip destination IPv6 address
300 * @param src_ip source IPv6 address (usually local machine)
301 * @param src_port source port (to be used for reply)
302 * @param udp_packet_len length of the UDP payload in bytes
303 * @param udp_packet UDP payload
306 GNUNET_DNS_queue_request_v6 (struct GNUNET_DNS_Handle *h,
307 const struct in6_addr *dst_ip,
308 const struct in6_addr *src_ip,
310 size_t udp_packet_len,
311 const char *udp_packet)
314 sizeof (struct query_packet) + udp_packet_len - 1;
315 struct query_packet_list *query =
316 GNUNET_malloc (len + sizeof (struct query_packet_list) -
317 sizeof (struct answer_packet));
318 query->pkt.hdr.type =
319 htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS);
320 query->pkt.hdr.size = htons (len);
321 memcpy (query->pkt.orig_to, dst_ip, 16);
322 memcpy (query->pkt.orig_from, src_ip, 16);
323 query->pkt.addrlen = 16;
324 query->pkt.src_port = htons (src_port);
325 memcpy (query->pkt.data, udp_packet,
327 queue_request (h, query);
332 GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *h)
334 if (h->dns_connection != NULL)
336 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
337 h->dns_connection = NULL;
342 /* end of dns_api.c */