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 GNUNET_PACKED;
42 struct query_packet_list *prev GNUNET_PACKED;
43 struct query_packet pkt;
48 struct GNUNET_DNS_Handle
50 struct query_packet_list *head;
51 struct query_packet_list *tail;
52 struct GNUNET_CLIENT_Connection *dns_connection;
53 unsigned char restart_hijack;
55 struct GNUNET_CLIENT_TransmitHandle *dns_transmit_handle;
57 const struct GNUNET_CONFIGURATION_Handle *cfg;
59 GNUNET_DNS_ResponseCallback process_answer_cb;
61 void *process_answer_cb_cls;
66 * Callback called by notify_transmit_ready; sends dns-queries or rehijack-messages
71 send_query (void *cls GNUNET_UNUSED, size_t size, void *buf)
73 struct GNUNET_DNS_Handle *h = cls;
77 h->dns_transmit_handle = NULL;
80 * Send the rehijack-message
82 if (h->restart_hijack == 1)
84 h->restart_hijack = 0;
86 * The message is just a header
88 GNUNET_assert (sizeof (struct GNUNET_MessageHeader) <= size);
89 struct GNUNET_MessageHeader *hdr = buf;
91 len = sizeof (struct GNUNET_MessageHeader);
92 hdr->size = htons (len);
93 hdr->type = htons (GNUNET_MESSAGE_TYPE_REHIJACK);
95 else if (h->head != NULL)
97 struct query_packet_list *query = h->head;
99 len = ntohs (query->pkt.hdr.size);
101 GNUNET_assert (len <= size);
103 memcpy (buf, &query->pkt.hdr, len);
105 GNUNET_CONTAINER_DLL_remove (h->head, h->tail, query);
116 * Check whether more data is to be sent
120 h->dns_transmit_handle =
121 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
122 ntohs (h->head->pkt.hdr.size),
123 GNUNET_TIME_UNIT_FOREVER_REL,
124 GNUNET_YES, &send_query, h);
126 else if (h->restart_hijack == 1)
128 h->dns_transmit_handle =
129 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
131 GNUNET_MessageHeader),
132 GNUNET_TIME_UNIT_FOREVER_REL,
133 GNUNET_YES, &send_query, h);
144 * This receives packets from the service-dns and schedules process_answer to
148 dns_answer_handler (void *cls,
149 const struct GNUNET_MessageHeader *msg)
151 struct GNUNET_DNS_Handle *h = cls;
153 /* the service disconnected, reconnect after short wait */
156 if (h->dns_transmit_handle != NULL)
157 GNUNET_CLIENT_notify_transmit_ready_cancel (h->dns_transmit_handle);
158 h->dns_transmit_handle = NULL;
159 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
160 h->dns_connection = NULL;
163 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
164 &connect_to_service_dns, h);
169 /* the service did something strange, reconnect immediately */
170 if (msg->type != htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS))
173 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
174 h->dns_connection = NULL;
176 conn_task = GNUNET_SCHEDULER_add_now (&connect_to_service_dns, NULL);
180 h->process_answer_cb (h->process_answer_cb_cls,
181 (const struct answer_packet*) msg);
182 GNUNET_CLIENT_receive (h->dns_connection, &dns_answer_handler, h,
183 GNUNET_TIME_UNIT_FOREVER_REL);
188 * Connect to the service-dns
190 struct GNUNET_DNS_Handle *
191 GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
192 GNUNET_DNS_ResponseCallback cb,
195 struct GNUNET_DNS_Handle *h;
197 h = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle));
199 h->process_answer_cb = cb;
200 h->process_answer_cb_cls = cb_cls;
201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connecting to service-dns\n");
202 h->dns_connection = GNUNET_CLIENT_connect ("dns", h->cfg);
203 /* This would most likely be a misconfiguration */
204 GNUNET_assert (NULL != h->dns_connection);
205 GNUNET_CLIENT_receive (h->dns_connection,
206 &dns_answer_handler, NULL,
207 GNUNET_TIME_UNIT_FOREVER_REL);
208 /* If a packet is already in the list, schedule to send it */
209 if (h->dns_transmit_handle == NULL && h->head != NULL)
210 h->dns_transmit_handle =
211 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
212 ntohs (h->head->pkt.hdr.size),
213 GNUNET_TIME_UNIT_FOREVER_REL,
214 GNUNET_YES, &send_query, h);
215 else if (h->dns_transmit_handle == NULL && h->restart_hijack == 1)
217 h->dns_transmit_handle =
218 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
220 GNUNET_MessageHeader),
221 GNUNET_TIME_UNIT_FOREVER_REL,
222 GNUNET_YES, &send_query, NULL);
229 GNUNET_DNS_restart_hijack (struct GNUNET_DNS_Handle *h)
231 h->restart_hijack = 1;
232 if (NULL != h->dns_connection && h->dns_transmit_handle == NULL)
233 h->dns_transmit_handle =
234 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection,
236 GNUNET_MessageHeader),
237 GNUNET_TIME_UNIT_FOREVER_REL,
238 GNUNET_YES, &send_query, h);
243 * FIXME: we should not expost our internal structures like this.
244 * Just a quick initial hack.
247 queue_request (struct GNUNET_DNS_Handle *h,
248 struct query_packet_list *q)
250 GNUNET_CONTAINER_DLL_insert_tail (h->head, h->tail, q);
251 if (h->dns_connection != NULL && h->dns_transmit_handle == NULL)
252 h->dns_transmit_handle =
253 GNUNET_CLIENT_notify_transmit_ready (h->dns_connection, ntohs(q->pkt.hdr.size),
254 GNUNET_TIME_UNIT_FOREVER_REL,
255 GNUNET_YES, &send_query,
262 * Process a DNS request sent to an IPv4 resolver. Pass it
263 * to the DNS service for resolution.
265 * @param h DNS handle
266 * @param dst_ip destination IPv4 address
267 * @param src_ip source IPv4 address (usually local machine)
268 * @param src_port source port (to be used for reply)
269 * @param udp_packet_len length of the UDP payload in bytes
270 * @param udp_packet UDP payload
273 GNUNET_DNS_queue_request_v4 (struct GNUNET_DNS_Handle *h,
274 const struct in_addr *dst_ip,
275 const struct in_addr *src_ip,
277 size_t udp_packet_len,
278 const char *udp_packet)
280 size_t len = sizeof (struct query_packet) + udp_packet_len - 1;
281 struct query_packet_list *query =
282 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
283 sizeof (struct answer_packet));
284 query->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS);
285 query->pkt.hdr.size = htons (len);
286 memcpy (query->pkt.orig_to, dst_ip, 4);
287 memcpy (query->pkt.orig_from, src_ip, 4);
288 query->pkt.addrlen = 4;
289 query->pkt.src_port = htons (src_port);
290 memcpy (query->pkt.data, udp_packet, udp_packet_len);
291 queue_request (h, query);
296 * Process a DNS request sent to an IPv6 resolver. Pass it
297 * to the DNS service for resolution.
299 * @param h DNS handle
300 * @param dst_ip destination IPv6 address
301 * @param src_ip source IPv6 address (usually local machine)
302 * @param src_port source port (to be used for reply)
303 * @param udp_packet_len length of the UDP payload in bytes
304 * @param udp_packet UDP payload
307 GNUNET_DNS_queue_request_v6 (struct GNUNET_DNS_Handle *h,
308 const struct in6_addr *dst_ip,
309 const struct in6_addr *src_ip,
311 size_t udp_packet_len,
312 const char *udp_packet)
315 sizeof (struct query_packet) + udp_packet_len - 1;
316 struct query_packet_list *query =
317 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
318 sizeof (struct answer_packet));
319 query->pkt.hdr.type =
320 htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS);
321 query->pkt.hdr.size = htons (len);
322 memcpy (query->pkt.orig_to, dst_ip, 16);
323 memcpy (query->pkt.orig_from, src_ip, 16);
324 query->pkt.addrlen = 16;
325 query->pkt.src_port = htons (src_port);
326 memcpy (query->pkt.data, udp_packet,
328 queue_request (h, query);
333 GNUNET_DNS_disconnect (struct GNUNET_DNS_Handle *h)
335 if (h->dns_connection != NULL)
337 GNUNET_CLIENT_disconnect (h->dns_connection, GNUNET_NO);
338 h->dns_connection = NULL;
343 /* end of dns_api.c */