aboutsummaryrefslogtreecommitdiff
path: root/src/vpn/gnunet-service-dns.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2012-01-01 23:00:59 +0000
committerChristian Grothoff <christian@grothoff.org>2012-01-01 23:00:59 +0000
commit66ffc809472f27d69b9ad7361f8ba29c2674f716 (patch)
tree609623cb79291939f9cb81a8858853a202dae2ca /src/vpn/gnunet-service-dns.c
parent131c43b2b18b12e52ff045e51025706802cbd2e2 (diff)
downloadgnunet-66ffc809472f27d69b9ad7361f8ba29c2674f716.tar.gz
gnunet-66ffc809472f27d69b9ad7361f8ba29c2674f716.zip
-moving DNS code into its own directory
Diffstat (limited to 'src/vpn/gnunet-service-dns.c')
-rw-r--r--src/vpn/gnunet-service-dns.c1731
1 files changed, 0 insertions, 1731 deletions
diff --git a/src/vpn/gnunet-service-dns.c b/src/vpn/gnunet-service-dns.c
deleted file mode 100644
index 12d0a93cf..000000000
--- a/src/vpn/gnunet-service-dns.c
+++ /dev/null
@@ -1,1731 +0,0 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19*/
20
21/**
22 * @file vpn/gnunet-service-dns.c
23 * @author Philipp Toelke
24 */
25#include "platform.h"
26#include "gnunet_getopt_lib.h"
27#include "gnunet_service_lib.h"
28#include <gnunet_constants.h>
29#include "gnunet_network_lib.h"
30#include "gnunet_os_lib.h"
31#include "gnunet-service-dns-p.h"
32#include "gnunet_connection_lib.h"
33#include "gnunet_protocols.h"
34#include "gnunet_applications.h"
35#include "gnunet-vpn-packet.h"
36#include "gnunet_container_lib.h"
37#include "gnunet-dns-parser.h"
38#include "gnunet_dht_service.h"
39#include "gnunet_block_lib.h"
40#include "block_dns.h"
41#include "gnunet_crypto_lib.h"
42#include "gnunet_mesh_service.h"
43#include "gnunet_signatures.h"
44
45struct GNUNET_MESH_Handle *mesh_handle;
46
47struct GNUNET_CONNECTION_TransmitHandle *server_notify;
48
49/**
50 * The UDP-Socket through which DNS-Resolves will be sent if they are not to be
51 * sent through gnunet. The port of this socket will not be hijacked.
52 */
53static struct GNUNET_NETWORK_Handle *dnsout;
54static struct GNUNET_NETWORK_Handle *dnsout6;
55
56/**
57 * The port bound to the socket dnsout
58 */
59static unsigned short dnsoutport;
60
61/**
62 * A handle to the DHT-Service
63 */
64static struct GNUNET_DHT_Handle *dht;
65
66/**
67 * The configuration to use
68 */
69static const struct GNUNET_CONFIGURATION_Handle *cfg;
70
71/**
72 * A list of DNS-Responses that have to be sent to the requesting client
73 */
74static struct answer_packet_list *head;
75
76/**
77 * The tail of the list of DNS-responses
78 */
79static struct answer_packet_list *tail;
80
81/**
82 * A structure containing a mapping from network-byte-ordered DNS-id (16 bit) to
83 * some information needed to handle this query
84 *
85 * It currently allocates at least
86 * (1 + machine-width + machine-width + 32 + 32 + 16 + machine-width + 8) * 65536 bit
87 * = 17 MiB on 64 bit.
88 * = 11 MiB on 32 bit.
89 */
90static struct
91{
92 unsigned valid:1;
93 struct GNUNET_SERVER_Client *client;
94 struct GNUNET_MESH_Tunnel *tunnel;
95 char local_ip[16];
96 char remote_ip[16];
97 char addrlen;
98 uint16_t local_port;
99 char *name;
100 uint8_t namelen;
101 uint16_t qtype;
102} query_states[UINT16_MAX + 1];
103
104/**
105 * A struct used to give more than one value as
106 * closure to receive_dht
107 */
108struct receive_dht_cls
109{
110 uint16_t id;
111 struct GNUNET_DHT_GetHandle *handle;
112};
113
114struct tunnel_notify_queue
115{
116 struct tunnel_notify_queue *next;
117 struct tunnel_notify_queue *prev;
118 void *cls;
119 size_t len;
120 GNUNET_CONNECTION_TransmitReadyNotify cb;
121};
122
123struct tunnel_state
124{
125 struct tunnel_notify_queue *head, *tail;
126 struct GNUNET_MESH_TransmitHandle *th;
127};
128
129static size_t
130send_answer (void *cls, size_t size, void *buf);
131
132static void
133client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
134{
135 if (NULL == head)
136 return;
137
138 if (head->client == client)
139 {
140 GNUNET_CONNECTION_notify_transmit_ready_cancel (server_notify);
141 server_notify =
142 GNUNET_SERVER_notify_transmit_ready (head->next->client,
143 ntohs (head->next->pkt.hdr.size),
144 GNUNET_TIME_UNIT_FOREVER_REL,
145 &send_answer, NULL);
146 }
147
148 struct answer_packet_list *element = head;
149
150 while (element != NULL)
151 {
152 if (element->client == client)
153 {
154 GNUNET_SERVER_client_drop (client);
155 GNUNET_CONTAINER_DLL_remove (head, tail, element);
156 struct answer_packet_list *t = element;
157
158 element = element->next;
159 GNUNET_free (t);
160 }
161 else
162 element = element->next;
163 }
164}
165
166/**
167 * Hijack all outgoing DNS-Traffic but for traffic leaving "our" port.
168 */
169static void
170hijack (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc)
171{
172 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
173 return;
174
175 if (0 == dnsoutport)
176 {
177 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
178 "Delaying the hijacking, port is still %d!\n", dnsoutport);
179 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL);
180 return;
181 }
182
183 char port_s[6];
184 char *virt_dns;
185 struct GNUNET_OS_Process *proc;
186
187 if (GNUNET_SYSERR ==
188 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns))
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
191 "No entry 'VIRTDNS' in configuration!\n");
192 exit (1);
193 }
194
195 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Hijacking, port is %d\n", dnsoutport);
196 snprintf (port_s, 6, "%d", dnsoutport);
197 if (NULL !=
198 (proc =
199 GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns",
200 "gnunet-hijack-dns", port_s, virt_dns, NULL)))
201 {
202 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc));
203 GNUNET_OS_process_close (proc);
204 }
205 GNUNET_free (virt_dns);
206}
207
208static void *
209new_tunnel (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
210 const struct GNUNET_PeerIdentity *initiator GNUNET_UNUSED,
211 const struct GNUNET_ATS_Information *ats GNUNET_UNUSED)
212{
213 struct tunnel_state *s = GNUNET_malloc (sizeof *s);
214
215 s->head = NULL;
216 s->tail = NULL;
217 s->th = NULL;
218 return s;
219}
220
221static void
222clean_tunnel (void *cls GNUNET_UNUSED, const struct GNUNET_MESH_Tunnel *tunnel,
223 void *tunnel_ctx)
224{
225 GNUNET_free (tunnel_ctx);
226}
227
228/**
229 * Delete the hijacking-routes
230 */
231static void
232unhijack (unsigned short port)
233{
234 char port_s[6];
235 char *virt_dns;
236 struct GNUNET_OS_Process *proc;
237
238 if (GNUNET_SYSERR ==
239 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS", &virt_dns))
240 {
241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
242 "No entry 'VIRTDNS' in configuration!\n");
243 exit (1);
244 }
245
246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "unHijacking, port is %d\n", port);
247 snprintf (port_s, 6, "%d", port);
248 if (NULL !=
249 (proc =
250 GNUNET_OS_start_process (NULL, NULL, "gnunet-helper-hijack-dns",
251 "gnunet-hijack-dns", "-d", port_s, virt_dns,
252 NULL)))
253 {
254 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc));
255 GNUNET_OS_process_close (proc);
256 }
257 GNUNET_free (virt_dns);
258}
259
260/**
261 * Send the DNS-Response to the client. Gets called via the notify_transmit_ready-
262 * system.
263 */
264static size_t
265send_answer (void *cls, size_t size, void *buf)
266{
267 server_notify = NULL;
268 struct answer_packet_list *query = head;
269 size_t len = ntohs (query->pkt.hdr.size);
270
271 GNUNET_assert (len <= size);
272
273 memcpy (buf, &query->pkt.hdr, len);
274
275 GNUNET_CONTAINER_DLL_remove (head, tail, query);
276
277 /* When more data is to be sent, reschedule */
278 if (head != NULL)
279 server_notify =
280 GNUNET_SERVER_notify_transmit_ready (head->client,
281 ntohs (head->pkt.hdr.size),
282 GNUNET_TIME_UNIT_FOREVER_REL,
283 &send_answer, NULL);
284
285 GNUNET_SERVER_client_drop (query->client);
286 GNUNET_free (query);
287 return len;
288}
289
290GNUNET_NETWORK_STRUCT_BEGIN
291
292struct tunnel_cls
293{
294 struct GNUNET_MESH_Tunnel *tunnel GNUNET_PACKED;
295 struct GNUNET_MessageHeader hdr;
296 struct dns_pkt dns;
297};
298GNUNET_NETWORK_STRUCT_END
299
300struct tunnel_cls *remote_pending[UINT16_MAX];
301
302static size_t
303mesh_send_response (void *cls, size_t size, void *buf)
304{
305 GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
306 struct GNUNET_MessageHeader *hdr = buf;
307 uint32_t *sz = cls;
308 struct GNUNET_MESH_Tunnel **tunnel = (struct GNUNET_MESH_Tunnel **) (sz + 1);
309 struct dns_pkt *dns = (struct dns_pkt *) (tunnel + 1);
310
311 GNUNET_MESH_tunnel_set_data (*tunnel, NULL);
312
313 hdr->type = htons (GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS);
314 hdr->size = htons (*sz + sizeof (struct GNUNET_MessageHeader));
315
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "Sending response, size=%d, sz=%d, sz+hdr=%d\n", size, *sz,
318 *sz + sizeof (struct GNUNET_MessageHeader));
319
320 GNUNET_assert (size >= (*sz + sizeof (struct GNUNET_MessageHeader)));
321
322 memcpy (hdr + 1, dns, *sz);
323 struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (*tunnel);
324
325 if (NULL != s->head)
326 {
327 struct tunnel_notify_queue *element = s->head;
328 struct tunnel_notify_queue *head = s->head;
329 struct tunnel_notify_queue *tail = s->tail;
330
331 GNUNET_CONTAINER_DLL_remove (head, tail, element);
332
333 s->th =
334 GNUNET_MESH_notify_transmit_ready (*tunnel, GNUNET_NO, 42,
335 GNUNET_TIME_relative_divide
336 (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
337 (const struct GNUNET_PeerIdentity *)
338 NULL, element->len, element->cb,
339 element->cls);
340 }
341
342 GNUNET_free (cls);
343
344 return ntohs (hdr->size);
345}
346
347static size_t
348mesh_send (void *cls, size_t size, void *buf)
349{
350 struct tunnel_cls *cls_ = (struct tunnel_cls *) cls;
351
352 GNUNET_MESH_tunnel_set_data (cls_->tunnel, NULL);
353
354 GNUNET_assert (cls_->hdr.size <= size);
355
356 size = cls_->hdr.size;
357 cls_->hdr.size = htons (cls_->hdr.size);
358
359 memcpy (buf, &cls_->hdr, size);
360
361 struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel);
362
363 if (NULL != s->head)
364 {
365 struct tunnel_notify_queue *element = s->head;
366 struct tunnel_notify_queue *head = s->head;
367 struct tunnel_notify_queue *tail = s->tail;;
368
369 GNUNET_CONTAINER_DLL_remove (head, tail, element);
370
371 s->th =
372 GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_NO, 42,
373 GNUNET_TIME_relative_divide
374 (GNUNET_CONSTANTS_MAX_CORK_DELAY, 2),
375 (const struct GNUNET_PeerIdentity *)
376 NULL, element->len, element->cb,
377 element->cls);
378
379 GNUNET_free (element);
380 }
381
382 return size;
383}
384
385
386void
387mesh_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
388 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
389{
390 if (NULL == peer)
391 return;
392 struct tunnel_cls *cls_ = (struct tunnel_cls *) cls;
393
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395 "Connected to peer %s, %x, sending query with id %d\n",
396 GNUNET_i2s (peer), peer, ntohs (cls_->dns.s.id));
397
398 struct tunnel_state *s = GNUNET_MESH_tunnel_get_data (cls_->tunnel);
399
400 if (NULL == s->head)
401 {
402 s->th =
403 GNUNET_MESH_notify_transmit_ready (cls_->tunnel, GNUNET_YES, 42,
404 GNUNET_TIME_UNIT_MINUTES, NULL,
405 cls_->hdr.size, mesh_send, cls);
406
407 }
408 else
409 {
410 struct tunnel_notify_queue *head = s->head;
411 struct tunnel_notify_queue *tail = s->tail;
412
413 struct tunnel_notify_queue *element =
414 GNUNET_malloc (sizeof (struct tunnel_notify_queue));
415 element->cls = cls;
416 element->len = cls_->hdr.size;
417 element->cb = mesh_send;
418
419 GNUNET_CONTAINER_DLL_insert_tail (head, tail, element);
420 }
421}
422
423
424static void
425send_mesh_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
426{
427 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
428 return;
429
430 struct tunnel_cls *cls_ = (struct tunnel_cls *) cls;
431
432 struct tunnel_state *s = GNUNET_malloc (sizeof *s);
433
434 s->head = NULL;
435 s->tail = NULL;
436 s->th = NULL;
437
438 cls_->tunnel =
439 GNUNET_MESH_tunnel_create (mesh_handle, s, mesh_connect, NULL, cls_);
440
441 GNUNET_MESH_peer_request_connect_by_type (cls_->tunnel,
442 GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER);
443
444 remote_pending[cls_->dns.s.id] = cls_;
445}
446
447static int
448receive_mesh_query (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
449 void **ctx GNUNET_UNUSED,
450 const struct GNUNET_PeerIdentity *sender GNUNET_UNUSED,
451 const struct GNUNET_MessageHeader *message,
452 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
453{
454 struct dns_pkt *dns = (struct dns_pkt *) (message + 1);
455
456 struct sockaddr_in dest;
457
458 struct dns_pkt_parsed *pdns = parse_dns_packet (dns);
459
460 memset (&dest, 0, sizeof dest);
461 dest.sin_port = htons (53);
462 char *dns_resolver;
463
464 if (GNUNET_OK !=
465 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "EXTERNAL_DNS",
466 &dns_resolver) ||
467 1 != inet_pton (AF_INET, dns_resolver, &dest.sin_addr))
468 inet_pton (AF_INET, "8.8.8.8", &dest.sin_addr);
469
470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Querying for remote, id=%d\n",
471 ntohs (dns->s.id));
472 query_states[dns->s.id].tunnel = tunnel;
473 query_states[dns->s.id].valid = GNUNET_YES;
474
475 int i;
476
477 for (i = 0; i < ntohs (pdns->s.qdcount); i++)
478 {
479 if (pdns->queries[i]->qtype == htons (28) ||
480 pdns->queries[i]->qtype == htons (1))
481 {
482 query_states[dns->s.id].qtype = pdns->queries[i]->qtype;
483 break;
484 }
485 }
486 free_parsed_dns_packet (pdns);
487
488 GNUNET_NETWORK_socket_sendto (dnsout, dns,
489 ntohs (message->size) -
490 sizeof (struct GNUNET_MessageHeader),
491 (struct sockaddr *) &dest, sizeof dest);
492
493 return GNUNET_SYSERR;
494}
495
496static int
497receive_mesh_answer (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
498 void **ctx GNUNET_UNUSED,
499 const struct GNUNET_PeerIdentity *sender,
500 const struct GNUNET_MessageHeader *message,
501 const struct GNUNET_ATS_Information *atsi GNUNET_UNUSED)
502{
503 /* TODo: size check */
504 struct dns_pkt *dns = (struct dns_pkt *) (message + 1);
505
506 /* They sent us a packet we were not waiting for */
507 if (remote_pending[dns->s.id] == NULL ||
508 remote_pending[dns->s.id]->tunnel != tunnel)
509 return GNUNET_OK;
510
511 GNUNET_free (remote_pending[dns->s.id]);
512 remote_pending[dns->s.id] = NULL;
513
514 if (query_states[dns->s.id].valid != GNUNET_YES)
515 return GNUNET_SYSERR;
516 query_states[dns->s.id].valid = GNUNET_NO;
517
518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
519 "Received answer from peer %s, dns-id %d\n", GNUNET_i2s (sender),
520 ntohs (dns->s.id));
521
522 size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[dns->s.id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */
523 + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */
524
525 struct answer_packet_list *answer =
526 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
527 sizeof (struct answer_packet));
528
529 answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS);
530 answer->pkt.hdr.size = htons (len);
531
532 struct dns_pkt_parsed *pdns = parse_dns_packet (dns);
533
534 if (ntohs (pdns->s.ancount) < 1)
535 {
536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer only contains %d answers.\n",
537 ntohs (pdns->s.ancount));
538 free_parsed_dns_packet (pdns);
539 GNUNET_free (answer);
540 return GNUNET_OK;
541 }
542
543 int i = 0;
544
545 while (i < ntohs (pdns->s.ancount) && ntohs (pdns->answers[i]->type) != 28 &&
546 ntohs (pdns->answers[i]->type) != 1)
547 {
548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer contains %d.\n",
549 ntohs (pdns->answers[i]->type));
550 i++;
551 }
552
553 if (i >= ntohs (pdns->s.ancount))
554 {
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "Answer does not contain any usable answers.\n");
557 free_parsed_dns_packet (pdns);
558 GNUNET_free (answer);
559 return GNUNET_OK;
560 }
561
562 answer->pkt.addrsize = ntohs (pdns->answers[i]->data_len);
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "The first answer has the addrlen %d\n",
564 answer->pkt.addrsize);
565 memcpy (answer->pkt.addr, pdns->answers[i]->data,
566 ntohs (pdns->answers[i]->data_len));
567
568 memcpy (answer->pkt.from, query_states[dns->s.id].remote_ip,
569 query_states[dns->s.id].addrlen);
570 memcpy (answer->pkt.to, query_states[dns->s.id].local_ip,
571 query_states[dns->s.id].addrlen);
572 answer->pkt.addrlen = query_states[dns->s.id].addrlen;
573 answer->pkt.dst_port = query_states[dns->s.id].local_port;
574
575 struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data;
576
577 dpkt->s.id = dns->s.id;
578 dpkt->s.aa = 1;
579 dpkt->s.qr = 1;
580 dpkt->s.ra = 1;
581 dpkt->s.qdcount = htons (1);
582 dpkt->s.ancount = htons (1);
583
584 memcpy (dpkt->data, query_states[dns->s.id].name,
585 query_states[dns->s.id].namelen);
586 GNUNET_free (query_states[dns->s.id].name);
587 query_states[dns->s.id].name = NULL;
588
589 struct dns_query_line *dque =
590 (struct dns_query_line *) (dpkt->data +
591 (query_states[dns->s.id].namelen));
592
593 struct dns_record_line *drec_data =
594 (struct dns_record_line *) (dpkt->data +
595 (query_states[dns->s.id].namelen) +
596 sizeof (struct dns_query_line) + 2);
597 if (htons (28) == query_states[dns->s.id].qtype)
598 {
599 answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_AAAA;
600 dque->type = htons (28); /* AAAA */
601 drec_data->type = htons (28); /* AAAA */
602 drec_data->data_len = htons (16);
603 }
604 else if (htons (1) == query_states[dns->s.id].qtype)
605 {
606 answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REMOTE_A;
607 dque->type = htons (1); /* A */
608 drec_data->type = htons (1); /* A */
609 drec_data->data_len = htons (4);
610 }
611 else
612 {
613 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "dns-answer with pending qtype = %d\n",
614 query_states[dns->s.id].qtype);
615 GNUNET_assert (0);
616 }
617 dque->class = htons (1); /* IN */
618
619 char *anname =
620 (char *) (dpkt->data + (query_states[dns->s.id].namelen) +
621 sizeof (struct dns_query_line));
622 memcpy (anname, "\xc0\x0c", 2);
623 drec_data->class = htons (1); /* IN */
624
625 drec_data->ttl = pdns->answers[i]->ttl;
626
627 /* Calculate at which offset in the packet the IPv6-Address belongs, it is
628 * filled in by the daemon-vpn */
629 answer->pkt.addroffset =
630 htons ((unsigned short) ((unsigned long) (&drec_data->data) -
631 (unsigned long) (&answer->pkt)));
632
633 GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
634 answer->client = query_states[dns->s.id].client;
635
636 if (server_notify == NULL)
637 server_notify =
638 GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client,
639 len, GNUNET_TIME_UNIT_FOREVER_REL,
640 &send_answer, NULL);
641
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "Sent answer of length %d on to client, addroffset = %d\n", len,
644 answer->pkt.addroffset);
645
646 free_parsed_dns_packet (pdns);
647 return GNUNET_OK;
648}
649
650
651static void
652send_rev_query (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
653{
654 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
655 return;
656
657 struct dns_pkt_parsed *pdns = (struct dns_pkt_parsed *) cls;
658
659 unsigned short id = pdns->s.id;
660
661 free_parsed_dns_packet (pdns);
662
663 if (query_states[id].valid != GNUNET_YES)
664 return;
665 query_states[id].valid = GNUNET_NO;
666
667 GNUNET_assert (query_states[id].namelen == 74);
668
669 size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + 74 /* this is the length of a reverse ipv6-lookup */
670 + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */
671 + sizeof (struct dns_record_line) - 1 -
672 2 /* We do not know the lenght of the answer yet */ ;
673
674 struct answer_packet_list *answer =
675 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
676 sizeof (struct answer_packet));
677
678 answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS);
679 answer->pkt.hdr.size = htons (len);
680 answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_REV;
681
682 memcpy (answer->pkt.from, query_states[id].remote_ip,
683 query_states[id].addrlen);
684 memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen);
685
686 answer->pkt.dst_port = query_states[id].local_port;
687
688 struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data;
689
690 dpkt->s.id = id;
691 dpkt->s.aa = 1;
692 dpkt->s.qr = 1;
693 dpkt->s.ra = 1;
694 dpkt->s.qdcount = htons (1);
695 dpkt->s.ancount = htons (1);
696
697 memcpy (dpkt->data, query_states[id].name, query_states[id].namelen);
698 GNUNET_free (query_states[id].name);
699 query_states[id].name = NULL;
700
701 struct dns_query_line *dque =
702 (struct dns_query_line *) (dpkt->data + (query_states[id].namelen));
703 dque->type = htons (12); /* PTR */
704 dque->class = htons (1); /* IN */
705
706 char *anname =
707 (char *) (dpkt->data + (query_states[id].namelen) +
708 sizeof (struct dns_query_line));
709 memcpy (anname, "\xc0\x0c", 2);
710
711 struct dns_record_line *drec_data =
712 (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) +
713 sizeof (struct dns_query_line) + 2);
714 drec_data->type = htons (12); /* AAAA */
715 drec_data->class = htons (1); /* IN */
716 /* FIXME: read the TTL from block:
717 * GNUNET_TIME_absolute_get_remaining(rec->expiration_time)
718 *
719 * But how to get the seconds out of this?
720 */
721 drec_data->ttl = htonl (3600);
722
723 /* Calculate at which offset in the packet the length of the name and the
724 * name, it is filled in by the daemon-vpn */
725 answer->pkt.addroffset =
726 htons ((unsigned short) ((unsigned long) (&drec_data->data_len) -
727 (unsigned long) (&answer->pkt)));
728
729 GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
730 answer->client = query_states[id].client;
731
732 if (server_notify == NULL)
733 server_notify =
734 GNUNET_SERVER_notify_transmit_ready (query_states[id].client, len,
735 GNUNET_TIME_UNIT_FOREVER_REL,
736 &send_answer, NULL);
737}
738
739/**
740 * Receive a block from the dht.
741 */
742static void
743receive_dht (void *cls, struct GNUNET_TIME_Absolute exp GNUNET_UNUSED,
744 const GNUNET_HashCode * key GNUNET_UNUSED,
745 const struct GNUNET_PeerIdentity *get_path GNUNET_UNUSED,
746 unsigned int get_path_length GNUNET_UNUSED,
747 const struct GNUNET_PeerIdentity *put_path GNUNET_UNUSED,
748 unsigned int put_path_length GNUNET_UNUSED,
749 enum GNUNET_BLOCK_Type type, size_t size, const void *data)
750{
751
752 unsigned short id = ((struct receive_dht_cls *) cls)->id;
753 struct GNUNET_DHT_GetHandle *handle =
754 ((struct receive_dht_cls *) cls)->handle;
755 GNUNET_free (cls);
756
757 GNUNET_DHT_get_stop (handle);
758
759 GNUNET_assert (type == GNUNET_BLOCK_TYPE_DNS);
760
761 /* If no query with this id is pending, ignore the block */
762 if (query_states[id].valid != GNUNET_YES)
763 return;
764 query_states[id].valid = GNUNET_NO;
765
766 const struct GNUNET_DNS_Record *rec = data;
767
768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
769 "Got block of size %d, peer: %08x, desc: %08x\n", size,
770 *((unsigned int *) &rec->peer),
771 *((unsigned int *) &rec->service_descriptor));
772
773 size_t len = sizeof (struct answer_packet) - 1 + sizeof (struct dns_static) + query_states[id].namelen + sizeof (struct dns_query_line) + 2 /* To hold the pointer (as defined in RFC1035) to the name */
774 + sizeof (struct dns_record_line) - 1 + 16; /* To hold the IPv6-Address */
775
776 struct answer_packet_list *answer =
777 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
778 sizeof (struct answer_packet));
779
780 answer->pkt.hdr.type = htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS);
781 answer->pkt.hdr.size = htons (len);
782 answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_SERVICE;
783 answer->client = query_states[id].client;
784
785 GNUNET_CRYPTO_hash (&rec->peer,
786 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
787 &answer->pkt.service_descr.peer);
788
789 memcpy (&answer->pkt.service_descr.service_descriptor,
790 &rec->service_descriptor, sizeof (GNUNET_HashCode));
791 memcpy (&answer->pkt.service_descr.service_type, &rec->service_type,
792 sizeof (answer->pkt.service_descr.service_type));
793 memcpy (&answer->pkt.service_descr.ports, &rec->ports,
794 sizeof (answer->pkt.service_descr.ports));
795
796 memcpy (answer->pkt.from, query_states[id].remote_ip,
797 query_states[id].addrlen);
798 memcpy (answer->pkt.to, query_states[id].local_ip, query_states[id].addrlen);
799 answer->pkt.addrlen = query_states[id].addrlen;
800
801 answer->pkt.dst_port = query_states[id].local_port;
802
803 struct dns_pkt *dpkt = (struct dns_pkt *) answer->pkt.data;
804
805 dpkt->s.id = id;
806 dpkt->s.aa = 1;
807 dpkt->s.qr = 1;
808 dpkt->s.ra = 1;
809 dpkt->s.qdcount = htons (1);
810 dpkt->s.ancount = htons (1);
811
812 memcpy (dpkt->data, query_states[id].name, query_states[id].namelen);
813 GNUNET_free (query_states[id].name);
814 query_states[id].name = NULL;
815
816 struct dns_query_line *dque =
817 (struct dns_query_line *) (dpkt->data + (query_states[id].namelen));
818 dque->type = htons (28); /* AAAA */
819 dque->class = htons (1); /* IN */
820
821 char *anname =
822 (char *) (dpkt->data + (query_states[id].namelen) +
823 sizeof (struct dns_query_line));
824 memcpy (anname, "\xc0\x0c", 2);
825
826 struct dns_record_line *drec_data =
827 (struct dns_record_line *) (dpkt->data + (query_states[id].namelen) +
828 sizeof (struct dns_query_line) + 2);
829 drec_data->type = htons (28); /* AAAA */
830 drec_data->class = htons (1); /* IN */
831
832 /* FIXME: read the TTL from block:
833 * GNUNET_TIME_absolute_get_remaining(rec->expiration_time)
834 *
835 * But how to get the seconds out of this?
836 */
837 drec_data->ttl = htonl (3600);
838 drec_data->data_len = htons (16);
839
840 /* Calculate at which offset in the packet the IPv6-Address belongs, it is
841 * filled in by the daemon-vpn */
842 answer->pkt.addroffset =
843 htons ((unsigned short) ((unsigned long) (&drec_data->data) -
844 (unsigned long) (&answer->pkt)));
845
846 GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
847
848 if (server_notify == NULL)
849 server_notify =
850 GNUNET_SERVER_notify_transmit_ready (answer->client, len,
851 GNUNET_TIME_UNIT_FOREVER_REL,
852 &send_answer, NULL);
853}
854
855/**
856 * This receives a GNUNET_MESSAGE_TYPE_REHIJACK and rehijacks the DNS
857 */
858static void
859rehijack (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
860 const struct GNUNET_MessageHeader *message GNUNET_UNUSED)
861{
862 unhijack (dnsoutport);
863 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL);
864
865 GNUNET_SERVER_receive_done (client, GNUNET_OK);
866}
867
868/**
869 * This receives the dns-payload from the daemon-vpn and sends it on over the udp-socket
870 */
871static void
872receive_query (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client,
873 const struct GNUNET_MessageHeader *message)
874{
875 struct query_packet *pkt = (struct query_packet *) message;
876 struct dns_pkt *dns = (struct dns_pkt *) pkt->data;
877 struct dns_pkt_parsed *pdns = parse_dns_packet (dns);
878
879 query_states[dns->s.id].valid = GNUNET_YES;
880 query_states[dns->s.id].client = client;
881 GNUNET_SERVER_client_keep (client);
882 memcpy (query_states[dns->s.id].local_ip, pkt->orig_from, pkt->addrlen);
883 query_states[dns->s.id].addrlen = pkt->addrlen;
884 query_states[dns->s.id].local_port = pkt->src_port;
885 memcpy (query_states[dns->s.id].remote_ip, pkt->orig_to, pkt->addrlen);
886 query_states[dns->s.id].namelen = strlen ((char *) dns->data) + 1;
887 if (query_states[dns->s.id].name != NULL)
888 GNUNET_free (query_states[dns->s.id].name);
889 query_states[dns->s.id].name =
890 GNUNET_malloc (query_states[dns->s.id].namelen);
891 memcpy (query_states[dns->s.id].name, dns->data,
892 query_states[dns->s.id].namelen);
893
894 int i;
895
896 for (i = 0; i < ntohs (pdns->s.qdcount); i++)
897 {
898 if (pdns->queries[i]->qtype == htons (28) ||
899 pdns->queries[i]->qtype == htons (1))
900 {
901 query_states[dns->s.id].qtype = pdns->queries[i]->qtype;
902 break;
903 }
904 }
905
906 /* The query is for a .gnunet-address */
907 if (pdns->queries[0]->namelen > 9 &&
908 0 == strncmp (pdns->queries[0]->name + (pdns->queries[0]->namelen - 9),
909 ".gnunet.", 9))
910 {
911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for .gnunet!\n");
912 GNUNET_HashCode key;
913
914 GNUNET_CRYPTO_hash (pdns->queries[0]->name, pdns->queries[0]->namelen,
915 &key);
916
917 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Getting with key %08x, len is %d\n",
918 *((unsigned int *) &key), pdns->queries[0]->namelen);
919
920 struct receive_dht_cls *cls =
921 GNUNET_malloc (sizeof (struct receive_dht_cls));
922 cls->id = dns->s.id;
923
924 cls->handle =
925 GNUNET_DHT_get_start (dht, GNUNET_TIME_UNIT_MINUTES,
926 GNUNET_BLOCK_TYPE_DNS, &key,
927 5 /* DEFAULT_GET_REPLICATION */ ,
928 GNUNET_DHT_RO_NONE, NULL, 0, &receive_dht, cls);
929
930 goto outfree;
931 }
932
933 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Query for '%s'; namelen=%d\n",
934 pdns->queries[0]->name, pdns->queries[0]->namelen);
935
936 /* This is a PTR-Query. Check if it is for "our" network */
937 if (htons (pdns->queries[0]->qtype) == 12 && 74 == pdns->queries[0]->namelen)
938 {
939 char *ipv6addr;
940 char ipv6[16];
941 char ipv6rev[74] =
942 "X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.X.ip6.arpa.";
943 unsigned int i;
944 unsigned long long ipv6prefix;
945 unsigned int comparelen;
946
947 GNUNET_assert (GNUNET_OK ==
948 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn",
949 "IPV6ADDR",
950 &ipv6addr));
951 inet_pton (AF_INET6, ipv6addr, ipv6);
952 GNUNET_free (ipv6addr);
953
954 GNUNET_assert (GNUNET_OK ==
955 GNUNET_CONFIGURATION_get_value_number (cfg, "vpn",
956 "IPV6PREFIX",
957 &ipv6prefix));
958 GNUNET_assert (ipv6prefix < 127);
959 ipv6prefix = (ipv6prefix + 7) / 8;
960
961 for (i = ipv6prefix; i < 16; i++)
962 ipv6[i] = 0;
963
964 for (i = 0; i < 16; i++)
965 {
966 unsigned char c1 = ipv6[i] >> 4;
967 unsigned char c2 = ipv6[i] & 0xf;
968
969 if (c1 <= 9)
970 ipv6rev[62 - (4 * i)] = c1 + '0';
971 else
972 ipv6rev[62 - (4 * i)] = c1 + 87; /* 87 is the difference between 'a' and 10 */
973
974 if (c2 <= 9)
975 ipv6rev[62 - ((4 * i) + 2)] = c2 + '0';
976 else
977 ipv6rev[62 - ((4 * i) + 2)] = c2 + 87;
978 }
979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "My network is %s'.\n", ipv6rev);
980 comparelen = 10 + 4 * ipv6prefix;
981 if (0 ==
982 strncmp (pdns->queries[0]->name +
983 (pdns->queries[0]->namelen - comparelen),
984 ipv6rev + (74 - comparelen), comparelen))
985 {
986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Reverse-Query for .gnunet!\n");
987
988 GNUNET_SCHEDULER_add_now (send_rev_query, pdns);
989
990 goto out;
991 }
992 }
993
994 unsigned char virt_dns_bytes[16];
995
996 if (pkt->addrlen == 4)
997 {
998 char *virt_dns;
999
1000 if (GNUNET_SYSERR ==
1001 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS",
1002 &virt_dns))
1003 {
1004 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1005 "No entry 'VIRTDNS' in configuration!\n");
1006 exit (1);
1007 }
1008
1009 if (1 != inet_pton (AF_INET, virt_dns, &virt_dns_bytes))
1010 {
1011 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Error parsing 'VIRTDNS': %s; %m!\n",
1012 virt_dns);
1013 exit (1);
1014 }
1015
1016 GNUNET_free (virt_dns);
1017 }
1018 else if (pkt->addrlen == 16)
1019 {
1020 char *virt_dns;
1021
1022 if (GNUNET_SYSERR ==
1023 GNUNET_CONFIGURATION_get_value_string (cfg, "vpn", "VIRTDNS6",
1024 &virt_dns))
1025 {
1026 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1027 "No entry 'VIRTDNS6' in configuration!\n");
1028 exit (1);
1029 }
1030
1031 if (1 != inet_pton (AF_INET6, virt_dns, &virt_dns_bytes))
1032 {
1033 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1034 "Error parsing 'VIRTDNS6': %s; %m!\n", virt_dns);
1035 exit (1);
1036 }
1037
1038 GNUNET_free (virt_dns);
1039 }
1040 else
1041 {
1042 GNUNET_assert (0);
1043 }
1044
1045 if (memcmp (virt_dns_bytes, pkt->orig_to, pkt->addrlen) == 0)
1046 {
1047 /* This is a packet that was sent directly to the virtual dns-server
1048 *
1049 * This means we have to send this query over gnunet
1050 */
1051
1052 size_t size =
1053 sizeof (struct GNUNET_MESH_Tunnel *) +
1054 sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) -
1055 sizeof (struct query_packet) +
1056 1);
1057 struct tunnel_cls *cls_ = GNUNET_malloc (size);
1058
1059 cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *);
1060
1061 cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS);
1062 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size);
1063
1064 memcpy (&cls_->dns, dns,
1065 cls_->hdr.size - sizeof (struct GNUNET_MessageHeader));
1066 GNUNET_SCHEDULER_add_now (send_mesh_query, cls_);
1067
1068 if (ntohs (pdns->s.qdcount) == 1)
1069 {
1070 if (ntohs (pdns->queries[0]->qtype) == 1)
1071 pdns->queries[0]->qtype = htons (28);
1072 else if (ntohs (pdns->queries[0]->qtype) == 28)
1073 pdns->queries[0]->qtype = htons (1);
1074 else
1075 {
1076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "not sending second packet\n");
1077 goto outfree;
1078 }
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending second packet\n");
1080 struct dns_pkt *rdns = unparse_dns_packet (pdns);
1081 size_t size =
1082 sizeof (struct GNUNET_MESH_Tunnel *) +
1083 sizeof (struct GNUNET_MessageHeader) + (ntohs (message->size) -
1084 sizeof (struct query_packet) +
1085 1);
1086 struct tunnel_cls *cls_ = GNUNET_malloc (size);
1087
1088 cls_->hdr.size = size - sizeof (struct GNUNET_MESH_Tunnel *);
1089
1090 cls_->hdr.type = ntohs (GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS);
1091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "size: %d\n", size);
1092
1093 memcpy (&cls_->dns, rdns,
1094 cls_->hdr.size - sizeof (struct GNUNET_MessageHeader));
1095 GNUNET_SCHEDULER_add_now (send_mesh_query, cls_);
1096 GNUNET_free (rdns);
1097 }
1098
1099 goto outfree;
1100 }
1101
1102
1103 /* The query should be sent to the network */
1104 if (pkt->addrlen == 4)
1105 {
1106 struct sockaddr_in dest;
1107
1108 memset (&dest, 0, sizeof dest);
1109 dest.sin_port = htons (53);
1110 memcpy (&dest.sin_addr.s_addr, pkt->orig_to, pkt->addrlen);
1111
1112 GNUNET_NETWORK_socket_sendto (dnsout, dns,
1113 ntohs (pkt->hdr.size) -
1114 sizeof (struct query_packet) + 1,
1115 (struct sockaddr *) &dest, sizeof dest);
1116 }
1117 else if (pkt->addrlen == 16)
1118 {
1119 struct sockaddr_in6 dest;
1120
1121 memset (&dest, 0, sizeof dest);
1122 dest.sin6_port = htons (53);
1123 memcpy (&dest.sin6_addr, pkt->orig_to, pkt->addrlen);
1124
1125 GNUNET_NETWORK_socket_sendto (dnsout6, dns,
1126 ntohs (pkt->hdr.size) -
1127 sizeof (struct query_packet) + 1,
1128 (struct sockaddr *) &dest, sizeof dest);
1129 }
1130
1131outfree:
1132 free_parsed_dns_packet (pdns);
1133 pdns = NULL;
1134out:
1135 GNUNET_SERVER_receive_done (client, GNUNET_OK);
1136}
1137
1138static void
1139read_response (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1140
1141static void
1142read_response6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
1143
1144static int
1145open_port6 ()
1146{
1147 struct sockaddr_in6 addr;
1148
1149 dnsout6 = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_DGRAM, 0);
1150 if (dnsout6 == NULL)
1151 {
1152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create socket: %m\n");
1153 return GNUNET_SYSERR;
1154 }
1155 memset (&addr, 0, sizeof (struct sockaddr_in6));
1156
1157 addr.sin6_family = AF_INET6;
1158 int err = GNUNET_NETWORK_socket_bind (dnsout6,
1159 (struct sockaddr *) &addr,
1160 sizeof (struct sockaddr_in6));
1161
1162 if (err != GNUNET_OK)
1163 {
1164 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n");
1165 return GNUNET_SYSERR;
1166 }
1167
1168 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6,
1169 &read_response6, NULL);
1170
1171 return GNUNET_YES;
1172}
1173
1174static int
1175open_port ()
1176{
1177 struct sockaddr_in addr;
1178
1179 dnsout = GNUNET_NETWORK_socket_create (AF_INET, SOCK_DGRAM, 0);
1180 if (dnsout == NULL)
1181 return GNUNET_SYSERR;
1182 memset (&addr, 0, sizeof (struct sockaddr_in));
1183
1184 addr.sin_family = AF_INET;
1185 int err = GNUNET_NETWORK_socket_bind (dnsout,
1186 (struct sockaddr *) &addr,
1187 sizeof (struct sockaddr_in));
1188
1189 if (err != GNUNET_OK)
1190 {
1191 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not bind a port: %m\n");
1192 return GNUNET_SYSERR;
1193 }
1194
1195 /* Read the port we bound to */
1196 socklen_t addrlen = sizeof (struct sockaddr_in);
1197
1198 err =
1199 getsockname (GNUNET_NETWORK_get_fd (dnsout), (struct sockaddr *) &addr,
1200 &addrlen);
1201
1202 dnsoutport = htons (addr.sin_port);
1203
1204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to port %d.\n", dnsoutport);
1205
1206 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout,
1207 &read_response, NULL);
1208
1209 return GNUNET_YES;
1210}
1211
1212void
1213handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen,
1214 int r);
1215
1216/**
1217 * Read a response-packet of the UDP-Socket
1218 */
1219static void
1220read_response6 (void *cls GNUNET_UNUSED,
1221 const struct GNUNET_SCHEDULER_TaskContext *tc)
1222{
1223 struct sockaddr_in6 addr;
1224 socklen_t addrlen = sizeof (addr);
1225 int r;
1226 int len;
1227
1228 if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
1229 return;
1230
1231 memset (&addr, 0, sizeof addr);
1232
1233#ifndef MINGW
1234 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout6), FIONREAD, &len))
1235 {
1236 (void) open_port6 ();
1237 return;
1238 }
1239#else
1240 /* port the code above? */
1241 len = 65536;
1242#endif
1243
1244 unsigned char buf[len];
1245 struct dns_pkt *dns = (struct dns_pkt *) buf;
1246
1247 r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf),
1248 (struct sockaddr *) &addr, &addrlen);
1249
1250 if (r < 0)
1251 {
1252 (void) open_port6 ();
1253 return;
1254 }
1255
1256 struct sockaddr *addr_ = GNUNET_malloc (sizeof addr);
1257
1258 memcpy (addr_, &addr, sizeof addr);
1259 handle_response (dns, addr_, 4, r);
1260
1261 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout6,
1262 &read_response6, NULL);
1263}
1264
1265/**
1266 * Read a response-packet of the UDP-Socket
1267 */
1268static void
1269read_response (void *cls GNUNET_UNUSED,
1270 const struct GNUNET_SCHEDULER_TaskContext *tc)
1271{
1272 struct sockaddr_in addr;
1273 socklen_t addrlen = sizeof (addr);
1274 int r;
1275 int len;
1276
1277 if (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)
1278 return;
1279
1280 memset (&addr, 0, sizeof addr);
1281
1282#ifndef MINGW
1283 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
1284 {
1285 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "ioctl");
1286 unhijack (dnsoutport);
1287 if (GNUNET_YES == open_port ())
1288 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL);
1289 return;
1290 }
1291#else
1292 /* port the code above? */
1293 len = 65536;
1294#endif
1295
1296 unsigned char buf[len];
1297 struct dns_pkt *dns = (struct dns_pkt *) buf;
1298
1299 r = GNUNET_NETWORK_socket_recvfrom (dnsout, buf, sizeof (buf),
1300 (struct sockaddr *) &addr, &addrlen);
1301
1302 if (r < 0)
1303 {
1304 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
1305 unhijack (dnsoutport);
1306 if (GNUNET_YES == open_port ())
1307 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &hijack, NULL);
1308 return;
1309 }
1310
1311 struct sockaddr *addr_ = GNUNET_malloc (sizeof addr);
1312
1313 memcpy (addr_, &addr, sizeof addr);
1314 handle_response (dns, addr_, 4, r);
1315
1316 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, dnsout,
1317 &read_response, NULL);
1318}
1319
1320void
1321handle_response (struct dns_pkt *dns, struct sockaddr *addr, socklen_t addrlen,
1322 int r)
1323{
1324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Answer to query %d\n",
1325 ntohs (dns->s.id));
1326
1327
1328 if (query_states[dns->s.id].valid == GNUNET_YES)
1329 {
1330 if (query_states[dns->s.id].tunnel != NULL)
1331 {
1332 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1333 "Answer to query %d for a remote peer!\n", ntohs (dns->s.id));
1334 /* This response should go through a tunnel */
1335 uint32_t *c =
1336 GNUNET_malloc (4 + sizeof (struct GNUNET_MESH_Tunnel *) + r);
1337 *c = r;
1338 struct GNUNET_MESH_Tunnel **t = (struct GNUNET_MESH_Tunnel **) (c + 1);
1339
1340 *t = query_states[dns->s.id].tunnel;
1341 memcpy (t + 1, dns, r);
1342 struct tunnel_state *s =
1343 GNUNET_MESH_tunnel_get_data (query_states[dns->s.id].tunnel);
1344 if (NULL == s->th)
1345 {
1346 s->th =
1347 GNUNET_MESH_notify_transmit_ready (query_states[dns->s.id].tunnel,
1348 GNUNET_YES, 32,
1349 GNUNET_TIME_UNIT_MINUTES, NULL,
1350 r +
1351 sizeof (struct
1352 GNUNET_MessageHeader),
1353 mesh_send_response, c);
1354 }
1355 else
1356 {
1357 struct tunnel_notify_queue *element =
1358 GNUNET_malloc (sizeof (struct tunnel_notify_queue));
1359 element->cls = c;
1360 element->len = r + sizeof (struct GNUNET_MessageHeader);
1361 element->cb = mesh_send_response;
1362
1363 GNUNET_CONTAINER_DLL_insert_tail (s->head, s->tail, element);
1364 }
1365 }
1366 else
1367 {
1368 query_states[dns->s.id].valid = GNUNET_NO;
1369
1370 size_t len = sizeof (struct answer_packet) + r - 1; /* 1 for the unsigned char data[1]; */
1371 struct answer_packet_list *answer =
1372 GNUNET_malloc (len + sizeof (struct answer_packet_list) -
1373 (sizeof (struct answer_packet)));
1374 answer->pkt.hdr.type =
1375 htons (GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_RESPONSE_DNS);
1376 answer->pkt.hdr.size = htons (len);
1377 answer->pkt.subtype = GNUNET_DNS_ANSWER_TYPE_IP;
1378 answer->pkt.addrlen = addrlen;
1379 if (addrlen == 16)
1380 {
1381 struct sockaddr_in6 *addr_ = (struct sockaddr_in6 *) addr;
1382
1383 memcpy (answer->pkt.from, &addr_->sin6_addr, addrlen);
1384 memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen);
1385 }
1386 else if (addrlen == 4)
1387 {
1388 struct sockaddr_in *addr_ = (struct sockaddr_in *) addr;
1389
1390 memcpy (answer->pkt.from, &addr_->sin_addr.s_addr, addrlen);
1391 memcpy (answer->pkt.to, query_states[dns->s.id].local_ip, addrlen);
1392 }
1393 else
1394 {
1395 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "addrlen = %d\n", addrlen);
1396 GNUNET_assert (0);
1397 }
1398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sending answer with addrlen = %d\n",
1399 addrlen);
1400 answer->pkt.dst_port = query_states[dns->s.id].local_port;
1401 memcpy (answer->pkt.data, dns, r);
1402 answer->client = query_states[dns->s.id].client;
1403
1404 GNUNET_CONTAINER_DLL_insert_after (head, tail, tail, answer);
1405
1406 if (server_notify == NULL)
1407 server_notify =
1408 GNUNET_SERVER_notify_transmit_ready (query_states[dns->s.id].client,
1409 len,
1410 GNUNET_TIME_UNIT_FOREVER_REL,
1411 &send_answer, NULL);
1412 }
1413 }
1414 GNUNET_free (addr);
1415}
1416
1417
1418/**
1419 * Task run during shutdown.
1420 *
1421 * @param cls unused
1422 * @param tc unused
1423 */
1424static void
1425cleanup_task (void *cls GNUNET_UNUSED,
1426 const struct GNUNET_SCHEDULER_TaskContext *tc)
1427{
1428 GNUNET_assert (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN));
1429
1430 unhijack (dnsoutport);
1431 GNUNET_DHT_disconnect (dht);
1432 GNUNET_MESH_disconnect (mesh_handle);
1433}
1434
1435/**
1436 * @brief Create a port-map from udp and tcp redirects
1437 *
1438 * @param udp_redirects
1439 * @param tcp_redirects
1440 *
1441 * @return
1442 */
1443static uint64_t
1444get_port_from_redirects (const char *udp_redirects, const char *tcp_redirects)
1445{
1446 uint64_t ret = 0;
1447 char *cpy, *hostname, *redirect;
1448 int local_port;
1449 unsigned int count = 0;
1450
1451 cpy = NULL;
1452 if (NULL != udp_redirects)
1453 {
1454 cpy = GNUNET_strdup (udp_redirects);
1455 for (redirect = strtok (cpy, " "); redirect != NULL;
1456 redirect = strtok (NULL, " "))
1457 {
1458 if (NULL == (hostname = strstr (redirect, ":")))
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1461 "Warning: option %s is not formatted correctly!\n",
1462 redirect);
1463 continue;
1464 }
1465 hostname[0] = '\0';
1466 local_port = atoi (redirect);
1467 if (!((local_port > 0) && (local_port < 65536)))
1468 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1469 "Warning: %s is not a correct port.", redirect);
1470
1471 ret |= (0xFFFF & htons (local_port));
1472 ret <<= 16;
1473 count++;
1474
1475 if (count > 4)
1476 {
1477 ret = 0;
1478 goto out;
1479 }
1480 }
1481 GNUNET_free (cpy);
1482 cpy = NULL;
1483 }
1484
1485 if (NULL != tcp_redirects)
1486 {
1487 cpy = GNUNET_strdup (tcp_redirects);
1488 for (redirect = strtok (cpy, " "); redirect != NULL;
1489 redirect = strtok (NULL, " "))
1490 {
1491 if (NULL == (hostname = strstr (redirect, ":")))
1492 {
1493 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1494 "Warning: option %s is not formatted correctly!\n",
1495 redirect);
1496 continue;
1497 }
1498 hostname[0] = '\0';
1499 local_port = atoi (redirect);
1500 if (!((local_port > 0) && (local_port < 65536)))
1501 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1502 "Warning: %s is not a correct port.", redirect);
1503
1504 ret |= (0xFFFF & htons (local_port));
1505 ret <<= 16;
1506 count++;
1507
1508 if (count > 4)
1509 {
1510 ret = 0;
1511 goto out;
1512 }
1513 }
1514 GNUNET_free (cpy);
1515 cpy = NULL;
1516 }
1517
1518out:
1519 GNUNET_free_non_null (cpy);
1520 return ret;
1521}
1522
1523static void
1524publish_name (const char *name, uint64_t ports, uint32_t service_type,
1525 struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key)
1526{
1527 size_t size = sizeof (struct GNUNET_DNS_Record);
1528 struct GNUNET_DNS_Record data;
1529
1530 memset (&data, 0, size);
1531
1532 data.purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
1533 data.purpose.purpose = GNUNET_SIGNATURE_PURPOSE_DNS_RECORD;
1534
1535 GNUNET_CRYPTO_hash (name, strlen (name) + 1, &data.service_descriptor);
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Store with key1 %x\n",
1537 *((unsigned long long *) &data.service_descriptor));
1538
1539 data.service_type = service_type;
1540 data.ports = ports;
1541
1542 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &data.peer);
1543
1544 data.expiration_time =
1545 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute
1546 (GNUNET_TIME_relative_multiply
1547 (GNUNET_TIME_UNIT_HOURS, 2)));
1548
1549 /* Sign the block */
1550 if (GNUNET_OK !=
1551 GNUNET_CRYPTO_rsa_sign (my_private_key, &data.purpose, &data.signature))
1552 {
1553 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not sign DNS_Record\n");
1554 return;
1555 }
1556
1557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Putting with key %08x, size = %d\n",
1558 *((unsigned int *) &data.service_descriptor), size);
1559
1560 GNUNET_DHT_put (dht, &data.service_descriptor,
1561 5 /* DEFAULT_PUT_REPLICATION */ ,
1562 GNUNET_DHT_RO_NONE, GNUNET_BLOCK_TYPE_DNS, size,
1563 (char *) &data,
1564 GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_HOURS),
1565 GNUNET_TIME_UNIT_MINUTES, NULL, NULL);
1566}
1567
1568
1569/**
1570 * @brief Publishes the record defined by the section section
1571 *
1572 * @param cls closure
1573 * @param section the current section
1574 */
1575static void
1576publish_iterate (void *cls GNUNET_UNUSED, const char *section)
1577{
1578 char *udp_redirects;
1579 char *tcp_redirects;
1580 char *alternative_names;
1581 char *alternative_name;
1582 char *keyfile;
1583
1584 if ((strlen (section) < 8) ||
1585 (0 != strcmp (".gnunet.", section + (strlen (section) - 8))))
1586 return;
1587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Parsing dns-name %s\n", section);
1588 if (GNUNET_OK !=
1589 GNUNET_CONFIGURATION_get_value_string (cfg, section, "UDP_REDIRECTS",
1590 &udp_redirects))
1591 udp_redirects = NULL;
1592 if (GNUNET_OK !=
1593 GNUNET_CONFIGURATION_get_value_string (cfg, section, "TCP_REDIRECTS",
1594 &tcp_redirects))
1595 tcp_redirects = NULL;
1596
1597 if (GNUNET_OK !=
1598 GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY",
1599 &keyfile))
1600 {
1601 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "could not read keyfile-value\n");
1602 if (keyfile != NULL)
1603 GNUNET_free (keyfile);
1604 return;
1605 }
1606
1607 struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key =
1608 GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1609 GNUNET_free (keyfile);
1610 GNUNET_assert (my_private_key != NULL);
1611
1612 uint64_t ports = get_port_from_redirects (udp_redirects, tcp_redirects);
1613 uint32_t service_type = 0;
1614
1615 if (NULL != udp_redirects)
1616 service_type = GNUNET_DNS_SERVICE_TYPE_UDP;
1617
1618 if (NULL != tcp_redirects)
1619 service_type |= GNUNET_DNS_SERVICE_TYPE_TCP;
1620
1621 service_type = htonl (service_type);
1622
1623
1624 publish_name (section, ports, service_type, my_private_key);
1625 if (GNUNET_OK ==
1626 GNUNET_CONFIGURATION_get_value_string (cfg, section, "ALTERNATIVE_NAMES",
1627 &alternative_names))
1628 {
1629 for (alternative_name = strtok (alternative_names, " ");
1630 alternative_name != NULL; alternative_name = strtok (NULL, " "))
1631 {
1632 char *altname =
1633 alloca (strlen (alternative_name) + strlen (section) + 1 + 1);
1634 strcpy (altname, alternative_name);
1635 strcpy (altname + strlen (alternative_name) + 1, section);
1636 altname[strlen (alternative_name)] = '.';
1637
1638 publish_name (altname, ports, service_type, my_private_key);
1639 }
1640 GNUNET_free (alternative_names);
1641 }
1642 GNUNET_CRYPTO_rsa_key_free (my_private_key);
1643 GNUNET_free_non_null (udp_redirects);
1644 GNUNET_free_non_null (tcp_redirects);
1645}
1646
1647/**
1648 * Publish a DNS-record in the DHT.
1649 */
1650static void
1651publish_names (void *cls GNUNET_UNUSED,
1652 const struct GNUNET_SCHEDULER_TaskContext *tc)
1653{
1654 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1655 return;
1656
1657 GNUNET_CONFIGURATION_iterate_sections (cfg, &publish_iterate, NULL);
1658
1659 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_HOURS, &publish_names, NULL);
1660}
1661
1662/**
1663 * @param cls closure
1664 * @param server the initialized server
1665 * @param cfg_ configuration to use
1666 */
1667static void
1668run (void *cls, struct GNUNET_SERVER_Handle *server,
1669 const struct GNUNET_CONFIGURATION_Handle *cfg_)
1670{
1671 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1672 /* callback, cls, type, size */
1673 {&receive_query, NULL, GNUNET_MESSAGE_TYPE_VPN_DNS_LOCAL_QUERY_DNS, 0},
1674 {&rehijack, NULL, GNUNET_MESSAGE_TYPE_REHIJACK,
1675 sizeof (struct GNUNET_MessageHeader)},
1676 {NULL, NULL, 0, 0}
1677 };
1678
1679 static const struct GNUNET_MESH_MessageHandler mesh_handlers[] = {
1680 {receive_mesh_query, GNUNET_MESSAGE_TYPE_VPN_REMOTE_QUERY_DNS, 0},
1681 {receive_mesh_answer, GNUNET_MESSAGE_TYPE_VPN_REMOTE_ANSWER_DNS, 0},
1682 {NULL, 0, 0}
1683 };
1684
1685 static GNUNET_MESH_ApplicationType apptypes[] = {
1686 GNUNET_APPLICATION_TYPE_END,
1687 GNUNET_APPLICATION_TYPE_END
1688 };
1689
1690 if (GNUNET_YES != open_port6 ())
1691 {
1692 GNUNET_SCHEDULER_shutdown ();
1693 return;
1694 }
1695
1696 if (GNUNET_YES != open_port ())
1697 {
1698 GNUNET_SCHEDULER_shutdown ();
1699 return;
1700 }
1701
1702 if (GNUNET_YES ==
1703 GNUNET_CONFIGURATION_get_value_yesno (cfg_, "dns", "PROVIDE_EXIT"))
1704 apptypes[0] = GNUNET_APPLICATION_TYPE_INTERNET_RESOLVER;
1705 mesh_handle =
1706 GNUNET_MESH_connect (cfg_, 42, NULL, new_tunnel, clean_tunnel,
1707 mesh_handlers, apptypes);
1708
1709 cfg = cfg_;
1710 dht = GNUNET_DHT_connect (cfg, 1024);
1711 GNUNET_SCHEDULER_add_now (publish_names, NULL);
1712 GNUNET_SERVER_add_handlers (server, handlers);
1713 GNUNET_SERVER_disconnect_notify (server, &client_disconnect, NULL);
1714 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task,
1715 cls);
1716}
1717
1718/**
1719 * The main function for the dns service.
1720 *
1721 * @param argc number of arguments from the command line
1722 * @param argv command line arguments
1723 * @return 0 ok, 1 on error
1724 */
1725int
1726main (int argc, char *const *argv)
1727{
1728 return (GNUNET_OK ==
1729 GNUNET_SERVICE_run (argc, argv, "dns", GNUNET_SERVICE_OPTION_NONE,
1730 &run, NULL)) ? 0 : 1;
1731}