2 This file is part of GNUnet.
3 (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @file gnunet-dns2gns.c
22 * @brief DNS server that translates DNS requests to GNS
23 * @author Christian Grothoff
26 #include <gnunet_util_lib.h>
27 #include <gnunet_dnsparser_lib.h>
28 #include <gnunet_gns_service.h>
31 * Timeout for DNS requests.
33 #define TIMEOUT GNUNET_TIME_UNIT_MINUTES
36 * Data kept per request.
41 * Socket to use for sending the reply.
43 struct GNUNET_NETWORK_Handle *lsock;
46 * Destination address to use.
51 * Initially, this is the DNS request, it will then be
52 * converted to the DNS response.
54 struct GNUNET_DNSPARSER_Packet *packet;
57 * Our GNS request handle.
59 struct GNUNET_GNS_LookupRequest *lookup;
62 * Task run on timeout or shutdown to clean up without
65 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
68 * Number of bytes in 'addr'.
76 * Handle to GNS resolver.
78 struct GNUNET_GNS_Handle *gns;
81 * Listen socket for IPv4.
83 static struct GNUNET_NETWORK_Handle *listen_socket4;
86 * Listen socket for IPv6.
88 static struct GNUNET_NETWORK_Handle *listen_socket6;
91 * Task for IPv4 socket.
93 static GNUNET_SCHEDULER_TaskIdentifier t4;
96 * Task for IPv6 socket.
98 static GNUNET_SCHEDULER_TaskIdentifier t6;
102 * Task run on shutdown. Cleans up everything.
105 * @param tc scheduler context
108 do_shutdown (void *cls,
109 const struct GNUNET_SCHEDULER_TaskContext *tc)
111 if (GNUNET_SCHEDULER_NO_TASK != t4)
112 GNUNET_SCHEDULER_cancel (t4);
113 if (GNUNET_SCHEDULER_NO_TASK != t6)
114 GNUNET_SCHEDULER_cancel (t6);
115 if (NULL != listen_socket4)
117 GNUNET_NETWORK_socket_close (listen_socket4);
118 listen_socket4 = NULL;
120 if (NULL != listen_socket6)
122 GNUNET_NETWORK_socket_close (listen_socket6);
123 listen_socket6 = NULL;
125 GNUNET_GNS_disconnect (gns);
131 * Send the response for the given request and clean up.
133 * @param request context for the request.
136 send_response (struct Request *request)
142 GNUNET_DNSPARSER_pack (request->packet,
143 UINT16_MAX /* is this not too much? */,
147 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
148 _("Failed to pack DNS response into UDP packet!\n"));
153 GNUNET_NETWORK_socket_sendto (request->lsock,
157 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
160 GNUNET_SCHEDULER_cancel (request->timeout_task);
161 GNUNET_DNSPARSER_free_packet (request->packet);
162 GNUNET_free (request);
167 * Task run on timeout. Cleans up request.
169 * @param cls 'struct Request' of the request to clean up
170 * @param tc scheduler context
173 do_timeout (void *cls,
174 const struct GNUNET_SCHEDULER_TaskContext *tc)
176 struct Request *request = cls;
178 GNUNET_DNSPARSER_free_packet (request->packet);
179 GNUNET_GNS_cancel_lookup_request (request->lookup);
180 GNUNET_free (request);
185 * Iterator called on obtained result for a GNS
189 * @param name "name" of the original lookup
190 * @param rd_count number of records
191 * @param rd the records in reply
194 result_processor (void *cls,
196 const struct GNUNET_NAMESTORE_RecordData *rd)
198 struct Request *request = cls;
200 // FIXME: is 'processor' called only once or
201 // possibly more than once?
202 request->lookup = NULL;
204 // FIXME: convert 'rd' to response here...
205 send_response (request);
210 * Handle DNS request.
212 * @param lsock socket to use for sending the reply
213 * @param addr address to use for sending the reply
214 * @param addr_len number of bytes in addr
215 * @param udp_msg DNS request payload
216 * @param udp_msg_size number of bytes in udp_msg
219 handle_request (struct GNUNET_NETWORK_Handle *lsock,
225 struct Request *request;
226 struct GNUNET_DNSPARSER_Packet *packet;
228 packet = GNUNET_DNSPARSER_parse (udp_msg, udp_msg_size);
231 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
232 _("Received malformed DNS request from %s\n"),
233 GNUNET_a2s (addr, addr_len));
236 request = GNUNET_malloc (sizeof (struct Request) + addr_len);
237 request->lsock = lsock;
238 request->packet = packet;
239 request->addr = &request[1];
240 request->addr_len = addr_len;
241 memcpy (&request[1], addr, addr_len);
242 request->timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
245 // FIXME: extract name and type from 'request->packet'
246 const char *name = "foo";
247 enum GNUNET_GNS_RecordType type = GNUNET_GNS_RECORD_A;
248 request->lookup = GNUNET_GNS_lookup (gns,
259 * Task to read IPv4 DNS packets.
261 * @param cls the 'listen_socket4'
262 * @param tc scheduler context
265 read_dns4 (void *cls,
266 const struct GNUNET_SCHEDULER_TaskContext *tc)
268 struct sockaddr_in v4;
272 GNUNET_assert (listen_socket4 == cls);
273 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
277 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
278 return; /* shutdown? */
279 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket4);
283 return; /* read error!? */
288 addrlen = sizeof (v4);
289 GNUNET_break (size ==
290 GNUNET_NETWORK_socket_recvfrom (listen_socket4,
293 (struct sockaddr *) &v4,
295 handle_request (listen_socket4, &v4, addrlen,
302 * Task to read IPv6 DNS packets.
304 * @param cls the 'listen_socket6'
305 * @param tc scheduler context
308 read_dns6 (void *cls,
309 const struct GNUNET_SCHEDULER_TaskContext *tc)
311 struct sockaddr_in6 v6;
315 GNUNET_assert (listen_socket6 == cls);
316 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
320 if (0 == (GNUNET_SCHEDULER_REASON_READ_READY & tc->reason))
321 return; /* shutdown? */
322 size = GNUNET_NETWORK_socket_recvfrom_amount (listen_socket6);
326 return; /* read error!? */
331 addrlen = sizeof (v6);
332 GNUNET_break (size ==
333 GNUNET_NETWORK_socket_recvfrom (listen_socket6,
336 (struct sockaddr *) &v6,
338 handle_request (listen_socket6, &v6, addrlen,
345 * Main function that will be run.
348 * @param args remaining command-line arguments
349 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
350 * @param cfg configuration
353 run (void *cls, char *const *args, const char *cfgfile,
354 const struct GNUNET_CONFIGURATION_Handle *cfg)
356 gns = GNUNET_GNS_connect (cfg);
359 listen_socket4 = GNUNET_NETWORK_socket_create (PF_INET,
362 if (NULL != listen_socket4)
364 struct sockaddr_in v4;
366 memset (&v4, 0, sizeof (v4));
367 v4.sin_family = AF_INET;
368 #if HAVE_SOCKADDR_IN_SIN_LEN
369 v4.sin_len = sizeof (v4);
371 v4.sin_port = htons (53);
373 GNUNET_NETWORK_socket_bind (listen_socket4,
374 (struct sockaddr *) &v4,
377 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
378 GNUNET_NETWORK_socket_close (listen_socket4);
379 listen_socket4 = NULL;
382 listen_socket6 = GNUNET_NETWORK_socket_create (PF_INET6,
385 if (NULL != listen_socket6)
387 struct sockaddr_in6 v6;
389 memset (&v6, 0, sizeof (v6));
390 v6.sin6_family = AF_INET6;
391 #if HAVE_SOCKADDR_IN_SIN_LEN
392 v6.sin6_len = sizeof (v6);
394 v6.sin6_port = htons (53);
396 GNUNET_NETWORK_socket_bind (listen_socket6,
397 (struct sockaddr *) &v6,
400 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
401 GNUNET_NETWORK_socket_close (listen_socket6);
402 listen_socket6 = NULL;
405 if ( (NULL == listen_socket4) &&
406 (NULL == listen_socket6) )
408 if (NULL != listen_socket4)
409 t4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
413 if (NULL != listen_socket6)
414 t6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
419 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
425 * The main function for the fcfs daemon.
427 * @param argc number of arguments from the command line
428 * @param argv command line arguments
429 * @return 0 ok, 1 on error
435 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
436 GNUNET_GETOPT_OPTION_END
440 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv,
443 GNUNET_log_setup ("gnunet-dns2gns", "WARNING", NULL);
446 GNUNET_PROGRAM_run (argc, argv, "gnunet-dns2gns",
447 _("GNUnet DNS-to-GNS proxy (a DNS server)"),
449 &run, NULL)) ? 0 : 1;
454 /* end of gnunet-dns2gns.c */