aboutsummaryrefslogtreecommitdiff
path: root/src/service/gns/gnunet-dns2gns.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/gns/gnunet-dns2gns.c')
-rw-r--r--src/service/gns/gnunet-dns2gns.c1024
1 files changed, 1024 insertions, 0 deletions
diff --git a/src/service/gns/gnunet-dns2gns.c b/src/service/gns/gnunet-dns2gns.c
new file mode 100644
index 000000000..04d320c62
--- /dev/null
+++ b/src/service/gns/gnunet-dns2gns.c
@@ -0,0 +1,1024 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012-2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file gnunet-dns2gns.c
22 * @brief DNS server that translates DNS requests to GNS
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <gnunet_util_lib.h>
27#include <gnunet_gns_service.h>
28#include "gnunet_vpn_service.h"
29#include "gns.h"
30
31/**
32 * Timeout for DNS requests.
33 */
34#define TIMEOUT GNUNET_TIME_UNIT_MINUTES
35
36/**
37 * Default timeout for VPN redirections.
38 */
39#define VPN_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 30)
40
41
42struct Request;
43
44/**
45 * Closure for #vpn_allocation_cb.
46 */
47struct VpnContext
48{
49 /**
50 * Which resolution process are we processing.
51 */
52 struct Request *request;
53
54 /**
55 * Handle to the VPN request that we were performing.
56 */
57 struct GNUNET_VPN_RedirectionRequest *vpn_request;
58
59 /**
60 * Number of records serialized in @e rd_data.
61 */
62 unsigned int rd_count;
63
64 /**
65 * Serialized records.
66 */
67 char *rd_data;
68
69 /**
70 * Number of bytes in @e rd_data.
71 */
72 ssize_t rd_data_size;
73};
74
75
76/**
77 * Data kept per request.
78 */
79struct Request
80{
81 /**
82 * Socket to use for sending the reply.
83 */
84 struct GNUNET_NETWORK_Handle *lsock;
85
86 /**
87 * Destination address to use.
88 */
89 const void *addr;
90
91 /**
92 * Initially, this is the DNS request, it will then be
93 * converted to the DNS response.
94 */
95 struct GNUNET_DNSPARSER_Packet *packet;
96
97 /**
98 * Our GNS request handle.
99 */
100 struct GNUNET_GNS_LookupWithTldRequest *lookup;
101
102 /**
103 * Our DNS request handle
104 */
105 struct GNUNET_DNSSTUB_RequestSocket *dns_lookup;
106
107 /**
108 * Task run on timeout or shutdown to clean up without
109 * response.
110 */
111 struct GNUNET_SCHEDULER_Task *timeout_task;
112
113 /**
114 * Vpn resulution context
115 */
116 struct VpnContext *vpn_ctx;
117
118 /**
119 * Original UDP request message.
120 */
121 char *udp_msg;
122
123 /**
124 * Number of bytes in @e addr.
125 */
126 size_t addr_len;
127
128 /**
129 * Number of bytes in @e udp_msg.
130 */
131 size_t udp_msg_size;
132
133 /**
134 * ID of the original request.
135 */
136 uint16_t original_request_id;
137
138};
139
140/**
141 * The address to bind to
142 */
143static in_addr_t address;
144
145/**
146 * The IPv6 address to bind to
147 */
148static struct in6_addr address6;
149
150
151/**
152 * Handle to GNS resolver.
153 */
154struct GNUNET_GNS_Handle *gns;
155
156/**
157 * Our handle to the vpn service
158 */
159static struct GNUNET_VPN_Handle *vpn_handle;
160
161/**
162 * Stub resolver
163 */
164struct GNUNET_DNSSTUB_Context *dns_stub;
165
166/**
167 * Listen socket for IPv4.
168 */
169static struct GNUNET_NETWORK_Handle *listen_socket4;
170
171/**
172 * Listen socket for IPv6.
173 */
174static struct GNUNET_NETWORK_Handle *listen_socket6;
175
176/**
177 * Task for IPv4 socket.
178 */
179static struct GNUNET_SCHEDULER_Task *t4;
180
181/**
182 * Task for IPv6 socket.
183 */
184static struct GNUNET_SCHEDULER_Task *t6;
185
186/**
187 * IP of DNS server
188 */
189static char *dns_ip;
190
191/**
192 * UDP Port we listen on for inbound DNS requests.
193 */
194static unsigned long long listen_port = 53;
195
196/**
197 * Configuration to use.
198 */
199static const struct GNUNET_CONFIGURATION_Handle *cfg;
200
201
202/**
203 * Task run on shutdown. Cleans up everything.
204 *
205 * @param cls unused
206 */
207static void
208do_shutdown (void *cls)
209{
210 (void) cls;
211 if (NULL != t4)
212 {
213 GNUNET_SCHEDULER_cancel (t4);
214 t4 = NULL;
215 }
216 if (NULL != t6)
217 {
218 GNUNET_SCHEDULER_cancel (t6);
219 t6 = NULL;
220 }
221 if (NULL != listen_socket4)
222 {
223 GNUNET_NETWORK_socket_close (listen_socket4);
224 listen_socket4 = NULL;
225 }
226 if (NULL != listen_socket6)
227 {
228 GNUNET_NETWORK_socket_close (listen_socket6);
229 listen_socket6 = NULL;
230 }
231 if (NULL != gns)
232 {
233 GNUNET_GNS_disconnect (gns);
234 gns = NULL;
235 }
236 if (NULL != vpn_handle)
237 {
238 GNUNET_VPN_disconnect (vpn_handle);
239 vpn_handle = NULL;
240 }
241 if (NULL != dns_stub)
242 {
243 GNUNET_DNSSTUB_stop (dns_stub);
244 dns_stub = NULL;
245 }
246}
247
248
249/**
250 * Shuffle answers
251 * Fisher-Yates (aka Knuth) Shuffle
252 *
253 * @param request context for the request (with answers)
254 */
255static void
256shuffle_answers (struct Request *request)
257{
258 unsigned int idx = request->packet->num_answers;
259 unsigned int r_idx;
260 struct GNUNET_DNSPARSER_Record tmp_answer;
261
262 while (0 != idx)
263 {
264 r_idx = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
265 request->packet->num_answers);
266 idx--;
267 tmp_answer = request->packet->answers[idx];
268 memcpy (&request->packet->answers[idx], &request->packet->answers[r_idx],
269 sizeof (struct GNUNET_DNSPARSER_Record));
270 memcpy (&request->packet->answers[r_idx], &tmp_answer,
271 sizeof (struct GNUNET_DNSPARSER_Record));
272 }
273}
274
275
276/**
277 * Send the response for the given request and clean up.
278 *
279 * @param request context for the request.
280 */
281static void
282send_response (struct Request *request)
283{
284 char *buf;
285 size_t size;
286 ssize_t sret;
287
288 shuffle_answers (request);
289 if (GNUNET_SYSERR ==
290 GNUNET_DNSPARSER_pack (request->packet,
291 UINT16_MAX /* is this not too much? */,
292 &buf,
293 &size))
294 {
295 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
296 _ ("Failed to pack DNS response into UDP packet!\n"));
297 }
298 else
299 {
300 sret = GNUNET_NETWORK_socket_sendto (request->lsock,
301 buf,
302 size,
303 request->addr,
304 request->addr_len);
305 if ((sret < 0) ||
306 (size != (size_t) sret))
307 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
308 "sendto");
309 GNUNET_free (buf);
310 }
311 GNUNET_SCHEDULER_cancel (request->timeout_task);
312 GNUNET_DNSPARSER_free_packet (request->packet);
313 GNUNET_free (request->udp_msg);
314 GNUNET_free (request);
315}
316
317
318/**
319 * Task run on timeout. Cleans up request.
320 *
321 * @param cls `struct Request *` of the request to clean up
322 */
323static void
324do_timeout (void *cls)
325{
326 struct Request *request = cls;
327 struct VpnContext *vpn_ctx;
328
329 if (NULL != request->packet)
330 GNUNET_DNSPARSER_free_packet (request->packet);
331 if (NULL != request->lookup)
332 GNUNET_GNS_lookup_with_tld_cancel (request->lookup);
333 if (NULL != request->dns_lookup)
334 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
335 GNUNET_free (request->udp_msg);
336 if (NULL != (vpn_ctx = request->vpn_ctx))
337 {
338 GNUNET_VPN_cancel_request (vpn_ctx->vpn_request);
339 GNUNET_free (vpn_ctx->rd_data);
340 GNUNET_free (vpn_ctx);
341 }
342 GNUNET_free (request);
343}
344
345
346/**
347 * Iterator called on obtained result for a DNS lookup
348 *
349 * @param cls closure
350 * @param dns the DNS udp payload
351 * @param r size of the DNS payload
352 */
353static void
354dns_result_processor (void *cls,
355 const struct GNUNET_TUN_DnsHeader *dns,
356 size_t r)
357{
358 struct Request *request = cls;
359
360 if (NULL == dns)
361 {
362 /* DNSSTUB gave up, so we trigger timeout early */
363 GNUNET_SCHEDULER_cancel (request->timeout_task);
364 do_timeout (request);
365 return;
366 }
367 if (request->original_request_id != dns->id)
368 {
369 /* for a another query, ignore */
370 return;
371 }
372 request->packet = GNUNET_DNSPARSER_parse ((char *) dns,
373 r);
374 if (NULL == request->packet)
375 {
376 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
377 _ ("Failed to parse DNS response!\n"));
378 GNUNET_SCHEDULER_cancel (request->timeout_task);
379 do_timeout (request);
380 return;
381 }
382 GNUNET_DNSSTUB_resolve_cancel (request->dns_lookup);
383 send_response (request);
384}
385
386/**
387 * Callback invoked from the VPN service once a redirection is
388 * available. Provides the IP address that can now be used to
389 * reach the requested destination. Replaces the "VPN" record
390 * with the respective A/AAAA record and continues processing.
391 *
392 * @param cls closure
393 * @param af address family, AF_INET or AF_INET6; AF_UNSPEC on error;
394 * will match 'result_af' from the request
395 * @param address IP address (struct in_addr or struct in_addr6, depending on 'af')
396 * that the VPN allocated for the redirection;
397 * traffic to this IP will now be redirected to the
398 * specified target peer; NULL on error
399 */
400static void
401vpn_allocation_cb (void *cls,
402 int af,
403 const void *address)
404{
405 struct VpnContext *vpn_ctx = cls;
406 struct Request *request = vpn_ctx->request;
407 struct GNUNET_GNSRECORD_Data rd[vpn_ctx->rd_count];
408 unsigned int i;
409
410 vpn_ctx->vpn_request = NULL;
411 request->vpn_ctx = NULL;
412 GNUNET_assert (GNUNET_OK ==
413 GNUNET_GNSRECORD_records_deserialize (
414 (size_t) vpn_ctx->rd_data_size,
415 vpn_ctx->rd_data,
416 vpn_ctx->rd_count,
417 rd));
418 for (i = 0; i < vpn_ctx->rd_count; i++)
419 {
420 if (GNUNET_GNSRECORD_TYPE_VPN == rd[i].record_type)
421 {
422 switch (af)
423 {
424 case AF_INET:
425 rd[i].record_type = GNUNET_DNSPARSER_TYPE_A;
426 rd[i].data_size = sizeof(struct in_addr);
427 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
428 VPN_TIMEOUT).abs_value_us;
429 rd[i].flags = 0;
430 rd[i].data = address;
431 break;
432
433 case AF_INET6:
434 rd[i].record_type = GNUNET_DNSPARSER_TYPE_AAAA;
435 rd[i].expiration_time = GNUNET_TIME_relative_to_absolute (
436 VPN_TIMEOUT).abs_value_us;
437 rd[i].flags = 0;
438 rd[i].data = address;
439 rd[i].data_size = sizeof(struct in6_addr);
440 break;
441
442 default:
443 GNUNET_assert (0);
444 }
445 break;
446 }
447 }
448 GNUNET_assert (i < vpn_ctx->rd_count);
449 if (0 == vpn_ctx->rd_count)
450 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
451 _ ("VPN returned empty result for `%s'\n"),
452 request->packet->queries[0].name);
453 send_response (request);
454 GNUNET_free (vpn_ctx->rd_data);
455 GNUNET_free (vpn_ctx);
456}
457
458
459
460/**
461 * Iterator called on obtained result for a GNS lookup.
462 *
463 * @param cls closure
464 * @param was_gns #GNUNET_NO if the TLD is not configured for GNS
465 * @param rd_count number of records in @a rd
466 * @param rd the records in reply
467 */
468static void
469result_processor (void *cls,
470 int was_gns,
471 uint32_t rd_count,
472 const struct GNUNET_GNSRECORD_Data *rd)
473{
474 struct Request *request = cls;
475 struct GNUNET_DNSPARSER_Packet *packet;
476 struct GNUNET_DNSPARSER_Record rec;
477 struct VpnContext *vpn_ctx;
478 const struct GNUNET_TUN_GnsVpnRecord *vpn;
479 const char *vname;
480 struct GNUNET_HashCode vhash;
481 int af;
482
483 request->lookup = NULL;
484 if (GNUNET_NO == was_gns)
485 {
486 /* TLD not configured for GNS, fall back to DNS */
487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
488 "Using DNS resolver IP `%s' to resolve `%s'\n",
489 dns_ip,
490 request->packet->queries[0].name);
491 request->original_request_id = request->packet->id;
492 GNUNET_DNSPARSER_free_packet (request->packet);
493 request->packet = NULL;
494 request->dns_lookup = GNUNET_DNSSTUB_resolve (dns_stub,
495 request->udp_msg,
496 request->udp_msg_size,
497 &dns_result_processor,
498 request);
499 return;
500 }
501 packet = request->packet;
502 packet->flags.query_or_response = 1;
503 packet->flags.return_code = GNUNET_TUN_DNS_RETURN_CODE_NO_ERROR;
504 packet->flags.checking_disabled = 0;
505 packet->flags.authenticated_data = 1;
506 packet->flags.zero = 0;
507 packet->flags.recursion_available = 1;
508 packet->flags.message_truncated = 0;
509 packet->flags.authoritative_answer = 0;
510 // packet->flags.opcode = GNUNET_TUN_DNS_OPCODE_STATUS; // ???
511 for (uint32_t i = 0; i < rd_count; i++)
512 {
513 rec.expiration_time.abs_value_us = rd[i].expiration_time;
514 switch (rd[i].record_type)
515 {
516 case GNUNET_DNSPARSER_TYPE_A:
517 GNUNET_assert (sizeof(struct in_addr) == rd[i].data_size);
518 rec.name = GNUNET_strdup (packet->queries[0].name);
519 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
520 rec.type = GNUNET_DNSPARSER_TYPE_A;
521 rec.data.raw.data = GNUNET_new (struct in_addr);
522 GNUNET_memcpy (rec.data.raw.data,
523 rd[i].data,
524 rd[i].data_size);
525 rec.data.raw.data_len = sizeof(struct in_addr);
526 GNUNET_array_append (packet->answers,
527 packet->num_answers,
528 rec);
529 break;
530
531 case GNUNET_DNSPARSER_TYPE_AAAA:
532 GNUNET_assert (sizeof(struct in6_addr) == rd[i].data_size);
533 rec.name = GNUNET_strdup (packet->queries[0].name);
534 rec.data.raw.data = GNUNET_new (struct in6_addr);
535 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
536 rec.type = GNUNET_DNSPARSER_TYPE_AAAA;
537 GNUNET_memcpy (rec.data.raw.data,
538 rd[i].data,
539 rd[i].data_size);
540 rec.data.raw.data_len = sizeof(struct in6_addr);
541 GNUNET_array_append (packet->answers,
542 packet->num_answers,
543 rec);
544 break;
545
546 case GNUNET_DNSPARSER_TYPE_CNAME:
547 rec.name = GNUNET_strdup (packet->queries[0].name);
548 rec.data.hostname = GNUNET_strdup (rd[i].data);
549 rec.dns_traffic_class = GNUNET_TUN_DNS_CLASS_INTERNET;
550 rec.type = GNUNET_DNSPARSER_TYPE_CNAME;
551 GNUNET_memcpy (rec.data.hostname,
552 rd[i].data,
553 rd[i].data_size);
554 GNUNET_array_append (packet->answers,
555 packet->num_answers,
556 rec);
557 break;
558 case GNUNET_GNSRECORD_TYPE_VPN:
559 if ((GNUNET_DNSPARSER_TYPE_A != request->packet->queries[0].type) &&
560 (GNUNET_DNSPARSER_TYPE_AAAA != request->packet->queries[0].type))
561 break;
562 af = (GNUNET_DNSPARSER_TYPE_A == request->packet->queries[0].type) ?
563 AF_INET :
564 AF_INET6;
565 if (sizeof(struct GNUNET_TUN_GnsVpnRecord) >
566 rd[i].data_size)
567 {
568 GNUNET_break_op (0);
569 break;
570 }
571 vpn = (const struct GNUNET_TUN_GnsVpnRecord *) rd[i].data;
572 vname = (const char *) &vpn[1];
573 if ('\0' != vname[rd[i].data_size - 1 - sizeof(struct
574 GNUNET_TUN_GnsVpnRecord)
575 ])
576 {
577 GNUNET_break_op (0);
578 break;
579 }
580 GNUNET_TUN_service_name_to_hash (vname,
581 &vhash);
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583 "Attempting VPN allocation for %s-%s (AF: %d, proto %d)\n",
584 GNUNET_i2s (&vpn->peer),
585 vname,
586 (int) af,
587 (int) ntohs (vpn->proto));
588 vpn_ctx = GNUNET_new (struct VpnContext);
589 request->vpn_ctx = vpn_ctx;
590 vpn_ctx->request = request;
591 vpn_ctx->rd_data_size = GNUNET_GNSRECORD_records_get_size (rd_count,
592 rd);
593 if (vpn_ctx->rd_data_size < 0)
594 {
595 GNUNET_break_op (0);
596 GNUNET_free (vpn_ctx);
597 break;
598 }
599 vpn_ctx->rd_data = GNUNET_malloc ((size_t) vpn_ctx->rd_data_size);
600 vpn_ctx->rd_count = rd_count;
601 GNUNET_assert (vpn_ctx->rd_data_size ==
602 GNUNET_GNSRECORD_records_serialize (rd_count,
603 rd,
604 (size_t) vpn_ctx
605 ->rd_data_size,
606 vpn_ctx->rd_data));
607 vpn_ctx->vpn_request = GNUNET_VPN_redirect_to_peer (vpn_handle,
608 af,
609 ntohs (
610 vpn->proto),
611 &vpn->peer,
612 &vhash,
613 GNUNET_TIME_relative_to_absolute (
614 VPN_TIMEOUT),
615 &
616 vpn_allocation_cb,
617 vpn_ctx);
618 return;
619
620
621 default:
622 /* skip */
623 break;
624 }
625 }
626 send_response (request);
627}
628
629
630/**
631 * Handle DNS request.
632 *
633 * @param lsock socket to use for sending the reply
634 * @param addr address to use for sending the reply
635 * @param addr_len number of bytes in @a addr
636 * @param udp_msg DNS request payload
637 * @param udp_msg_size number of bytes in @a udp_msg
638 */
639static void
640handle_request (struct GNUNET_NETWORK_Handle *lsock,
641 const void *addr,
642 size_t addr_len,
643 const char *udp_msg,
644 size_t udp_msg_size)
645{
646 struct Request *request;
647 struct GNUNET_DNSPARSER_Packet *packet;
648
649 packet = GNUNET_DNSPARSER_parse (udp_msg,
650 udp_msg_size);
651 if (NULL == packet)
652 {
653 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
654 _ ("Cannot parse DNS request from %s\n"),
655 GNUNET_a2s (addr, addr_len));
656 return;
657 }
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Received request for `%s' with flags %u, #answers %d, #auth %d, #additional %d\n",
660 packet->queries[0].name,
661 (unsigned int) packet->flags.query_or_response,
662 (int) packet->num_answers,
663 (int) packet->num_authority_records,
664 (int) packet->num_additional_records);
665 if ((0 != packet->flags.query_or_response) ||
666 (0 != packet->num_answers) ||
667 (0 != packet->num_authority_records))
668 {
669 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
670 _ ("Received malformed DNS request from %s\n"),
671 GNUNET_a2s (addr, addr_len));
672 GNUNET_DNSPARSER_free_packet (packet);
673 return;
674 }
675 if ((1 != packet->num_queries))
676 {
677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
678 _ ("Received unsupported DNS request from %s\n"),
679 GNUNET_a2s (addr,
680 addr_len));
681 GNUNET_DNSPARSER_free_packet (packet);
682 return;
683 }
684 request = GNUNET_malloc (sizeof(struct Request) + addr_len);
685 request->lsock = lsock;
686 request->packet = packet;
687 request->addr = &request[1];
688 request->addr_len = addr_len;
689 GNUNET_memcpy (&request[1],
690 addr,
691 addr_len);
692 request->udp_msg_size = udp_msg_size;
693 request->udp_msg = GNUNET_memdup (udp_msg,
694 udp_msg_size);
695 request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
696 &do_timeout,
697 request);
698 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
699 "Calling GNS on `%s'\n",
700 packet->queries[0].name);
701 request->lookup = GNUNET_GNS_lookup_with_tld (gns,
702 packet->queries[0].name,
703 packet->queries[0].type,
704 GNUNET_GNS_LO_DEFAULT,
705 &result_processor,
706 request);
707}
708
709
710/**
711 * Task to read IPv4 DNS packets.
712 *
713 * @param cls the 'listen_socket4'
714 */
715static void
716read_dns4 (void *cls)
717{
718 struct sockaddr_in v4;
719 socklen_t addrlen;
720 ssize_t size;
721 const struct GNUNET_SCHEDULER_TaskContext *tc;
722
723 GNUNET_assert (listen_socket4 == cls);
724 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
725 listen_socket4,
726 &read_dns4,
727 listen_socket4);
728 tc = GNUNET_SCHEDULER_get_task_context ();
729 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
730 return; /* shutdown? */
731 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
732 if (0 > size)
733 {
734 GNUNET_break (0);
735 return; /* read error!? */
736 }
737 {
738 char buf[size + 1];
739 ssize_t sret;
740
741 addrlen = sizeof(v4);
742 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket4,
743 buf,
744 size + 1,
745 (struct sockaddr *) &v4,
746 &addrlen);
747 if (0 > sret)
748 {
749 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
750 "recvfrom");
751 return;
752 }
753 GNUNET_break (size == sret);
754 handle_request (listen_socket4,
755 &v4,
756 addrlen,
757 buf,
758 size);
759 }
760}
761
762
763/**
764 * Task to read IPv6 DNS packets.
765 *
766 * @param cls the 'listen_socket6'
767 */
768static void
769read_dns6 (void *cls)
770{
771 struct sockaddr_in6 v6;
772 socklen_t addrlen;
773 ssize_t size;
774 const struct GNUNET_SCHEDULER_TaskContext *tc;
775
776 GNUNET_assert (listen_socket6 == cls);
777 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
778 listen_socket6,
779 &read_dns6,
780 listen_socket6);
781 tc = GNUNET_SCHEDULER_get_task_context ();
782 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
783 return; /* shutdown? */
784 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
785 if (0 > size)
786 {
787 GNUNET_break (0);
788 return; /* read error!? */
789 }
790 {
791 char buf[size];
792 ssize_t sret;
793
794 addrlen = sizeof(v6);
795 sret = GNUNET_NETWORK_socket_recvfrom (listen_socket6,
796 buf,
797 size,
798 (struct sockaddr *) &v6,
799 &addrlen);
800 if (0 > sret)
801 {
802 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
803 "recvfrom");
804 return;
805 }
806 GNUNET_break (size == sret);
807 handle_request (listen_socket6,
808 &v6,
809 addrlen,
810 buf,
811 size);
812 }
813}
814
815
816/**
817 * Main function that will be run.
818 *
819 * @param cls closure
820 * @param args remaining command-line arguments
821 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
822 * @param c configuration
823 */
824static void
825run (void *cls,
826 char *const *args,
827 const char *cfgfile,
828 const struct GNUNET_CONFIGURATION_Handle *c)
829{
830 char *addr_str;
831
832 (void) cls;
833 (void) args;
834 (void) cfgfile;
835 cfg = c;
836 if (NULL == dns_ip)
837 {
838 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
839 _ ("No DNS server specified!\n"));
840 return;
841 }
842 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
843 NULL);
844 if (NULL == (gns = GNUNET_GNS_connect (cfg)))
845 return;
846 if (NULL == (vpn_handle = GNUNET_VPN_connect (cfg)))
847 return;
848 GNUNET_assert (NULL != (dns_stub = GNUNET_DNSSTUB_start (128)));
849 if (GNUNET_OK !=
850 GNUNET_DNSSTUB_add_dns_ip (dns_stub,
851 dns_ip))
852 {
853 GNUNET_DNSSTUB_stop (dns_stub);
854 GNUNET_GNS_disconnect (gns);
855 gns = NULL;
856 GNUNET_VPN_disconnect (vpn_handle);
857 vpn_handle = NULL;
858 return;
859 }
860
861 /* Get address to bind to */
862 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
863 "BIND_TO",
864 &addr_str))
865 {
866 // No address specified
867 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
868 "Don't know what to bind to...\n");
869 GNUNET_free (addr_str);
870 GNUNET_SCHEDULER_shutdown ();
871 return;
872 }
873 if (1 != inet_pton (AF_INET, addr_str, &address))
874 {
875 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
876 "Unable to parse address %s\n",
877 addr_str);
878 GNUNET_free (addr_str);
879 GNUNET_SCHEDULER_shutdown ();
880 return;
881 }
882 GNUNET_free (addr_str);
883 /* Get address to bind to */
884 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (c, "dns2gns",
885 "BIND_TO6",
886 &addr_str))
887 {
888 // No address specified
889 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
890 "Don't know what to bind6 to...\n");
891 GNUNET_free (addr_str);
892 GNUNET_SCHEDULER_shutdown ();
893 return;
894 }
895 if (1 != inet_pton (AF_INET6, addr_str, &address6))
896 {
897 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
898 "Unable to parse IPv6 address %s\n",
899 addr_str);
900 GNUNET_free (addr_str);
901 GNUNET_SCHEDULER_shutdown ();
902 return;
903 }
904 GNUNET_free (addr_str);
905 if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (c, "dns2gns",
906 "PORT",
907 &listen_port))
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "Listening on %llu\n", listen_port);
910
911 listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
912 SOCK_DGRAM,
913 IPPROTO_UDP);
914 if (NULL != listen_socket4)
915 {
916 struct sockaddr_in v4;
917
918 memset (&v4, 0, sizeof(v4));
919 v4.sin_family = AF_INET;
920 v4.sin_addr.s_addr = address;
921#if HAVE_SOCKADDR_IN_SIN_LEN
922 v4.sin_len = sizeof(v4);
923#endif
924 v4.sin_port = htons (listen_port);
925 if (GNUNET_OK !=
926 GNUNET_NETWORK_socket_bind (listen_socket4,
927 (struct sockaddr *) &v4,
928 sizeof(v4)))
929 {
930 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
931 GNUNET_NETWORK_socket_close (listen_socket4);
932 listen_socket4 = NULL;
933 }
934 }
935 listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
936 SOCK_DGRAM,
937 IPPROTO_UDP);
938 if (NULL != listen_socket6)
939 {
940 struct sockaddr_in6 v6;
941
942 memset (&v6, 0, sizeof(v6));
943 v6.sin6_family = AF_INET6;
944 v6.sin6_addr = address6;
945#if HAVE_SOCKADDR_IN_SIN_LEN
946 v6.sin6_len = sizeof(v6);
947#endif
948 v6.sin6_port = htons (listen_port);
949 if (GNUNET_OK !=
950 GNUNET_NETWORK_socket_bind (listen_socket6,
951 (struct sockaddr *) &v6,
952 sizeof(v6)))
953 {
954 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
955 GNUNET_NETWORK_socket_close (listen_socket6);
956 listen_socket6 = NULL;
957 }
958 }
959 if ((NULL == listen_socket4) &&
960 (NULL == listen_socket6))
961 {
962 GNUNET_GNS_disconnect (gns);
963 gns = NULL;
964 GNUNET_VPN_disconnect (vpn_handle);
965 vpn_handle = NULL;
966 GNUNET_DNSSTUB_stop (dns_stub);
967 dns_stub = NULL;
968 return;
969 }
970 if (NULL != listen_socket4)
971 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
972 listen_socket4,
973 &read_dns4,
974 listen_socket4);
975 if (NULL != listen_socket6)
976 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
977 listen_socket6,
978 &read_dns6,
979 listen_socket6);
980}
981
982
983/**
984 * The main function for the dns2gns daemon.
985 *
986 * @param argc number of arguments from the command line
987 * @param argv command line arguments
988 * @return 0 ok, 1 on error
989 */
990int
991main (int argc,
992 char *const *argv)
993{
994 struct GNUNET_GETOPT_CommandLineOption options[] = {
995 GNUNET_GETOPT_option_string ('d',
996 "dns",
997 "IP",
998 gettext_noop (
999 "IP of recursive DNS resolver to use (required)"),
1000 &dns_ip),
1001 GNUNET_GETOPT_OPTION_END
1002 };
1003 int ret;
1004
1005 if (GNUNET_OK !=
1006 GNUNET_STRINGS_get_utf8_args (argc, argv,
1007 &argc, &argv))
1008 return 2;
1009 GNUNET_log_setup ("gnunet-dns2gns",
1010 "WARNING",
1011 NULL);
1012 ret =
1013 (GNUNET_OK ==
1014 GNUNET_PROGRAM_run (argc, argv,
1015 "gnunet-dns2gns",
1016 _ ("GNUnet DNS-to-GNS proxy (a DNS server)"),
1017 options,
1018 &run, NULL)) ? 0 : 1;
1019 GNUNET_free_nz ((void *) argv);
1020 return ret;
1021}
1022
1023
1024/* end of gnunet-dns2gns.c */