aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/dns/Makefile.am10
-rw-r--r--src/dns/dnsstub.c520
-rw-r--r--src/dns/gnunet-service-dns.c468
-rw-r--r--src/include/Makefile.am1
-rw-r--r--src/include/gnunet_dnsstub_lib.h115
5 files changed, 722 insertions, 392 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index 8a102c414..aca8ea25c 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -25,6 +25,7 @@ endif
25 25
26lib_LTLIBRARIES = \ 26lib_LTLIBRARIES = \
27 libgnunetdnsparser.la \ 27 libgnunetdnsparser.la \
28 libgnunetdnsstub.la \
28 libgnunetdns.la 29 libgnunetdns.la
29 30
30bin_PROGRAMS = \ 31bin_PROGRAMS = \
@@ -70,6 +71,7 @@ gnunet_dns_redirector_DEPENDENCIES = \
70gnunet_service_dns_SOURCES = \ 71gnunet_service_dns_SOURCES = \
71 gnunet-service-dns.c 72 gnunet-service-dns.c
72gnunet_service_dns_LDADD = \ 73gnunet_service_dns_LDADD = \
74 $(top_builddir)/src/dns/libgnunetdnsstub.la \
73 $(top_builddir)/src/tun/libgnunettun.la \ 75 $(top_builddir)/src/tun/libgnunettun.la \
74 $(top_builddir)/src/mesh/libgnunetmesh.la \ 76 $(top_builddir)/src/mesh/libgnunetmesh.la \
75 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 77 $(top_builddir)/src/statistics/libgnunetstatistics.la \
@@ -84,6 +86,14 @@ libgnunetdnsparser_la_LDFLAGS = \
84 $(GN_LIB_LDFLAGS) \ 86 $(GN_LIB_LDFLAGS) \
85 -version-info 0:0:0 87 -version-info 0:0:0
86 88
89libgnunetdnsstub_la_SOURCES = \
90 dnsstub.c
91libgnunetdnsstub_la_LIBADD = \
92 $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
93libgnunetdnsstub_la_LDFLAGS = \
94 $(GN_LIB_LDFLAGS) \
95 -version-info 0:0:0
96
87libgnunetdns_la_SOURCES = \ 97libgnunetdns_la_SOURCES = \
88 dns_api.c dns.h 98 dns_api.c dns.h
89libgnunetdns_la_LIBADD = \ 99libgnunetdns_la_LIBADD = \
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c
new file mode 100644
index 000000000..383b1d699
--- /dev/null
+++ b/src/dns/dnsstub.c
@@ -0,0 +1,520 @@
1/*
2 This file is part of GNUnet.
3 (C) 2012 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 * @file dns/dnsstub.c
22 * @brief DNS stub resolver which sends DNS requests to an actual resolver
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_dnsstub_lib.h"
28
29/**
30 * Timeout for an external (Internet-DNS) DNS resolution
31 */
32#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
33
34/**
35 * How many DNS sockets do we open at most at the same time?
36 * (technical socket maximum is this number x2 for IPv4+IPv6)
37 */
38#define DNS_SOCKET_MAX 128
39
40
41/**
42 * UDP socket we are using for sending DNS requests to the Internet.
43 */
44struct GNUNET_DNSSTUB_RequestSocket
45{
46
47 /**
48 * UDP socket we use for this request for IPv4
49 */
50 struct GNUNET_NETWORK_Handle *dnsout4;
51
52 /**
53 * UDP socket we use for this request for IPv6
54 */
55 struct GNUNET_NETWORK_Handle *dnsout6;
56
57 /**
58 * Function to call with result.
59 */
60 GNUNET_DNSSTUB_ResultCallback rc;
61
62 /**
63 * Closure for 'rc'.
64 */
65 void *rc_cls;
66
67 /**
68 * Task for reading from dnsout4 and dnsout6.
69 */
70 GNUNET_SCHEDULER_TaskIdentifier read_task;
71
72 /**
73 * When should this request time out?
74 */
75 struct GNUNET_TIME_Absolute timeout;
76
77 /**
78 * Address we sent the DNS request to.
79 */
80 struct sockaddr_storage addr;
81
82 /**
83 * Number of bytes in 'addr'.
84 */
85 socklen_t addrlen;
86
87};
88
89
90struct GNUNET_DNSSTUB_Context
91{
92
93 /**
94 * Array of all open sockets for DNS requests.
95 */
96 struct GNUNET_DNSSTUB_RequestSocket sockets[DNS_SOCKET_MAX];
97
98 /**
99 * IP address to use for the DNS server if we are a DNS exit service
100 * (for VPN via mesh); otherwise NULL.
101 */
102 char *dns_exit;
103};
104
105
106
107/**
108 * We're done with a GNUNET_DNSSTUB_RequestSocket, close it for now.
109 *
110 * @param rs request socket to clean up
111 */
112static void
113cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
114{
115 if (NULL != rs->dnsout4)
116 {
117 GNUNET_NETWORK_socket_close (rs->dnsout4);
118 rs->dnsout4 = NULL;
119 }
120 if (NULL != rs->dnsout6)
121 {
122 GNUNET_NETWORK_socket_close (rs->dnsout6);
123 rs->dnsout6 = NULL;
124 }
125 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
126 {
127 GNUNET_SCHEDULER_cancel (rs->read_task);
128 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
129 }
130}
131
132
133/**
134 * Open source port for sending DNS requests
135 *
136 * @param af AF_INET or AF_INET6
137 * @return GNUNET_OK on success
138 */
139static struct GNUNET_NETWORK_Handle *
140open_socket (int af)
141{
142 struct sockaddr_in a4;
143 struct sockaddr_in6 a6;
144 struct sockaddr *sa;
145 socklen_t alen;
146 struct GNUNET_NETWORK_Handle *ret;
147
148 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
149 if (NULL == ret)
150 return NULL;
151 switch (af)
152 {
153 case AF_INET:
154 memset (&a4, 0, alen = sizeof (struct sockaddr_in));
155 sa = (struct sockaddr *) &a4;
156 break;
157 case AF_INET6:
158 memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
159 sa = (struct sockaddr *) &a6;
160 break;
161 default:
162 GNUNET_break (0);
163 GNUNET_NETWORK_socket_close (ret);
164 return NULL;
165 }
166 sa->sa_family = af;
167 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
168 sa,
169 alen))
170 {
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
172 _("Could not bind to any port: %s\n"),
173 STRERROR (errno));
174 GNUNET_NETWORK_socket_close (ret);
175 return NULL;
176 }
177 return ret;
178}
179
180
181/**
182 * Read a DNS response from the (unhindered) UDP-Socket
183 *
184 * @param cls socket to read from
185 * @param tc scheduler context (must be shutdown or read ready)
186 */
187static void
188read_response (void *cls,
189 const struct GNUNET_SCHEDULER_TaskContext *tc);
190
191
192/**
193 * Get a socket of the specified address family to send out a
194 * UDP DNS request to the Internet.
195 *
196 * @param af desired address family
197 * @return NULL on error (given AF not "supported")
198 */
199static struct GNUNET_DNSSTUB_RequestSocket *
200get_request_socket (struct GNUNET_DNSSTUB_Context *ctx,
201 int af)
202{
203 struct GNUNET_DNSSTUB_RequestSocket *rs;
204 struct GNUNET_NETWORK_FDSet *rset;
205
206 rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
207 DNS_SOCKET_MAX)];
208 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
209 switch (af)
210 {
211 case AF_INET:
212 if (NULL == rs->dnsout4)
213 rs->dnsout4 = open_socket (AF_INET);
214 break;
215 case AF_INET6:
216 if (NULL == rs->dnsout6)
217 rs->dnsout6 = open_socket (AF_INET6);
218 break;
219 default:
220 return NULL;
221 }
222 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
223 {
224 GNUNET_SCHEDULER_cancel (rs->read_task);
225 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
226 }
227 if ( (NULL == rs->dnsout4) &&
228 (NULL == rs->dnsout6) )
229 return NULL;
230 rset = GNUNET_NETWORK_fdset_create ();
231 if (NULL != rs->dnsout4)
232 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
233 if (NULL != rs->dnsout6)
234 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
235 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
236 REQUEST_TIMEOUT,
237 rset,
238 NULL,
239 &read_response, rs);
240 GNUNET_NETWORK_fdset_destroy (rset);
241 return rs;
242}
243
244
245/**
246 * Perform DNS resolution.
247 *
248 * @param ctx stub resolver to use
249 * @param af address family to use
250 * @param request DNS request to transmit
251 * @param request_len number of bytes in msg
252 * @param rc function to call with result
253 * @param rc_cls closure for 'rc'
254 * @return socket used for the request, NULL on error
255 */
256struct GNUNET_DNSSTUB_RequestSocket *
257GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
258 const struct sockaddr *sa,
259 socklen_t sa_len,
260 const void *request,
261 size_t request_len,
262 GNUNET_DNSSTUB_ResultCallback rc,
263 void *rc_cls)
264{
265 struct GNUNET_DNSSTUB_RequestSocket *rs;
266 struct GNUNET_NETWORK_Handle *ret;
267 int af;
268
269 af = sa->sa_family;
270 if (NULL == (rs = get_request_socket (ctx, af)))
271 return NULL;
272 if (NULL != rs->dnsout4)
273 ret = rs->dnsout4;
274 else
275 ret = rs->dnsout6;
276 GNUNET_assert (NULL != ret);
277 rs->rc = rc;
278 rs->rc_cls = rc_cls;
279 GNUNET_NETWORK_socket_sendto (ret,
280 request,
281 request_len,
282 sa,
283 sa_len);
284 return rs;
285}
286
287
288/**
289 * Perform DNS resolution using our default IP from init.
290 *
291 * @param ctx stub resolver to use
292 * @param request DNS request to transmit
293 * @param request_len number of bytes in msg
294 * @param rc function to call with result
295 * @param rc_cls closure for 'rc'
296 * @return socket used for the request, NULL on error
297 */
298struct GNUNET_DNSSTUB_RequestSocket *
299GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
300 const void *request,
301 size_t request_len,
302 GNUNET_DNSSTUB_ResultCallback rc,
303 void *rc_cls)
304{
305 int af;
306 struct sockaddr_in v4;
307 struct sockaddr_in6 v6;
308 struct sockaddr *so;
309 socklen_t salen;
310 struct GNUNET_NETWORK_Handle *dnsout;
311 struct GNUNET_DNSSTUB_RequestSocket *rs;
312
313 memset (&v4, 0, sizeof (v4));
314 memset (&v6, 0, sizeof (v6));
315 if (1 == inet_pton (AF_INET, ctx->dns_exit, &v4.sin_addr))
316 {
317 salen = sizeof (v4);
318 v4.sin_family = AF_INET;
319 v4.sin_port = htons (53);
320#if HAVE_SOCKADDR_IN_SIN_LEN
321 v4.sin_len = (u_char) salen;
322#endif
323 so = (struct sockaddr *) &v4;
324 af = AF_INET;
325 }
326 else if (1 == inet_pton (AF_INET6, ctx->dns_exit, &v6.sin6_addr))
327 {
328 salen = sizeof (v6);
329 v6.sin6_family = AF_INET6;
330 v6.sin6_port = htons (53);
331#if HAVE_SOCKADDR_IN_SIN_LEN
332 v6.sin6_len = (u_char) salen;
333#endif
334 so = (struct sockaddr *) &v6;
335 af = AF_INET6;
336 }
337 else
338 {
339 GNUNET_break (0);
340 return NULL;
341 }
342 if (NULL == (rs = get_request_socket (ctx, af)))
343 return NULL;
344 if (NULL != rs->dnsout4)
345 dnsout = rs->dnsout4;
346 else
347 dnsout = rs->dnsout6;
348 if (NULL == dnsout)
349 {
350 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
351 _("Configured DNS exit `%s' is not working / valid.\n"),
352 ctx->dns_exit);
353 return NULL;
354 }
355 memcpy (&rs->addr,
356 so,
357 salen);
358 rs->addrlen = salen;
359 GNUNET_NETWORK_socket_sendto (dnsout,
360 request,
361 request_len, so, salen);
362 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
363
364 return rs;
365
366}
367
368
369/**
370 * Actually do the reading of a DNS packet from our UDP socket and see
371 * if we have a valid, matching, pending request.
372 *
373 * @param rs request socket with callback details
374 * @param dnsout socket to read from
375 * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket)
376 */
377static int
378do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
379 struct GNUNET_NETWORK_Handle *dnsout)
380{
381 struct sockaddr_storage addr;
382 socklen_t addrlen;
383 struct GNUNET_TUN_DnsHeader *dns;
384 ssize_t r;
385 int len;
386
387#ifndef MINGW
388 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len))
389 {
390 /* conservative choice: */
391 len = UINT16_MAX;
392 }
393#else
394 /* port the code above? */
395 len = UINT16_MAX;
396#endif
397
398 {
399 unsigned char buf[len] GNUNET_ALIGN;
400
401 addrlen = sizeof (addr);
402 memset (&addr, 0, sizeof (addr));
403 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
404 buf, sizeof (buf),
405 (struct sockaddr*) &addr, &addrlen);
406 if (-1 == r)
407 {
408 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
409 GNUNET_NETWORK_socket_close (dnsout);
410 return GNUNET_SYSERR;
411 }
412 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
413 {
414 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
415 _("Received DNS response that is too small (%u bytes)"),
416 r);
417 return GNUNET_NO;
418 }
419 dns = (struct GNUNET_TUN_DnsHeader *) buf;
420 if ( (addrlen != rs->addrlen) ||
421 (0 != memcmp (&rs->addr,
422 &addr,
423 addrlen)) ||
424 (0 == GNUNET_TIME_absolute_get_remaining (rs->timeout).rel_value) )
425 return GNUNET_NO;
426 rs->rc (rs->rc_cls,
427 rs,
428 dns,
429 r);
430 }
431 return GNUNET_OK;
432}
433
434
435/**
436 * Read a DNS response from the (unhindered) UDP-Socket
437 *
438 * @param cls socket to read from
439 * @param tc scheduler context (must be shutdown or read ready)
440 */
441static void
442read_response (void *cls,
443 const struct GNUNET_SCHEDULER_TaskContext *tc)
444{
445 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
446 struct GNUNET_NETWORK_FDSet *rset;
447
448 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
449 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
450 {
451 /* timeout or shutdown */
452 cleanup_rs (rs);
453 return;
454 }
455 /* read and process ready sockets */
456 if ((NULL != rs->dnsout4) &&
457 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
458 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout4)))
459 rs->dnsout4 = NULL;
460 if ((NULL != rs->dnsout6) &&
461 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
462 (GNUNET_SYSERR == do_dns_read (rs, rs->dnsout6)))
463 rs->dnsout6 = NULL;
464
465 /* re-schedule read task */
466 rset = GNUNET_NETWORK_fdset_create ();
467 if (NULL != rs->dnsout4)
468 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
469 if (NULL != rs->dnsout6)
470 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
471 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
472 GNUNET_TIME_absolute_get_remaining (rs->timeout),
473 rset,
474 NULL,
475 &read_response, rs);
476 GNUNET_NETWORK_fdset_destroy (rset);
477}
478
479
480
481/**
482 * Start a DNS stub resolver.
483 *
484 * @param dns_ip target IP address to use
485 * @return NULL on error
486 */
487struct GNUNET_DNSSTUB_Context *
488GNUNET_DNSSTUB_start (const char *dns_ip)
489{
490 struct GNUNET_DNSSTUB_Context *ctx;
491
492 ctx = GNUNET_malloc (sizeof (struct GNUNET_DNSSTUB_Context));
493 if (NULL != dns_ip)
494 ctx->dns_exit = GNUNET_strdup (dns_ip);
495 return ctx;
496}
497
498
499/**
500 * Cleanup DNSSTUB resolver.
501 *
502 * @param ctx stub resolver to clean up
503 */
504void
505GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
506{
507 unsigned int i;
508
509 for (i=0;i<=UINT16_MAX;i++)
510 cleanup_rs (&ctx->sockets[i]);
511 if (NULL != ctx->dns_exit)
512 {
513 GNUNET_free (ctx->dns_exit);
514 ctx->dns_exit = NULL;
515 }
516 GNUNET_free (ctx);
517}
518
519
520/* end of dnsstub.c */
diff --git a/src/dns/gnunet-service-dns.c b/src/dns/gnunet-service-dns.c
index 76ea1390f..b13f156a9 100644
--- a/src/dns/gnunet-service-dns.c
+++ b/src/dns/gnunet-service-dns.c
@@ -45,23 +45,13 @@
45#include "dns.h" 45#include "dns.h"
46#include "gnunet_dns_service.h" 46#include "gnunet_dns_service.h"
47#include "gnunet_dnsparser_lib.h" 47#include "gnunet_dnsparser_lib.h"
48#include "gnunet_dnsstub_lib.h"
48#include "gnunet_mesh_service.h" 49#include "gnunet_mesh_service.h"
49#include "gnunet_statistics_service.h" 50#include "gnunet_statistics_service.h"
50#include "gnunet_tun_lib.h" 51#include "gnunet_tun_lib.h"
51 52
52 53
53/** 54/**
54 * Timeout for an external (Internet-DNS) DNS resolution
55 */
56#define REQUEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
57
58/**
59 * How many DNS sockets do we open at most at the same time?
60 * (technical socket maximum is this number x2 for IPv4+IPv6)
61 */
62#define DNS_SOCKET_MAX 128
63
64/**
65 * Phases each request goes through. 55 * Phases each request goes through.
66 */ 56 */
67enum RequestPhase 57enum RequestPhase
@@ -137,34 +127,6 @@ struct ClientRecord
137 127
138 128
139/** 129/**
140 * UDP socket we are using for sending DNS requests to the Internet.
141 */
142struct RequestSocket
143{
144
145 /**
146 * UDP socket we use for this request for IPv4
147 */
148 struct GNUNET_NETWORK_Handle *dnsout4;
149
150 /**
151 * UDP socket we use for this request for IPv6
152 */
153 struct GNUNET_NETWORK_Handle *dnsout6;
154
155 /**
156 * Task for reading from dnsout4 and dnsout6.
157 */
158 GNUNET_SCHEDULER_TaskIdentifier read_task;
159
160 /**
161 * When should this socket be closed?
162 */
163 struct GNUNET_TIME_Absolute timeout;
164};
165
166
167/**
168 * Entry we keep for each active request. 130 * Entry we keep for each active request.
169 */ 131 */
170struct RequestRecord 132struct RequestRecord
@@ -184,10 +146,9 @@ struct RequestRecord
184 146
185 /** 147 /**
186 * Socket we are using to transmit this request (must match if we receive 148 * Socket we are using to transmit this request (must match if we receive
187 * a response). Must NOT be freed as part of this request record (as it 149 * a response).
188 * might be shared with other requests).
189 */ 150 */
190 struct GNUNET_NETWORK_Handle *dnsout; 151 struct GNUNET_DNSSTUB_RequestSocket *rs;
191 152
192 /** 153 /**
193 * Source address of the original request (for sending response). 154 * Source address of the original request (for sending response).
@@ -200,11 +161,6 @@ struct RequestRecord
200 struct sockaddr_storage dst_addr; 161 struct sockaddr_storage dst_addr;
201 162
202 /** 163 /**
203 * When should this request time out?
204 */
205 struct GNUNET_TIME_Absolute timeout;
206
207 /**
208 * ID of this request, also basis for hashing. Lowest 16 bit will 164 * ID of this request, also basis for hashing. Lowest 16 bit will
209 * be our message ID when doing a global DNS request and our index 165 * be our message ID when doing a global DNS request and our index
210 * into the 'requests' array. 166 * into the 'requests' array.
@@ -252,25 +208,9 @@ struct TunnelState
252 208
253 /** 209 /**
254 * Socket we are using to transmit this request (must match if we receive 210 * Socket we are using to transmit this request (must match if we receive
255 * a response). Must NOT be freed as part of this request record (as it 211 * a response).
256 * might be shared with other requests).
257 */
258 struct GNUNET_NETWORK_Handle *dnsout;
259
260 /**
261 * Address we sent the DNS request to.
262 */
263 struct sockaddr_storage addr;
264
265 /**
266 * When should this request time out?
267 */ 212 */
268 struct GNUNET_TIME_Absolute timeout; 213 struct GNUNET_DNSSTUB_RequestSocket *rs;
269
270 /**
271 * Number of bytes in 'addr'.
272 */
273 socklen_t addrlen;
274 214
275 /** 215 /**
276 * Number of bytes in 'reply'. 216 * Number of bytes in 'reply'.
@@ -330,19 +270,14 @@ static struct ClientRecord *clients_tail;
330static struct GNUNET_SERVER_NotificationContext *nc; 270static struct GNUNET_SERVER_NotificationContext *nc;
331 271
332/** 272/**
333 * Array of all open requests.
334 */
335static struct RequestRecord requests[UINT16_MAX + 1];
336
337/**
338 * Array of all open requests from tunnels. 273 * Array of all open requests from tunnels.
339 */ 274 */
340static struct TunnelState *tunnels[UINT16_MAX + 1]; 275static struct TunnelState *tunnels[UINT16_MAX + 1];
341 276
342/** 277/**
343 * Array of all open sockets for DNS requests. 278 * Array of all open requests.
344 */ 279 */
345static struct RequestSocket sockets[DNS_SOCKET_MAX]; 280static struct RequestRecord requests[UINT16_MAX + 1];
346 281
347/** 282/**
348 * Generator for unique request IDs. 283 * Generator for unique request IDs.
@@ -350,42 +285,15 @@ static struct RequestSocket sockets[DNS_SOCKET_MAX];
350static uint64_t request_id_gen; 285static uint64_t request_id_gen;
351 286
352/** 287/**
353 * IP address to use for the DNS server if we are a DNS exit service
354 * (for VPN via mesh); otherwise NULL.
355 */
356static char *dns_exit;
357
358/**
359 * Handle to the MESH service (for receiving DNS queries), or NULL 288 * Handle to the MESH service (for receiving DNS queries), or NULL
360 * if we are not a DNS exit. 289 * if we are not a DNS exit.
361 */ 290 */
362static struct GNUNET_MESH_Handle *mesh; 291static struct GNUNET_MESH_Handle *mesh;
363 292
364
365/** 293/**
366 * We're done with a RequestSocket, close it for now. 294 * Handle to the DNS Stub resolver.
367 *
368 * @param rs request socket to clean up
369 */ 295 */
370static void 296static struct GNUNET_DNSSTUB_Context *dnsstub;
371cleanup_rs (struct RequestSocket *rs)
372{
373 if (NULL != rs->dnsout4)
374 {
375 GNUNET_NETWORK_socket_close (rs->dnsout4);
376 rs->dnsout4 = NULL;
377 }
378 if (NULL != rs->dnsout6)
379 {
380 GNUNET_NETWORK_socket_close (rs->dnsout6);
381 rs->dnsout6 = NULL;
382 }
383 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
384 {
385 GNUNET_SCHEDULER_cancel (rs->read_task);
386 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
387 }
388}
389 297
390 298
391/** 299/**
@@ -430,10 +338,10 @@ cleanup_task (void *cls GNUNET_UNUSED,
430 GNUNET_STATISTICS_destroy (stats, GNUNET_NO); 338 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
431 stats = NULL; 339 stats = NULL;
432 } 340 }
433 if (NULL != dns_exit) 341 if (NULL != dnsstub)
434 { 342 {
435 GNUNET_free (dns_exit); 343 GNUNET_DNSSTUB_stop (dnsstub);
436 dns_exit = NULL; 344 dnsstub = NULL;
437 } 345 }
438 if (NULL != mesh) 346 if (NULL != mesh)
439 { 347 {
@@ -444,54 +352,6 @@ cleanup_task (void *cls GNUNET_UNUSED,
444 352
445 353
446/** 354/**
447 * Open source port for sending DNS requests
448 *
449 * @param af AF_INET or AF_INET6
450 * @return GNUNET_OK on success
451 */
452static struct GNUNET_NETWORK_Handle *
453open_socket (int af)
454{
455 struct sockaddr_in a4;
456 struct sockaddr_in6 a6;
457 struct sockaddr *sa;
458 socklen_t alen;
459 struct GNUNET_NETWORK_Handle *ret;
460
461 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
462 if (NULL == ret)
463 return NULL;
464 switch (af)
465 {
466 case AF_INET:
467 memset (&a4, 0, alen = sizeof (struct sockaddr_in));
468 sa = (struct sockaddr *) &a4;
469 break;
470 case AF_INET6:
471 memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
472 sa = (struct sockaddr *) &a6;
473 break;
474 default:
475 GNUNET_break (0);
476 GNUNET_NETWORK_socket_close (ret);
477 return NULL;
478 }
479 sa->sa_family = af;
480 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
481 sa,
482 alen))
483 {
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 _("Could not bind to any port: %s\n"),
486 STRERROR (errno));
487 GNUNET_NETWORK_socket_close (ret);
488 return NULL;
489 }
490 return ret;
491}
492
493
494/**
495 * We're done with some request, finish processing. 355 * We're done with some request, finish processing.
496 * 356 *
497 * @param rr request send to the network or just clean up. 357 * @param rr request send to the network or just clean up.
@@ -677,70 +537,21 @@ send_request_to_client (struct RequestRecord *rr,
677} 537}
678 538
679 539
680/**
681 * Read a DNS response from the (unhindered) UDP-Socket
682 *
683 * @param cls socket to read from
684 * @param tc scheduler context (must be shutdown or read ready)
685 */
686static void
687read_response (void *cls,
688 const struct GNUNET_SCHEDULER_TaskContext *tc);
689
690 540
691/** 541/**
692 * Get a socket of the specified address family to send out a 542 * Callback called from DNSSTUB resolver when a resolution
693 * UDP DNS request to the Internet. 543 * succeeded.
694 * 544 *
695 * @param af desired address family 545 * @param cls NULL
696 * @return NULL on error (given AF not "supported") 546 * @param rs the socket that received the response
547 * @param dns the response itself
548 * @param r number of bytes in dns
697 */ 549 */
698static struct GNUNET_NETWORK_Handle * 550static void
699get_request_socket (int af) 551process_dns_result (void *cls,
700{ 552 struct GNUNET_DNSSTUB_RequestSocket *rs,
701 struct RequestSocket *rs; 553 const struct GNUNET_TUN_DnsHeader *dns,
702 struct GNUNET_NETWORK_FDSet *rset; 554 size_t r);
703 static struct GNUNET_NETWORK_Handle *ret;
704
705 rs = &sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
706 DNS_SOCKET_MAX)];
707 rs->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
708 switch (af)
709 {
710 case AF_INET:
711 if (NULL == rs->dnsout4)
712 rs->dnsout4 = open_socket (AF_INET);
713 ret = rs->dnsout4;
714 break;
715 case AF_INET6:
716 if (NULL == rs->dnsout6)
717 rs->dnsout6 = open_socket (AF_INET6);
718 ret = rs->dnsout6;
719 break;
720 default:
721 return NULL;
722 }
723 if (GNUNET_SCHEDULER_NO_TASK != rs->read_task)
724 {
725 GNUNET_SCHEDULER_cancel (rs->read_task);
726 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
727 }
728 if ( (NULL == rs->dnsout4) &&
729 (NULL == rs->dnsout6) )
730 return NULL;
731 rset = GNUNET_NETWORK_fdset_create ();
732 if (NULL != rs->dnsout4)
733 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
734 if (NULL != rs->dnsout6)
735 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
736 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
737 REQUEST_TIMEOUT,
738 rset,
739 NULL,
740 &read_response, rs);
741 GNUNET_NETWORK_fdset_destroy (rset);
742 return ret;
743}
744 555
745 556
746/** 557/**
@@ -815,8 +626,14 @@ next_phase (struct RequestRecord *rr)
815 } 626 }
816 627
817 rr->phase = RP_INTERNET_DNS; 628 rr->phase = RP_INTERNET_DNS;
818 rr->dnsout = get_request_socket (rr->dst_addr.ss_family); 629 rr->rs = GNUNET_DNSSTUB_resolve (dnsstub,
819 if (NULL == rr->dnsout) 630 (struct sockaddr*) &rr->dst_addr,
631 salen,
632 rr->payload,
633 rr->payload_length,
634 &process_dns_result,
635 NULL);
636 if (NULL == rr->rs)
820 { 637 {
821 GNUNET_STATISTICS_update (stats, 638 GNUNET_STATISTICS_update (stats,
822 gettext_noop ("# DNS exit failed (failed to open socket)"), 639 gettext_noop ("# DNS exit failed (failed to open socket)"),
@@ -824,12 +641,6 @@ next_phase (struct RequestRecord *rr)
824 cleanup_rr (rr); 641 cleanup_rr (rr);
825 return; 642 return;
826 } 643 }
827 GNUNET_NETWORK_socket_sendto (rr->dnsout,
828 rr->payload,
829 rr->payload_length,
830 (struct sockaddr*) &rr->dst_addr,
831 salen);
832 rr->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
833 return; 644 return;
834 case RP_INTERNET_DNS: 645 case RP_INTERNET_DNS:
835 rr->phase = RP_MODIFY; 646 rr->phase = RP_MODIFY;
@@ -956,68 +767,32 @@ transmit_reply_to_mesh (void *cls,
956} 767}
957 768
958 769
770
959/** 771/**
960 * Actually do the reading of a DNS packet from our UDP socket and see 772 * Callback called from DNSSTUB resolver when a resolution
961 * if we have a valid, matching, pending request. 773 * succeeded.
962 * 774 *
963 * @param dnsout socket to read from 775 * @param cls NULL
964 * @return GNUNET_OK on success, GNUNET_NO on drop, GNUNET_SYSERR on IO-errors (closed socket) 776 * @param rs the socket that received the response
777 * @param dns the response itself
778 * @param r number of bytes in dns
965 */ 779 */
966static int 780static void
967do_dns_read (struct GNUNET_NETWORK_Handle *dnsout) 781process_dns_result (void *cls,
782 struct GNUNET_DNSSTUB_RequestSocket *rs,
783 const struct GNUNET_TUN_DnsHeader *dns,
784 size_t r)
968{ 785{
969 struct sockaddr_storage addr;
970 socklen_t addrlen;
971 struct GNUNET_TUN_DnsHeader *dns;
972 struct RequestRecord *rr; 786 struct RequestRecord *rr;
973 struct TunnelState *ts; 787 struct TunnelState *ts;
974 ssize_t r; 788
975 int len; 789 GNUNET_assert (NULL == cls);
976 790 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
977#ifndef MINGW 791 ts = tunnels[dns->id];
978 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout), FIONREAD, &len)) 792 if ( (NULL == ts) ||
979 { 793 (ts->rs != rs) )
980 /* conservative choice: */ 794 ts = NULL; /* DNS responder address missmatch */
981 len = UINT16_MAX; 795 if (NULL != ts)
982 }
983#else
984 /* port the code above? */
985 len = UINT16_MAX;
986#endif
987
988 {
989 unsigned char buf[len] GNUNET_ALIGN;
990
991 addrlen = sizeof (addr);
992 memset (&addr, 0, sizeof (addr));
993 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
994 buf, sizeof (buf),
995 (struct sockaddr*) &addr, &addrlen);
996 if (-1 == r)
997 {
998 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom");
999 GNUNET_NETWORK_socket_close (dnsout);
1000 return GNUNET_SYSERR;
1001 }
1002 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
1003 {
1004 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1005 _("Received DNS response that is too small (%u bytes)"),
1006 r);
1007 return GNUNET_NO;
1008 }
1009 dns = (struct GNUNET_TUN_DnsHeader *) buf;
1010 /* Handle case that this is a reply to a request from a MESH DNS tunnel */
1011 ts = tunnels[dns->id];
1012 if ( (NULL == ts) ||
1013 (ts->dnsout != dnsout) ||
1014 (addrlen != ts->addrlen) ||
1015 (0 != memcmp (&ts->addr,
1016 &addr,
1017 addrlen)) ||
1018 (0 == GNUNET_TIME_absolute_get_remaining (ts->timeout).rel_value) )
1019 ts = NULL; /* DNS responder address missmatch */
1020 if (NULL != ts)
1021 { 796 {
1022 tunnels[dns->id] = NULL; 797 tunnels[dns->id] = NULL;
1023 GNUNET_free_non_null (ts->reply); 798 GNUNET_free_non_null (ts->reply);
@@ -1034,76 +809,25 @@ do_dns_read (struct GNUNET_NETWORK_Handle *dnsout)
1034 &transmit_reply_to_mesh, 809 &transmit_reply_to_mesh,
1035 ts); 810 ts);
1036 } 811 }
1037 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */ 812 /* Handle case that this is a reply to a local request (intercepted from TUN interface) */
1038 rr = &requests[dns->id]; 813 rr = &requests[dns->id];
1039 if ( (rr->phase != RP_INTERNET_DNS) || 814 if ( (rr->phase != RP_INTERNET_DNS) ||
1040 (rr->dnsout != dnsout) || 815 (rr->rs != rs) )
1041 (0 != memcmp (&rr->dst_addr,
1042 &addr,
1043 addrlen)) ||
1044 (0 == GNUNET_TIME_absolute_get_remaining (rr->timeout).rel_value) )
1045 { 816 {
1046 if (NULL == ts) 817 if (NULL == ts)
1047 { 818 {
1048 /* unexpected / bogus reply */ 819 /* unexpected / bogus reply */
1049 GNUNET_STATISTICS_update (stats, 820 GNUNET_STATISTICS_update (stats,
1050 gettext_noop ("# External DNS response discarded (no matching request)"), 821 gettext_noop ("# External DNS response discarded (no matching request)"),
1051 1, GNUNET_NO); 822 1, GNUNET_NO);
1052 } 823 }
1053 return GNUNET_NO; 824 return;
1054 } 825 }
1055 GNUNET_free_non_null (rr->payload); 826 GNUNET_free_non_null (rr->payload);
1056 rr->payload = GNUNET_malloc (r); 827 rr->payload = GNUNET_malloc (r);
1057 memcpy (rr->payload, buf, r); 828 memcpy (rr->payload, dns, r);
1058 rr->payload_length = r; 829 rr->payload_length = r;
1059 next_phase (rr); 830 next_phase (rr);
1060 }
1061 return GNUNET_OK;
1062}
1063
1064
1065/**
1066 * Read a DNS response from the (unhindered) UDP-Socket
1067 *
1068 * @param cls socket to read from
1069 * @param tc scheduler context (must be shutdown or read ready)
1070 */
1071static void
1072read_response (void *cls,
1073 const struct GNUNET_SCHEDULER_TaskContext *tc)
1074{
1075 struct RequestSocket *rs = cls;
1076 struct GNUNET_NETWORK_FDSet *rset;
1077
1078 rs->read_task = GNUNET_SCHEDULER_NO_TASK;
1079 if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
1080 {
1081 /* timeout or shutdown */
1082 cleanup_rs (rs);
1083 return;
1084 }
1085 /* read and process ready sockets */
1086 if ((NULL != rs->dnsout4) &&
1087 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout4)) &&
1088 (GNUNET_SYSERR == do_dns_read (rs->dnsout4)))
1089 rs->dnsout4 = NULL;
1090 if ((NULL != rs->dnsout6) &&
1091 (GNUNET_NETWORK_fdset_isset (tc->read_ready, rs->dnsout6)) &&
1092 (GNUNET_SYSERR == do_dns_read (rs->dnsout6)))
1093 rs->dnsout6 = NULL;
1094
1095 /* re-schedule read task */
1096 rset = GNUNET_NETWORK_fdset_create ();
1097 if (NULL != rs->dnsout4)
1098 GNUNET_NETWORK_fdset_set (rset, rs->dnsout4);
1099 if (NULL != rs->dnsout6)
1100 GNUNET_NETWORK_fdset_set (rset, rs->dnsout6);
1101 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1102 GNUNET_TIME_absolute_get_remaining (rs->timeout),
1103 rset,
1104 NULL,
1105 &read_response, rs);
1106 GNUNET_NETWORK_fdset_destroy (rset);
1107} 831}
1108 832
1109 833
@@ -1410,11 +1134,7 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1410 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader); 1134 size_t dlen = mlen - sizeof (struct GNUNET_MessageHeader);
1411 char buf[dlen] GNUNET_ALIGN; 1135 char buf[dlen] GNUNET_ALIGN;
1412 struct GNUNET_TUN_DnsHeader *dout; 1136 struct GNUNET_TUN_DnsHeader *dout;
1413 struct sockaddr_in v4; 1137
1414 struct sockaddr_in6 v6;
1415 struct sockaddr *so;
1416 socklen_t salen;
1417
1418 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader)) 1138 if (dlen < sizeof (struct GNUNET_TUN_DnsHeader))
1419 { 1139 {
1420 GNUNET_break_op (0); 1140 GNUNET_break_op (0);
@@ -1428,51 +1148,14 @@ receive_dns_request (void *cls GNUNET_UNUSED, struct GNUNET_MESH_Tunnel *tunnel,
1428 UINT16_MAX + 1); 1148 UINT16_MAX + 1);
1429 tunnels[ts->my_id] = ts; 1149 tunnels[ts->my_id] = ts;
1430 memcpy (buf, dns, dlen); 1150 memcpy (buf, dns, dlen);
1431 dout = (struct GNUNET_TUN_DnsHeader*) buf; 1151 dout = (struct GNUNET_TUN_DnsHeader *) buf;
1432 dout->id = ts->my_id; 1152 dout->id = ts->my_id;
1433 memset (&v4, 0, sizeof (v4)); 1153 ts->rs = GNUNET_DNSSTUB_resolve2 (dnsstub,
1434 memset (&v6, 0, sizeof (v6)); 1154 buf, dlen,
1435 if (1 == inet_pton (AF_INET, dns_exit, &v4.sin_addr)) 1155 &process_dns_result,
1436 { 1156 NULL);
1437 salen = sizeof (v4); 1157 if (NULL == ts->rs)
1438 v4.sin_family = AF_INET;
1439 v4.sin_port = htons (53);
1440#if HAVE_SOCKADDR_IN_SIN_LEN
1441 v4.sin_len = (u_char) salen;
1442#endif
1443 so = (struct sockaddr *) &v4;
1444 ts->dnsout = get_request_socket (AF_INET);
1445 }
1446 else if (1 == inet_pton (AF_INET6, dns_exit, &v6.sin6_addr))
1447 {
1448 salen = sizeof (v6);
1449 v6.sin6_family = AF_INET6;
1450 v6.sin6_port = htons (53);
1451#if HAVE_SOCKADDR_IN_SIN_LEN
1452 v6.sin6_len = (u_char) salen;
1453#endif
1454 so = (struct sockaddr *) &v6;
1455 ts->dnsout = get_request_socket (AF_INET6);
1456 }
1457 else
1458 {
1459 GNUNET_break (0);
1460 return GNUNET_SYSERR; 1158 return GNUNET_SYSERR;
1461 }
1462 if (NULL == ts->dnsout)
1463 {
1464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1465 _("Configured DNS exit `%s' is not working / valid.\n"),
1466 dns_exit);
1467 return GNUNET_SYSERR;
1468 }
1469 memcpy (&ts->addr,
1470 so,
1471 salen);
1472 ts->addrlen = salen;
1473 GNUNET_NETWORK_socket_sendto (ts->dnsout,
1474 buf, dlen, so, salen);
1475 ts->timeout = GNUNET_TIME_relative_to_absolute (REQUEST_TIMEOUT);
1476 return GNUNET_OK; 1159 return GNUNET_OK;
1477} 1160}
1478 1161
@@ -1552,6 +1235,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1552 char *ipv6prefix; 1235 char *ipv6prefix;
1553 struct in_addr dns_exit4; 1236 struct in_addr dns_exit4;
1554 struct in6_addr dns_exit6; 1237 struct in6_addr dns_exit6;
1238 char *dns_exit;
1555 1239
1556 cfg = cfg_; 1240 cfg = cfg_;
1557 if (GNUNET_YES != 1241 if (GNUNET_YES !=
@@ -1582,7 +1266,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server,
1582 GNUNET_free_non_null (dns_exit); 1266 GNUNET_free_non_null (dns_exit);
1583 dns_exit = NULL; 1267 dns_exit = NULL;
1584 } 1268 }
1585 1269 dnsstub = GNUNET_DNSSTUB_start (dns_exit);
1586 helper_argv[0] = GNUNET_strdup ("gnunet-dns"); 1270 helper_argv[0] = GNUNET_strdup ("gnunet-dns");
1587 if (GNUNET_SYSERR == 1271 if (GNUNET_SYSERR ==
1588 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name)) 1272 GNUNET_CONFIGURATION_get_value_string (cfg, "dns", "IFNAME", &ifc_name))
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index 8a326e1bf..4bde4fbbb 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -40,6 +40,7 @@ gnunetinclude_HEADERS = \
40 gnunet_dht_service.h \ 40 gnunet_dht_service.h \
41 gnunet_disk_lib.h \ 41 gnunet_disk_lib.h \
42 gnunet_dnsparser_lib.h \ 42 gnunet_dnsparser_lib.h \
43 gnunet_dnsstub_lib.h \
43 gnunet_dns_service.h \ 44 gnunet_dns_service.h \
44 gnunet_dv_service.h \ 45 gnunet_dv_service.h \
45 gnunet_fragmentation_lib.h \ 46 gnunet_fragmentation_lib.h \
diff --git a/src/include/gnunet_dnsstub_lib.h b/src/include/gnunet_dnsstub_lib.h
new file mode 100644
index 000000000..ffe82dbbe
--- /dev/null
+++ b/src/include/gnunet_dnsstub_lib.h
@@ -0,0 +1,115 @@
1/*
2 This file is part of GNUnet
3 (C) 2012 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 include/gnunet_dnsstub_lib.h
23 * @brief API for helper library to send DNS requests to DNS resolver
24 * @author Christian Grothoff
25 */
26#ifndef GNUNET_DNSSTUB_LIB_H
27#define GNUNET_DNSSTUB_LIB_H
28
29#include "gnunet_common.h"
30#include "gnunet_tun_lib.h"
31
32/**
33 * Opaque handle to the stub resolver.
34 */
35struct GNUNET_DNSSTUB_Context;
36
37/**
38 * Opaque handle to a socket doing UDP requests.
39 */
40struct GNUNET_DNSSTUB_RequestSocket;
41
42
43/**
44 * Start a DNS stub resolver.
45 *
46 * @param dns_ip target IP address to use
47 * @return NULL on error
48 */
49struct GNUNET_DNSSTUB_Context *
50GNUNET_DNSSTUB_start (const char *dns_ip);
51
52
53/**
54 * Cleanup DNSSTUB resolver.
55 *
56 * @param ctx stub resolver to clean up
57 */
58void
59GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx);
60
61
62/**
63 * Function called with the result of a DNS resolution.
64 *
65 * @param cls closure
66 * @param rs socket that received the response
67 * @param dns dns response, never NULL
68 * @param dns_len number of bytes in 'dns'
69 */
70typedef void (*GNUNET_DNSSTUB_ResultCallback)(void *cls,
71 struct GNUNET_DNSSTUB_RequestSocket *rs,
72 const struct GNUNET_TUN_DnsHeader *dns,
73 size_t dns_len);
74
75
76/**
77 * Perform DNS resolution using given address.
78 *
79 * @param ctx stub resolver to use
80 * @param af address family to use
81 * @param request DNS request to transmit
82 * @param request_len number of bytes in msg
83 * @param rc function to call with result
84 * @param rc_cls closure for 'rc'
85 * @return socket used for the request, NULL on error
86 */
87struct GNUNET_DNSSTUB_RequestSocket *
88GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
89 const struct sockaddr *sa,
90 socklen_t sa_len,
91 const void *request,
92 size_t request_len,
93 GNUNET_DNSSTUB_ResultCallback rc,
94 void *rc_cls);
95
96
97/**
98 * Perform DNS resolution using our default IP from init.
99 *
100 * @param ctx stub resolver to use
101 * @param request DNS request to transmit
102 * @param request_len number of bytes in msg
103 * @param rc function to call with result
104 * @param rc_cls closure for 'rc'
105 * @return socket used for the request, NULL on error
106 */
107struct GNUNET_DNSSTUB_RequestSocket *
108GNUNET_DNSSTUB_resolve2 (struct GNUNET_DNSSTUB_Context *ctx,
109 const void *request,
110 size_t request_len,
111 GNUNET_DNSSTUB_ResultCallback rc,
112 void *rc_cls);
113
114
115#endif