aboutsummaryrefslogtreecommitdiff
path: root/src/dns
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-06-25 18:07:22 +0200
committerChristian Grothoff <christian@grothoff.org>2018-06-25 18:08:27 +0200
commit7da98cf076e9c5101244dfbbf8c3ddff045d298e (patch)
treedb4b4b28d0864cf5f7d424c40f1e7f4d945ff726 /src/dns
parentb96052f1d3b8bb05f1868bd809fcb6e4f6569a4c (diff)
downloadgnunet-7da98cf076e9c5101244dfbbf8c3ddff045d298e.tar.gz
gnunet-7da98cf076e9c5101244dfbbf8c3ddff045d298e.zip
integrate dnsparser and dnsstub and tun with libgnunetutil
Diffstat (limited to 'src/dns')
-rw-r--r--src/dns/Makefile.am34
-rw-r--r--src/dns/dnsparser.c1334
-rw-r--r--src/dns/dnsstub.c749
-rw-r--r--src/dns/test_hexcoder.c54
4 files changed, 0 insertions, 2171 deletions
diff --git a/src/dns/Makefile.am b/src/dns/Makefile.am
index 9a4ecdcfd..ca2685765 100644
--- a/src/dns/Makefile.am
+++ b/src/dns/Makefile.am
@@ -27,8 +27,6 @@ install-exec-hook:
27endif 27endif
28 28
29lib_LTLIBRARIES = \ 29lib_LTLIBRARIES = \
30 libgnunetdnsparser.la \
31 libgnunetdnsstub.la \
32 libgnunetdns.la 30 libgnunetdns.la
33 31
34libexec_PROGRAMS = \ 32libexec_PROGRAMS = \
@@ -47,9 +45,6 @@ check_SCRIPTS = \
47 test_gnunet_dns.sh 45 test_gnunet_dns.sh
48endif 46endif
49 47
50check_PROGRAMS = \
51 test_hexcoder
52
53gnunet_helper_dns_SOURCES = \ 48gnunet_helper_dns_SOURCES = \
54 gnunet-helper-dns.c 49 gnunet-helper-dns.c
55 50
@@ -57,7 +52,6 @@ gnunet_helper_dns_SOURCES = \
57gnunet_dns_monitor_SOURCES = \ 52gnunet_dns_monitor_SOURCES = \
58 gnunet-dns-monitor.c 53 gnunet-dns-monitor.c
59gnunet_dns_monitor_LDADD = \ 54gnunet_dns_monitor_LDADD = \
60 libgnunetdnsparser.la \
61 libgnunetdns.la \ 55 libgnunetdns.la \
62 $(top_builddir)/src/util/libgnunetutil.la \ 56 $(top_builddir)/src/util/libgnunetutil.la \
63 $(GN_LIBINTL) 57 $(GN_LIBINTL)
@@ -65,15 +59,12 @@ gnunet_dns_monitor_LDADD = \
65gnunet_zonewalk_SOURCES = \ 59gnunet_zonewalk_SOURCES = \
66 gnunet-zonewalk.c 60 gnunet-zonewalk.c
67gnunet_zonewalk_LDADD = \ 61gnunet_zonewalk_LDADD = \
68 libgnunetdnsparser.la \
69 libgnunetdnsstub.la \
70 $(top_builddir)/src/util/libgnunetutil.la \ 62 $(top_builddir)/src/util/libgnunetutil.la \
71 $(GN_LIBINTL) 63 $(GN_LIBINTL)
72 64
73gnunet_dns_redirector_SOURCES = \ 65gnunet_dns_redirector_SOURCES = \
74 gnunet-dns-redirector.c 66 gnunet-dns-redirector.c
75gnunet_dns_redirector_LDADD = \ 67gnunet_dns_redirector_LDADD = \
76 libgnunetdnsparser.la \
77 libgnunetdns.la \ 68 libgnunetdns.la \
78 $(top_builddir)/src/util/libgnunetutil.la \ 69 $(top_builddir)/src/util/libgnunetutil.la \
79 $(GN_LIBINTL) 70 $(GN_LIBINTL)
@@ -81,30 +72,10 @@ gnunet_dns_redirector_LDADD = \
81gnunet_service_dns_SOURCES = \ 72gnunet_service_dns_SOURCES = \
82 gnunet-service-dns.c 73 gnunet-service-dns.c
83gnunet_service_dns_LDADD = \ 74gnunet_service_dns_LDADD = \
84 libgnunetdnsstub.la \
85 $(top_builddir)/src/tun/libgnunettun.la \
86 $(top_builddir)/src/statistics/libgnunetstatistics.la \ 75 $(top_builddir)/src/statistics/libgnunetstatistics.la \
87 $(top_builddir)/src/util/libgnunetutil.la \ 76 $(top_builddir)/src/util/libgnunetutil.la \
88 $(GN_LIBINTL) 77 $(GN_LIBINTL)
89 78
90libgnunetdnsparser_la_SOURCES = \
91 dnsparser.c
92libgnunetdnsparser_la_LIBADD = \
93 $(top_builddir)/src/util/libgnunetutil.la $(XLIB) \
94 -lidn
95libgnunetdnsparser_la_LDFLAGS = \
96 $(GN_LIB_LDFLAGS) \
97 -version-info 1:0:1
98
99libgnunetdnsstub_la_SOURCES = \
100 dnsstub.c
101libgnunetdnsstub_la_LIBADD = \
102 $(top_builddir)/src/tun/libgnunettun.la \
103 $(top_builddir)/src/util/libgnunetutil.la $(XLIB)
104libgnunetdnsstub_la_LDFLAGS = \
105 $(GN_LIB_LDFLAGS) \
106 -version-info 0:0:0
107
108libgnunetdns_la_SOURCES = \ 79libgnunetdns_la_SOURCES = \
109 dns_api.c dns.h 80 dns_api.c dns.h
110libgnunetdns_la_LIBADD = \ 81libgnunetdns_la_LIBADD = \
@@ -131,8 +102,3 @@ EXTRA_DIST = \
131 $(check_SCRIPTS) 102 $(check_SCRIPTS)
132 103
133 104
134test_hexcoder_SOURCES = \
135 test_hexcoder.c
136test_hexcoder_LDADD = \
137 libgnunetdnsparser.la \
138 $(top_builddir)/src/util/libgnunetutil.la
diff --git a/src/dns/dnsparser.c b/src/dns/dnsparser.c
deleted file mode 100644
index 32ad7c0c2..000000000
--- a/src/dns/dnsparser.c
+++ /dev/null
@@ -1,1334 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014 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
19/**
20 * @file dns/dnsparser.c
21 * @brief helper library to parse DNS packets.
22 * @author Philipp Toelke
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include <idna.h>
27#if WINDOWS
28#include <idn-free.h>
29#endif
30#include "gnunet_util_lib.h"
31#include "gnunet_dnsparser_lib.h"
32#include "gnunet_tun_lib.h"
33
34
35/**
36 * Check if a label in UTF-8 format can be coded into valid IDNA.
37 * This can fail if the ASCII-conversion becomes longer than 63 characters.
38 *
39 * @param label label to check (UTF-8 string)
40 * @return #GNUNET_OK if the label can be converted to IDNA,
41 * #GNUNET_SYSERR if the label is not valid for DNS names
42 */
43int
44GNUNET_DNSPARSER_check_label (const char *label)
45{
46 char *output;
47 size_t slen;
48
49 if (NULL != strchr (label, '.'))
50 return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */
51 if (IDNA_SUCCESS !=
52 idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED))
53 return GNUNET_SYSERR;
54 slen = strlen (output);
55#if WINDOWS
56 idn_free (output);
57#else
58 free (output);
59#endif
60 return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK;
61}
62
63
64/**
65 * Check if a label in UTF-8 format can be coded into valid IDNA.
66 * This can fail if the ASCII-conversion becomes longer than 253 characters.
67 *
68 * @param name name to check (UTF-8 string)
69 * @return #GNUNET_OK if the label can be converted to IDNA,
70 * #GNUNET_SYSERR if the label is not valid for DNS names
71 */
72int
73GNUNET_DNSPARSER_check_name (const char *name)
74{
75 char *ldup;
76 char *output;
77 size_t slen;
78 char *tok;
79
80 ldup = GNUNET_strdup (name);
81 for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, "."))
82 if (GNUNET_OK !=
83 GNUNET_DNSPARSER_check_label (tok))
84 {
85 GNUNET_free (ldup);
86 return GNUNET_SYSERR;
87 }
88 GNUNET_free (ldup);
89 if (IDNA_SUCCESS !=
90 idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED))
91 return GNUNET_SYSERR;
92 slen = strlen (output);
93#if WINDOWS
94 idn_free (output);
95#else
96 free (output);
97#endif
98 return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK;
99}
100
101
102/**
103 * Free SOA information record.
104 *
105 * @param soa record to free
106 */
107void
108GNUNET_DNSPARSER_free_soa (struct GNUNET_DNSPARSER_SoaRecord *soa)
109{
110 if (NULL == soa)
111 return;
112 GNUNET_free_non_null (soa->mname);
113 GNUNET_free_non_null (soa->rname);
114 GNUNET_free (soa);
115}
116
117
118/**
119 * Free CERT information record.
120 *
121 * @param cert record to free
122 */
123void
124GNUNET_DNSPARSER_free_cert (struct GNUNET_DNSPARSER_CertRecord *cert)
125{
126 if (NULL == cert)
127 return;
128 GNUNET_free_non_null (cert->certificate_data);
129 GNUNET_free (cert);
130}
131
132
133/**
134 * Free SRV information record.
135 *
136 * @param srv record to free
137 */
138void
139GNUNET_DNSPARSER_free_srv (struct GNUNET_DNSPARSER_SrvRecord *srv)
140{
141 if (NULL == srv)
142 return;
143 GNUNET_free_non_null (srv->target);
144 GNUNET_free (srv);
145}
146
147
148/**
149 * Free MX information record.
150 *
151 * @param mx record to free
152 */
153void
154GNUNET_DNSPARSER_free_mx (struct GNUNET_DNSPARSER_MxRecord *mx)
155{
156 if (NULL == mx)
157 return;
158 GNUNET_free_non_null (mx->mxhost);
159 GNUNET_free (mx);
160}
161
162
163/**
164 * Free the given DNS record.
165 *
166 * @param r record to free
167 */
168void
169GNUNET_DNSPARSER_free_record (struct GNUNET_DNSPARSER_Record *r)
170{
171 GNUNET_free_non_null (r->name);
172 switch (r->type)
173 {
174 case GNUNET_DNSPARSER_TYPE_MX:
175 GNUNET_DNSPARSER_free_mx (r->data.mx);
176 break;
177 case GNUNET_DNSPARSER_TYPE_SOA:
178 GNUNET_DNSPARSER_free_soa (r->data.soa);
179 break;
180 case GNUNET_DNSPARSER_TYPE_SRV:
181 GNUNET_DNSPARSER_free_srv (r->data.srv);
182 break;
183 case GNUNET_DNSPARSER_TYPE_CERT:
184 GNUNET_DNSPARSER_free_cert (r->data.cert);
185 break;
186 case GNUNET_DNSPARSER_TYPE_NS:
187 case GNUNET_DNSPARSER_TYPE_CNAME:
188 case GNUNET_DNSPARSER_TYPE_PTR:
189 GNUNET_free_non_null (r->data.hostname);
190 break;
191 default:
192 GNUNET_free_non_null (r->data.raw.data);
193 break;
194 }
195}
196
197
198/**
199 * Parse name inside of a DNS query or record.
200 *
201 * @param udp_payload entire UDP payload
202 * @param udp_payload_length length of @a udp_payload
203 * @param off pointer to the offset of the name to parse in the udp_payload (to be
204 * incremented by the size of the name)
205 * @param depth current depth of our recursion (to prevent stack overflow)
206 * @return name as 0-terminated C string on success, NULL if the payload is malformed
207 */
208static char *
209parse_name (const char *udp_payload,
210 size_t udp_payload_length,
211 size_t *off,
212 unsigned int depth)
213{
214 const uint8_t *input = (const uint8_t *) udp_payload;
215 char *ret;
216 char *tmp;
217 char *xstr;
218 uint8_t len;
219 size_t xoff;
220 char *utf8;
221 Idna_rc rc;
222
223 ret = GNUNET_strdup ("");
224 while (1)
225 {
226 if (*off >= udp_payload_length)
227 {
228 GNUNET_break_op (0);
229 goto error;
230 }
231 len = input[*off];
232 if (0 == len)
233 {
234 (*off)++;
235 break;
236 }
237 if (len < 64)
238 {
239 if (*off + 1 + len > udp_payload_length)
240 {
241 GNUNET_break_op (0);
242 goto error;
243 }
244 GNUNET_asprintf (&tmp,
245 "%.*s",
246 (int) len,
247 &udp_payload[*off + 1]);
248 if (IDNA_SUCCESS !=
249 (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED)))
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252 _("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"),
253 tmp,
254 idna_strerror (rc));
255 GNUNET_free (tmp);
256 GNUNET_asprintf (&tmp,
257 "%s%.*s.",
258 ret,
259 (int) len,
260 &udp_payload[*off + 1]);
261 }
262 else
263 {
264 GNUNET_free (tmp);
265 GNUNET_asprintf (&tmp,
266 "%s%s.",
267 ret,
268 utf8);
269#if WINDOWS
270 idn_free (utf8);
271#else
272 free (utf8);
273#endif
274 }
275 GNUNET_free (ret);
276 ret = tmp;
277 *off += 1 + len;
278 }
279 else if ((64 | 128) == (len & (64 | 128)) )
280 {
281 if (depth > 32)
282 {
283 GNUNET_break_op (0);
284 goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */
285 }
286 /* pointer to string */
287 if (*off + 1 > udp_payload_length)
288 {
289 GNUNET_break_op (0);
290 goto error;
291 }
292 xoff = ((len - (64 | 128)) << 8) + input[*off+1];
293 xstr = parse_name (udp_payload,
294 udp_payload_length,
295 &xoff,
296 depth + 1);
297 if (NULL == xstr)
298 {
299 GNUNET_break_op (0);
300 goto error;
301 }
302 GNUNET_asprintf (&tmp,
303 "%s%s.",
304 ret,
305 xstr);
306 GNUNET_free (ret);
307 GNUNET_free (xstr);
308 ret = tmp;
309 if (strlen (ret) > udp_payload_length)
310 {
311 GNUNET_break_op (0);
312 goto error; /* we are looping (building an infinite string) */
313 }
314 *off += 2;
315 /* pointers always terminate names */
316 break;
317 }
318 else
319 {
320 /* neither pointer nor inline string, not supported... */
321 GNUNET_break_op (0);
322 goto error;
323 }
324 }
325 if (0 < strlen(ret))
326 ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */
327 return ret;
328 error:
329 GNUNET_break_op (0);
330 GNUNET_free (ret);
331 return NULL;
332}
333
334
335/**
336 * Parse name inside of a DNS query or record.
337 *
338 * @param udp_payload entire UDP payload
339 * @param udp_payload_length length of @a udp_payload
340 * @param off pointer to the offset of the name to parse in the udp_payload (to be
341 * incremented by the size of the name)
342 * @return name as 0-terminated C string on success, NULL if the payload is malformed
343 */
344char *
345GNUNET_DNSPARSER_parse_name (const char *udp_payload,
346 size_t udp_payload_length,
347 size_t *off)
348{
349 return parse_name (udp_payload, udp_payload_length, off, 0);
350}
351
352
353/**
354 * Parse a DNS query entry.
355 *
356 * @param udp_payload entire UDP payload
357 * @param udp_payload_length length of @a udp_payload
358 * @param off pointer to the offset of the query to parse in the udp_payload (to be
359 * incremented by the size of the query)
360 * @param q where to write the query information
361 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the query is malformed
362 */
363int
364GNUNET_DNSPARSER_parse_query (const char *udp_payload,
365 size_t udp_payload_length,
366 size_t *off,
367 struct GNUNET_DNSPARSER_Query *q)
368{
369 char *name;
370 struct GNUNET_TUN_DnsQueryLine ql;
371
372 name = GNUNET_DNSPARSER_parse_name (udp_payload,
373 udp_payload_length,
374 off);
375 if (NULL == name)
376 {
377 GNUNET_break_op (0);
378 return GNUNET_SYSERR;
379 }
380 q->name = name;
381 if (*off + sizeof (struct GNUNET_TUN_DnsQueryLine) > udp_payload_length)
382 {
383 GNUNET_break_op (0);
384 return GNUNET_SYSERR;
385 }
386 GNUNET_memcpy (&ql, &udp_payload[*off], sizeof (ql));
387 *off += sizeof (ql);
388 q->type = ntohs (ql.type);
389 q->dns_traffic_class = ntohs (ql.dns_traffic_class);
390 return GNUNET_OK;
391}
392
393
394/**
395 * Parse a DNS SOA record.
396 *
397 * @param udp_payload reference to UDP packet
398 * @param udp_payload_length length of @a udp_payload
399 * @param off pointer to the offset of the query to parse in the SOA record (to be
400 * incremented by the size of the record), unchanged on error
401 * @return the parsed SOA record, NULL on error
402 */
403struct GNUNET_DNSPARSER_SoaRecord *
404GNUNET_DNSPARSER_parse_soa (const char *udp_payload,
405 size_t udp_payload_length,
406 size_t *off)
407{
408 struct GNUNET_DNSPARSER_SoaRecord *soa;
409 struct GNUNET_TUN_DnsSoaRecord soa_bin;
410 size_t old_off;
411
412 old_off = *off;
413 soa = GNUNET_new (struct GNUNET_DNSPARSER_SoaRecord);
414 soa->mname = GNUNET_DNSPARSER_parse_name (udp_payload,
415 udp_payload_length,
416 off);
417 soa->rname = GNUNET_DNSPARSER_parse_name (udp_payload,
418 udp_payload_length,
419 off);
420 if ( (NULL == soa->mname) ||
421 (NULL == soa->rname) ||
422 (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > udp_payload_length) )
423 {
424 GNUNET_break_op (0);
425 GNUNET_DNSPARSER_free_soa (soa);
426 *off = old_off;
427 return NULL;
428 }
429 GNUNET_memcpy (&soa_bin,
430 &udp_payload[*off],
431 sizeof (struct GNUNET_TUN_DnsSoaRecord));
432 soa->serial = ntohl (soa_bin.serial);
433 soa->refresh = ntohl (soa_bin.refresh);
434 soa->retry = ntohl (soa_bin.retry);
435 soa->expire = ntohl (soa_bin.expire);
436 soa->minimum_ttl = ntohl (soa_bin.minimum);
437 (*off) += sizeof (struct GNUNET_TUN_DnsSoaRecord);
438 return soa;
439}
440
441
442/**
443 * Parse a DNS MX record.
444 *
445 * @param udp_payload reference to UDP packet
446 * @param udp_payload_length length of @a udp_payload
447 * @param off pointer to the offset of the query to parse in the MX record (to be
448 * incremented by the size of the record), unchanged on error
449 * @return the parsed MX record, NULL on error
450 */
451struct GNUNET_DNSPARSER_MxRecord *
452GNUNET_DNSPARSER_parse_mx (const char *udp_payload,
453 size_t udp_payload_length,
454 size_t *off)
455{
456 struct GNUNET_DNSPARSER_MxRecord *mx;
457 uint16_t mxpref;
458 size_t old_off;
459
460 old_off = *off;
461 if (*off + sizeof (uint16_t) > udp_payload_length)
462 {
463 GNUNET_break_op (0);
464 return NULL;
465 }
466 GNUNET_memcpy (&mxpref, &udp_payload[*off], sizeof (uint16_t));
467 (*off) += sizeof (uint16_t);
468 mx = GNUNET_new (struct GNUNET_DNSPARSER_MxRecord);
469 mx->preference = ntohs (mxpref);
470 mx->mxhost = GNUNET_DNSPARSER_parse_name (udp_payload,
471 udp_payload_length,
472 off);
473 if (NULL == mx->mxhost)
474 {
475 GNUNET_break_op (0);
476 GNUNET_DNSPARSER_free_mx (mx);
477 *off = old_off;
478 return NULL;
479 }
480 return mx;
481}
482
483
484/**
485 * Parse a DNS SRV record.
486 *
487 * @param udp_payload reference to UDP packet
488 * @param udp_payload_length length of @a udp_payload
489 * @param off pointer to the offset of the query to parse in the SRV record (to be
490 * incremented by the size of the record), unchanged on error
491 * @return the parsed SRV record, NULL on error
492 */
493struct GNUNET_DNSPARSER_SrvRecord *
494GNUNET_DNSPARSER_parse_srv (const char *udp_payload,
495 size_t udp_payload_length,
496 size_t *off)
497{
498 struct GNUNET_DNSPARSER_SrvRecord *srv;
499 struct GNUNET_TUN_DnsSrvRecord srv_bin;
500 size_t old_off;
501
502 old_off = *off;
503 if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > udp_payload_length)
504 return NULL;
505 GNUNET_memcpy (&srv_bin,
506 &udp_payload[*off],
507 sizeof (struct GNUNET_TUN_DnsSrvRecord));
508 (*off) += sizeof (struct GNUNET_TUN_DnsSrvRecord);
509 srv = GNUNET_new (struct GNUNET_DNSPARSER_SrvRecord);
510 srv->priority = ntohs (srv_bin.prio);
511 srv->weight = ntohs (srv_bin.weight);
512 srv->port = ntohs (srv_bin.port);
513 srv->target = GNUNET_DNSPARSER_parse_name (udp_payload,
514 udp_payload_length,
515 off);
516 if (NULL == srv->target)
517 {
518 GNUNET_DNSPARSER_free_srv (srv);
519 *off = old_off;
520 return NULL;
521 }
522 return srv;
523}
524
525
526/**
527 * Parse a DNS CERT record.
528 *
529 * @param udp_payload reference to UDP packet
530 * @param udp_payload_length length of @a udp_payload
531 * @param off pointer to the offset of the query to parse in the CERT record (to be
532 * incremented by the size of the record), unchanged on error
533 * @return the parsed CERT record, NULL on error
534 */
535struct GNUNET_DNSPARSER_CertRecord *
536GNUNET_DNSPARSER_parse_cert (const char *udp_payload,
537 size_t udp_payload_length,
538 size_t *off)
539{
540 struct GNUNET_DNSPARSER_CertRecord *cert;
541 struct GNUNET_TUN_DnsCertRecord dcert;
542
543 if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) >= udp_payload_length)
544 {
545 GNUNET_break_op (0);
546 return NULL;
547 }
548 GNUNET_memcpy (&dcert, &udp_payload[*off], sizeof (struct GNUNET_TUN_DnsCertRecord));
549 (*off) += sizeof (struct GNUNET_TUN_DnsCertRecord);
550 cert = GNUNET_new (struct GNUNET_DNSPARSER_CertRecord);
551 cert->cert_type = ntohs (dcert.cert_type);
552 cert->cert_tag = ntohs (dcert.cert_tag);
553 cert->algorithm = dcert.algorithm;
554 cert->certificate_size = udp_payload_length - (*off);
555 cert->certificate_data = GNUNET_malloc (cert->certificate_size);
556 GNUNET_memcpy (cert->certificate_data,
557 &udp_payload[*off],
558 cert->certificate_size);
559 (*off) += cert->certificate_size;
560 return cert;
561}
562
563
564/**
565 * Parse a DNS record entry.
566 *
567 * @param udp_payload entire UDP payload
568 * @param udp_payload_length length of @a udp_payload
569 * @param off pointer to the offset of the record to parse in the udp_payload (to be
570 * incremented by the size of the record)
571 * @param r where to write the record information
572 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the record is malformed
573 */
574int
575GNUNET_DNSPARSER_parse_record (const char *udp_payload,
576 size_t udp_payload_length,
577 size_t *off,
578 struct GNUNET_DNSPARSER_Record *r)
579{
580 char *name;
581 struct GNUNET_TUN_DnsRecordLine rl;
582 size_t old_off;
583 uint16_t data_len;
584
585 name = GNUNET_DNSPARSER_parse_name (udp_payload,
586 udp_payload_length,
587 off);
588 if (NULL == name)
589 {
590 GNUNET_break_op (0);
591 return GNUNET_SYSERR;
592 }
593 r->name = name;
594 if (*off + sizeof (struct GNUNET_TUN_DnsRecordLine) > udp_payload_length)
595 {
596 GNUNET_break_op (0);
597 return GNUNET_SYSERR;
598 }
599 GNUNET_memcpy (&rl, &udp_payload[*off], sizeof (rl));
600 (*off) += sizeof (rl);
601 r->type = ntohs (rl.type);
602 r->dns_traffic_class = ntohs (rl.dns_traffic_class);
603 r->expiration_time = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,
604 ntohl (rl.ttl)));
605 data_len = ntohs (rl.data_len);
606 if (*off + data_len > udp_payload_length)
607 {
608 GNUNET_break_op (0);
609 return GNUNET_SYSERR;
610 }
611 old_off = *off;
612 switch (r->type)
613 {
614 case GNUNET_DNSPARSER_TYPE_NS:
615 case GNUNET_DNSPARSER_TYPE_CNAME:
616 case GNUNET_DNSPARSER_TYPE_DNAME:
617 case GNUNET_DNSPARSER_TYPE_PTR:
618 r->data.hostname = GNUNET_DNSPARSER_parse_name (udp_payload,
619 udp_payload_length,
620 off);
621 if ( (NULL == r->data.hostname) ||
622 (old_off + data_len != *off) )
623 return GNUNET_SYSERR;
624 return GNUNET_OK;
625 case GNUNET_DNSPARSER_TYPE_SOA:
626 r->data.soa = GNUNET_DNSPARSER_parse_soa (udp_payload,
627 udp_payload_length,
628 off);
629 if ( (NULL == r->data.soa) ||
630 (old_off + data_len != *off) )
631 {
632 GNUNET_break_op (0);
633 return GNUNET_SYSERR;
634 }
635 return GNUNET_OK;
636 case GNUNET_DNSPARSER_TYPE_MX:
637 r->data.mx = GNUNET_DNSPARSER_parse_mx (udp_payload,
638 udp_payload_length,
639 off);
640 if ( (NULL == r->data.mx) ||
641 (old_off + data_len != *off) )
642 {
643 GNUNET_break_op (0);
644 return GNUNET_SYSERR;
645 }
646 return GNUNET_OK;
647 case GNUNET_DNSPARSER_TYPE_SRV:
648 r->data.srv = GNUNET_DNSPARSER_parse_srv (udp_payload,
649 udp_payload_length,
650 off);
651 if ( (NULL == r->data.srv) ||
652 (old_off + data_len != *off) )
653 {
654 GNUNET_break_op (0);
655 return GNUNET_SYSERR;
656 }
657 return GNUNET_OK;
658 default:
659 r->data.raw.data = GNUNET_malloc (data_len);
660 r->data.raw.data_len = data_len;
661 GNUNET_memcpy (r->data.raw.data,
662 &udp_payload[*off],
663 data_len);
664 break;
665 }
666 (*off) += data_len;
667 return GNUNET_OK;
668}
669
670
671/**
672 * Parse a UDP payload of a DNS packet in to a nice struct for further
673 * processing and manipulation.
674 *
675 * @param udp_payload wire-format of the DNS packet
676 * @param udp_payload_length number of bytes in @a udp_payload
677 * @return NULL on error, otherwise the parsed packet
678 */
679struct GNUNET_DNSPARSER_Packet *
680GNUNET_DNSPARSER_parse (const char *udp_payload,
681 size_t udp_payload_length)
682{
683 struct GNUNET_DNSPARSER_Packet *p;
684 const struct GNUNET_TUN_DnsHeader *dns;
685 size_t off;
686 unsigned int n;
687 unsigned int i;
688
689 if (udp_payload_length < sizeof (struct GNUNET_TUN_DnsHeader))
690 return NULL;
691 dns = (const struct GNUNET_TUN_DnsHeader *) udp_payload;
692 off = sizeof (struct GNUNET_TUN_DnsHeader);
693 p = GNUNET_new (struct GNUNET_DNSPARSER_Packet);
694 p->flags = dns->flags;
695 p->id = dns->id;
696 n = ntohs (dns->query_count);
697 if (n > 0)
698 {
699 p->queries = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Query));
700 p->num_queries = n;
701 for (i=0;i<n;i++)
702 if (GNUNET_OK !=
703 GNUNET_DNSPARSER_parse_query (udp_payload,
704 udp_payload_length,
705 &off,
706 &p->queries[i]))
707 goto error;
708 }
709 n = ntohs (dns->answer_rcount);
710 if (n > 0)
711 {
712 p->answers = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
713 p->num_answers = n;
714 for (i=0;i<n;i++)
715 if (GNUNET_OK !=
716 GNUNET_DNSPARSER_parse_record (udp_payload,
717 udp_payload_length,
718 &off,
719 &p->answers[i]))
720 goto error;
721 }
722 n = ntohs (dns->authority_rcount);
723 if (n > 0)
724 {
725 p->authority_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
726 p->num_authority_records = n;
727 for (i=0;i<n;i++)
728 if (GNUNET_OK !=
729 GNUNET_DNSPARSER_parse_record (udp_payload,
730 udp_payload_length,
731 &off,
732 &p->authority_records[i]))
733 goto error;
734 }
735 n = ntohs (dns->additional_rcount);
736 if (n > 0)
737 {
738 p->additional_records = GNUNET_malloc (n * sizeof (struct GNUNET_DNSPARSER_Record));
739 p->num_additional_records = n;
740 for (i=0;i<n;i++)
741 if (GNUNET_OK !=
742 GNUNET_DNSPARSER_parse_record (udp_payload,
743 udp_payload_length,
744 &off,
745 &p->additional_records[i]))
746 goto error;
747 }
748 return p;
749 error:
750 GNUNET_break_op (0);
751 GNUNET_DNSPARSER_free_packet (p);
752 return NULL;
753}
754
755
756/**
757 * Free memory taken by a packet.
758 *
759 * @param p packet to free
760 */
761void
762GNUNET_DNSPARSER_free_packet (struct GNUNET_DNSPARSER_Packet *p)
763{
764 unsigned int i;
765
766 for (i=0;i<p->num_queries;i++)
767 GNUNET_free_non_null (p->queries[i].name);
768 GNUNET_free_non_null (p->queries);
769 for (i=0;i<p->num_answers;i++)
770 GNUNET_DNSPARSER_free_record (&p->answers[i]);
771 GNUNET_free_non_null (p->answers);
772 for (i=0;i<p->num_authority_records;i++)
773 GNUNET_DNSPARSER_free_record (&p->authority_records[i]);
774 GNUNET_free_non_null (p->authority_records);
775 for (i=0;i<p->num_additional_records;i++)
776 GNUNET_DNSPARSER_free_record (&p->additional_records[i]);
777 GNUNET_free_non_null (p->additional_records);
778 GNUNET_free (p);
779}
780
781
782/* ********************** DNS packet assembly code **************** */
783
784
785/**
786 * Add a DNS name to the UDP packet at the given location, converting
787 * the name to IDNA notation as necessary.
788 *
789 * @param dst where to write the name (UDP packet)
790 * @param dst_len number of bytes in @a dst
791 * @param off pointer to offset where to write the name (increment by bytes used)
792 * must not be changed if there is an error
793 * @param name name to write
794 * @return #GNUNET_SYSERR if @a name is invalid
795 * #GNUNET_NO if @a name did not fit
796 * #GNUNET_OK if @a name was added to @a dst
797 */
798int
799GNUNET_DNSPARSER_builder_add_name (char *dst,
800 size_t dst_len,
801 size_t *off,
802 const char *name)
803{
804 const char *dot;
805 const char *idna_name;
806 char *idna_start;
807 size_t start;
808 size_t pos;
809 size_t len;
810 Idna_rc rc;
811
812 if (NULL == name)
813 return GNUNET_SYSERR;
814
815 if (IDNA_SUCCESS !=
816 (rc = idna_to_ascii_8z (name,
817 &idna_start,
818 IDNA_ALLOW_UNASSIGNED)))
819 {
820 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
821 _("Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"),
822 name,
823 idna_strerror (rc));
824 return GNUNET_NO;
825 }
826 idna_name = idna_start;
827 start = *off;
828 if (start + strlen (idna_name) + 2 > dst_len)
829 goto fail;
830 pos = start;
831 do
832 {
833 dot = strchr (idna_name, '.');
834 if (NULL == dot)
835 len = strlen (idna_name);
836 else
837 len = dot - idna_name;
838 if ( (len >= 64) || (0 == len) )
839 {
840 GNUNET_break (0);
841 goto fail; /* segment too long or empty */
842 }
843 dst[pos++] = (char) (uint8_t) len;
844 GNUNET_memcpy (&dst[pos],
845 idna_name,
846 len);
847 pos += len;
848 idna_name += len + 1; /* also skip dot */
849 }
850 while (NULL != dot);
851 dst[pos++] = '\0'; /* terminator */
852 *off = pos;
853#if WINDOWS
854 idn_free (idna_start);
855#else
856 free (idna_start);
857#endif
858 return GNUNET_OK;
859 fail:
860#if WINDOWS
861 idn_free (idna_start);
862#else
863 free (idna_start);
864#endif
865 return GNUNET_NO;
866}
867
868
869/**
870 * Add a DNS query to the UDP packet at the given location.
871 *
872 * @param dst where to write the query
873 * @param dst_len number of bytes in @a dst
874 * @param off pointer to offset where to write the query (increment by bytes used)
875 * must not be changed if there is an error
876 * @param query query to write
877 * @return #GNUNET_SYSERR if @a query is invalid
878 * #GNUNET_NO if @a query did not fit
879 * #GNUNET_OK if @a query was added to @a dst
880 */
881int
882GNUNET_DNSPARSER_builder_add_query (char *dst,
883 size_t dst_len,
884 size_t *off,
885 const struct GNUNET_DNSPARSER_Query *query)
886{
887 int ret;
888 struct GNUNET_TUN_DnsQueryLine ql;
889
890 ret = GNUNET_DNSPARSER_builder_add_name (dst, dst_len - sizeof (struct GNUNET_TUN_DnsQueryLine), off, query->name);
891 if (ret != GNUNET_OK)
892 return ret;
893 ql.type = htons (query->type);
894 ql.dns_traffic_class = htons (query->dns_traffic_class);
895 GNUNET_memcpy (&dst[*off], &ql, sizeof (ql));
896 (*off) += sizeof (ql);
897 return GNUNET_OK;
898}
899
900
901/**
902 * Add an MX record to the UDP packet at the given location.
903 *
904 * @param dst where to write the mx record
905 * @param dst_len number of bytes in @a dst
906 * @param off pointer to offset where to write the mx information (increment by bytes used);
907 * can also change if there was an error
908 * @param mx mx information to write
909 * @return #GNUNET_SYSERR if @a mx is invalid
910 * #GNUNET_NO if @a mx did not fit
911 * #GNUNET_OK if @a mx was added to @a dst
912 */
913int
914GNUNET_DNSPARSER_builder_add_mx (char *dst,
915 size_t dst_len,
916 size_t *off,
917 const struct GNUNET_DNSPARSER_MxRecord *mx)
918{
919 uint16_t mxpref;
920
921 if (*off + sizeof (uint16_t) > dst_len)
922 return GNUNET_NO;
923 mxpref = htons (mx->preference);
924 GNUNET_memcpy (&dst[*off],
925 &mxpref,
926 sizeof (mxpref));
927 (*off) += sizeof (mxpref);
928 return GNUNET_DNSPARSER_builder_add_name (dst,
929 dst_len,
930 off,
931 mx->mxhost);
932}
933
934
935/**
936 * Add a CERT record to the UDP packet at the given location.
937 *
938 * @param dst where to write the CERT record
939 * @param dst_len number of bytes in @a dst
940 * @param off pointer to offset where to write the CERT information (increment by bytes used);
941 * can also change if there was an error
942 * @param cert CERT information to write
943 * @return #GNUNET_SYSERR if @a cert is invalid
944 * #GNUNET_NO if @a cert did not fit
945 * #GNUNET_OK if @a cert was added to @a dst
946 */
947int
948GNUNET_DNSPARSER_builder_add_cert (char *dst,
949 size_t dst_len,
950 size_t *off,
951 const struct GNUNET_DNSPARSER_CertRecord *cert)
952{
953 struct GNUNET_TUN_DnsCertRecord dcert;
954
955 if ( (cert->cert_type > UINT16_MAX) ||
956 (cert->cert_tag > UINT16_MAX) ||
957 (cert->algorithm > UINT8_MAX) )
958 {
959 GNUNET_break (0);
960 return GNUNET_SYSERR;
961 }
962 if (*off + sizeof (struct GNUNET_TUN_DnsCertRecord) + cert->certificate_size > dst_len)
963 return GNUNET_NO;
964 dcert.cert_type = htons ((uint16_t) cert->cert_type);
965 dcert.cert_tag = htons ((uint16_t) cert->cert_tag);
966 dcert.algorithm = (uint8_t) cert->algorithm;
967 GNUNET_memcpy (&dst[*off], &dcert, sizeof (dcert));
968 (*off) += sizeof (dcert);
969 GNUNET_memcpy (&dst[*off], cert->certificate_data, cert->certificate_size);
970 (*off) += cert->certificate_size;
971 return GNUNET_OK;
972}
973
974
975/**
976 * Add an SOA record to the UDP packet at the given location.
977 *
978 * @param dst where to write the SOA record
979 * @param dst_len number of bytes in @a dst
980 * @param off pointer to offset where to write the SOA information (increment by bytes used)
981 * can also change if there was an error
982 * @param soa SOA information to write
983 * @return #GNUNET_SYSERR if @a soa is invalid
984 * #GNUNET_NO if @a soa did not fit
985 * #GNUNET_OK if @a soa was added to @a dst
986 */
987int
988GNUNET_DNSPARSER_builder_add_soa (char *dst,
989 size_t dst_len,
990 size_t *off,
991 const struct GNUNET_DNSPARSER_SoaRecord *soa)
992{
993 struct GNUNET_TUN_DnsSoaRecord sd;
994 int ret;
995
996 if ( (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst,
997 dst_len,
998 off,
999 soa->mname))) ||
1000 (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst,
1001 dst_len,
1002 off,
1003 soa->rname)) ) )
1004 return ret;
1005 if (*off + sizeof (struct GNUNET_TUN_DnsSoaRecord) > dst_len)
1006 return GNUNET_NO;
1007 sd.serial = htonl (soa->serial);
1008 sd.refresh = htonl (soa->refresh);
1009 sd.retry = htonl (soa->retry);
1010 sd.expire = htonl (soa->expire);
1011 sd.minimum = htonl (soa->minimum_ttl);
1012 GNUNET_memcpy (&dst[*off], &sd, sizeof (sd));
1013 (*off) += sizeof (sd);
1014 return GNUNET_OK;
1015}
1016
1017
1018/**
1019 * Add an SRV record to the UDP packet at the given location.
1020 *
1021 * @param dst where to write the SRV record
1022 * @param dst_len number of bytes in @a dst
1023 * @param off pointer to offset where to write the SRV information (increment by bytes used)
1024 * can also change if there was an error
1025 * @param srv SRV information to write
1026 * @return #GNUNET_SYSERR if @a srv is invalid
1027 * #GNUNET_NO if @a srv did not fit
1028 * #GNUNET_OK if @a srv was added to @a dst
1029 */
1030int
1031GNUNET_DNSPARSER_builder_add_srv (char *dst,
1032 size_t dst_len,
1033 size_t *off,
1034 const struct GNUNET_DNSPARSER_SrvRecord *srv)
1035{
1036 struct GNUNET_TUN_DnsSrvRecord sd;
1037 int ret;
1038
1039 if (*off + sizeof (struct GNUNET_TUN_DnsSrvRecord) > dst_len)
1040 return GNUNET_NO;
1041 sd.prio = htons (srv->priority);
1042 sd.weight = htons (srv->weight);
1043 sd.port = htons (srv->port);
1044 GNUNET_memcpy (&dst[*off], &sd, sizeof (sd));
1045 (*off) += sizeof (sd);
1046 if (GNUNET_OK != (ret = GNUNET_DNSPARSER_builder_add_name (dst,
1047 dst_len,
1048 off,
1049 srv->target)))
1050 return ret;
1051 return GNUNET_OK;
1052}
1053
1054
1055/**
1056 * Add a DNS record to the UDP packet at the given location.
1057 *
1058 * @param dst where to write the query
1059 * @param dst_len number of bytes in @a dst
1060 * @param off pointer to offset where to write the query (increment by bytes used)
1061 * must not be changed if there is an error
1062 * @param record record to write
1063 * @return #GNUNET_SYSERR if @a record is invalid
1064 * #GNUNET_NO if @a record did not fit
1065 * #GNUNET_OK if @a record was added to @a dst
1066 */
1067static int
1068add_record (char *dst,
1069 size_t dst_len,
1070 size_t *off,
1071 const struct GNUNET_DNSPARSER_Record *record)
1072{
1073 int ret;
1074 size_t start;
1075 size_t pos;
1076 struct GNUNET_TUN_DnsRecordLine rl;
1077
1078 start = *off;
1079 ret = GNUNET_DNSPARSER_builder_add_name (dst,
1080 dst_len - sizeof (struct GNUNET_TUN_DnsRecordLine),
1081 off,
1082 record->name);
1083 if (GNUNET_OK != ret)
1084 return ret;
1085 /* '*off' is now the position where we will need to write the record line */
1086
1087 pos = *off + sizeof (struct GNUNET_TUN_DnsRecordLine);
1088 switch (record->type)
1089 {
1090 case GNUNET_DNSPARSER_TYPE_MX:
1091 ret = GNUNET_DNSPARSER_builder_add_mx (dst,
1092 dst_len,
1093 &pos,
1094 record->data.mx);
1095 break;
1096 case GNUNET_DNSPARSER_TYPE_CERT:
1097 ret = GNUNET_DNSPARSER_builder_add_cert (dst,
1098 dst_len,
1099 &pos,
1100 record->data.cert);
1101 break;
1102 case GNUNET_DNSPARSER_TYPE_SOA:
1103 ret = GNUNET_DNSPARSER_builder_add_soa (dst,
1104 dst_len,
1105 &pos,
1106 record->data.soa);
1107 break;
1108 case GNUNET_DNSPARSER_TYPE_NS:
1109 case GNUNET_DNSPARSER_TYPE_CNAME:
1110 case GNUNET_DNSPARSER_TYPE_PTR:
1111 ret = GNUNET_DNSPARSER_builder_add_name (dst,
1112 dst_len,
1113 &pos,
1114 record->data.hostname);
1115 break;
1116 case GNUNET_DNSPARSER_TYPE_SRV:
1117 ret = GNUNET_DNSPARSER_builder_add_srv (dst,
1118 dst_len,
1119 &pos,
1120 record->data.srv);
1121 break;
1122 default:
1123 if (pos + record->data.raw.data_len > dst_len)
1124 {
1125 ret = GNUNET_NO;
1126 break;
1127 }
1128 GNUNET_memcpy (&dst[pos],
1129 record->data.raw.data,
1130 record->data.raw.data_len);
1131 pos += record->data.raw.data_len;
1132 ret = GNUNET_OK;
1133 break;
1134 }
1135 if (GNUNET_OK != ret)
1136 {
1137 *off = start;
1138 return GNUNET_NO;
1139 }
1140
1141 if (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine)) > UINT16_MAX)
1142 {
1143 /* record data too long */
1144 *off = start;
1145 return GNUNET_NO;
1146 }
1147 rl.type = htons (record->type);
1148 rl.dns_traffic_class = htons (record->dns_traffic_class);
1149 rl.ttl = htonl (GNUNET_TIME_absolute_get_remaining (record->expiration_time).rel_value_us / 1000LL / 1000LL); /* in seconds */
1150 rl.data_len = htons ((uint16_t) (pos - (*off + sizeof (struct GNUNET_TUN_DnsRecordLine))));
1151 GNUNET_memcpy (&dst[*off], &rl, sizeof (struct GNUNET_TUN_DnsRecordLine));
1152 *off = pos;
1153 return GNUNET_OK;
1154}
1155
1156
1157/**
1158 * Given a DNS packet @a p, generate the corresponding UDP payload.
1159 * Note that we do not attempt to pack the strings with pointers
1160 * as this would complicate the code and this is about being
1161 * simple and secure, not fast, fancy and broken like bind.
1162 *
1163 * @param p packet to pack
1164 * @param max maximum allowed size for the resulting UDP payload
1165 * @param buf set to a buffer with the packed message
1166 * @param buf_length set to the length of @a buf
1167 * @return #GNUNET_SYSERR if @a p is invalid
1168 * #GNUNET_NO if @a p was truncated (but there is still a result in @a buf)
1169 * #GNUNET_OK if @a p was packed completely into @a buf
1170 */
1171int
1172GNUNET_DNSPARSER_pack (const struct GNUNET_DNSPARSER_Packet *p,
1173 uint16_t max,
1174 char **buf,
1175 size_t *buf_length)
1176{
1177 struct GNUNET_TUN_DnsHeader dns;
1178 size_t off;
1179 char tmp[max];
1180 unsigned int i;
1181 int ret;
1182 int trc;
1183
1184 if ( (p->num_queries > UINT16_MAX) ||
1185 (p->num_answers > UINT16_MAX) ||
1186 (p->num_authority_records > UINT16_MAX) ||
1187 (p->num_additional_records > UINT16_MAX) )
1188 return GNUNET_SYSERR;
1189 dns.id = p->id;
1190 dns.flags = p->flags;
1191 dns.query_count = htons (p->num_queries);
1192 dns.answer_rcount = htons (p->num_answers);
1193 dns.authority_rcount = htons (p->num_authority_records);
1194 dns.additional_rcount = htons (p->num_additional_records);
1195
1196 off = sizeof (struct GNUNET_TUN_DnsHeader);
1197 trc = GNUNET_NO;
1198 for (i=0;i<p->num_queries;i++)
1199 {
1200 ret = GNUNET_DNSPARSER_builder_add_query (tmp,
1201 sizeof (tmp),
1202 &off,
1203 &p->queries[i]);
1204 if (GNUNET_SYSERR == ret)
1205 return GNUNET_SYSERR;
1206 if (GNUNET_NO == ret)
1207 {
1208 dns.query_count = htons ((uint16_t) (i-1));
1209 trc = GNUNET_YES;
1210 break;
1211 }
1212 }
1213 for (i=0;i<p->num_answers;i++)
1214 {
1215 ret = add_record (tmp,
1216 sizeof (tmp),
1217 &off,
1218 &p->answers[i]);
1219 if (GNUNET_SYSERR == ret)
1220 return GNUNET_SYSERR;
1221 if (GNUNET_NO == ret)
1222 {
1223 dns.answer_rcount = htons ((uint16_t) (i-1));
1224 trc = GNUNET_YES;
1225 break;
1226 }
1227 }
1228 for (i=0;i<p->num_authority_records;i++)
1229 {
1230 ret = add_record (tmp,
1231 sizeof (tmp),
1232 &off,
1233 &p->authority_records[i]);
1234 if (GNUNET_SYSERR == ret)
1235 return GNUNET_SYSERR;
1236 if (GNUNET_NO == ret)
1237 {
1238 dns.authority_rcount = htons ((uint16_t) (i-1));
1239 trc = GNUNET_YES;
1240 break;
1241 }
1242 }
1243 for (i=0;i<p->num_additional_records;i++)
1244 {
1245 ret = add_record (tmp,
1246 sizeof (tmp),
1247 &off,
1248 &p->additional_records[i]);
1249 if (GNUNET_SYSERR == ret)
1250 return GNUNET_SYSERR;
1251 if (GNUNET_NO == ret)
1252 {
1253 dns.additional_rcount = htons (i-1);
1254 trc = GNUNET_YES;
1255 break;
1256 }
1257 }
1258
1259 if (GNUNET_YES == trc)
1260 dns.flags.message_truncated = 1;
1261 GNUNET_memcpy (tmp,
1262 &dns,
1263 sizeof (struct GNUNET_TUN_DnsHeader));
1264
1265 *buf = GNUNET_malloc (off);
1266 *buf_length = off;
1267 GNUNET_memcpy (*buf,
1268 tmp,
1269 off);
1270 if (GNUNET_YES == trc)
1271 return GNUNET_NO;
1272 return GNUNET_OK;
1273}
1274
1275
1276/**
1277 * Convert a block of binary data to HEX.
1278 *
1279 * @param data binary data to convert
1280 * @param data_size number of bytes in @a data
1281 * @return HEX string (lower case)
1282 */
1283char *
1284GNUNET_DNSPARSER_bin_to_hex (const void *data,
1285 size_t data_size)
1286{
1287 char *ret;
1288 size_t off;
1289 const uint8_t *idata;
1290
1291 idata = data;
1292 ret = GNUNET_malloc (data_size * 2 + 1);
1293 for (off = 0; off < data_size; off++)
1294 sprintf (&ret[off * 2],
1295 "%02x",
1296 idata[off]);
1297 return ret;
1298}
1299
1300
1301/**
1302 * Convert a HEX string to block of binary data.
1303 *
1304 * @param hex HEX string to convert (may contain mixed case)
1305 * @param data where to write result, must be
1306 * at least `strlen(hex)/2` bytes long
1307 * @return number of bytes written to data
1308 */
1309size_t
1310GNUNET_DNSPARSER_hex_to_bin (const char *hex,
1311 void *data)
1312{
1313 size_t data_size;
1314 size_t off;
1315 uint8_t *idata;
1316 unsigned int h;
1317 char in[3];
1318
1319 data_size = strlen (hex) / 2;
1320 idata = data;
1321 in[2] = '\0';
1322 for (off = 0; off < data_size; off++)
1323 {
1324 in[0] = tolower ((unsigned char) hex[off * 2]);
1325 in[1] = tolower ((unsigned char) hex[off * 2 + 1]);
1326 if (1 != sscanf (in, "%x", &h))
1327 return off;
1328 idata[off] = (uint8_t) h;
1329 }
1330 return off;
1331}
1332
1333
1334/* end of dnsparser.c */
diff --git a/src/dns/dnsstub.c b/src/dns/dnsstub.c
deleted file mode 100644
index 969ff7beb..000000000
--- a/src/dns/dnsstub.c
+++ /dev/null
@@ -1,749 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2018 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/**
19 * @file dns/dnsstub.c
20 * @brief DNS stub resolver which sends DNS requests to an actual resolver
21 * @author Christian Grothoff
22 */
23#include "platform.h"
24#include "gnunet_util_lib.h"
25#include "gnunet_tun_lib.h"
26#include "gnunet_dnsstub_lib.h"
27
28/**
29 * Timeout for retrying DNS queries.
30 */
31#define DNS_RETRANSMIT_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250)
32
33
34/**
35 * DNS Server used for resolution.
36 */
37struct DnsServer;
38
39
40/**
41 * UDP socket we are using for sending DNS requests to the Internet.
42 */
43struct GNUNET_DNSSTUB_RequestSocket
44{
45
46 /**
47 * UDP socket we use for this request for IPv4
48 */
49 struct GNUNET_NETWORK_Handle *dnsout4;
50
51 /**
52 * UDP socket we use for this request for IPv6
53 */
54 struct GNUNET_NETWORK_Handle *dnsout6;
55
56 /**
57 * Function to call with result.
58 */
59 GNUNET_DNSSTUB_ResultCallback rc;
60
61 /**
62 * Closure for @e rc.
63 */
64 void *rc_cls;
65
66 /**
67 * Task for reading from dnsout4 and dnsout6.
68 */
69 struct GNUNET_SCHEDULER_Task *read_task;
70
71 /**
72 * Task for retrying transmission of the query.
73 */
74 struct GNUNET_SCHEDULER_Task *retry_task;
75
76 /**
77 * Next address we sent the DNS request to.
78 */
79 struct DnsServer *ds_pos;
80
81 /**
82 * Context this request executes in.
83 */
84 struct GNUNET_DNSSTUB_Context *ctx;
85
86 /**
87 * Query we sent to @e addr.
88 */
89 void *request;
90
91 /**
92 * Number of bytes in @a request.
93 */
94 size_t request_len;
95
96};
97
98
99/**
100 * DNS Server used for resolution.
101 */
102struct DnsServer
103{
104
105 /**
106 * Kept in a DLL.
107 */
108 struct DnsServer *next;
109
110 /**
111 * Kept in a DLL.
112 */
113 struct DnsServer *prev;
114
115 /**
116 * IP address of the DNS resolver.
117 */
118 struct sockaddr_storage ss;
119};
120
121
122/**
123 * Handle to the stub resolver.
124 */
125struct GNUNET_DNSSTUB_Context
126{
127
128 /**
129 * Array of all open sockets for DNS requests.
130 */
131 struct GNUNET_DNSSTUB_RequestSocket *sockets;
132
133 /**
134 * DLL of DNS resolvers we use.
135 */
136 struct DnsServer *dns_head;
137
138 /**
139 * DLL of DNS resolvers we use.
140 */
141 struct DnsServer *dns_tail;
142
143 /**
144 * How frequently do we retry requests?
145 */
146 struct GNUNET_TIME_Relative retry_freq;
147
148 /**
149 * Length of @e sockets array.
150 */
151 unsigned int num_sockets;
152
153};
154
155
156/**
157 * We're done with a `struct GNUNET_DNSSTUB_RequestSocket`, close it for now.
158 *
159 * @param rs request socket to clean up
160 */
161static void
162cleanup_rs (struct GNUNET_DNSSTUB_RequestSocket *rs)
163{
164 if (NULL != rs->dnsout4)
165 {
166 GNUNET_NETWORK_socket_close (rs->dnsout4);
167 rs->dnsout4 = NULL;
168 }
169 if (NULL != rs->dnsout6)
170 {
171 GNUNET_NETWORK_socket_close (rs->dnsout6);
172 rs->dnsout6 = NULL;
173 }
174 if (NULL != rs->read_task)
175 {
176 GNUNET_SCHEDULER_cancel (rs->read_task);
177 rs->read_task = NULL;
178 }
179 if (NULL != rs->retry_task)
180 {
181 GNUNET_SCHEDULER_cancel (rs->retry_task);
182 rs->retry_task = NULL;
183 }
184 if (NULL != rs->request)
185 {
186 GNUNET_free (rs->request);
187 rs->request = NULL;
188 }
189}
190
191
192/**
193 * Open source port for sending DNS requests
194 *
195 * @param af AF_INET or AF_INET6
196 * @return #GNUNET_OK on success
197 */
198static struct GNUNET_NETWORK_Handle *
199open_socket (int af)
200{
201 struct sockaddr_in a4;
202 struct sockaddr_in6 a6;
203 struct sockaddr *sa;
204 socklen_t alen;
205 struct GNUNET_NETWORK_Handle *ret;
206
207 ret = GNUNET_NETWORK_socket_create (af, SOCK_DGRAM, 0);
208 if (NULL == ret)
209 return NULL;
210 switch (af)
211 {
212 case AF_INET:
213 memset (&a4, 0, alen = sizeof (struct sockaddr_in));
214 sa = (struct sockaddr *) &a4;
215 break;
216 case AF_INET6:
217 memset (&a6, 0, alen = sizeof (struct sockaddr_in6));
218 sa = (struct sockaddr *) &a6;
219 break;
220 default:
221 GNUNET_break (0);
222 GNUNET_NETWORK_socket_close (ret);
223 return NULL;
224 }
225 sa->sa_family = af;
226 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (ret,
227 sa,
228 alen))
229 {
230 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
231 _("Could not bind to any port: %s\n"),
232 STRERROR (errno));
233 GNUNET_NETWORK_socket_close (ret);
234 return NULL;
235 }
236 return ret;
237}
238
239
240/**
241 * Get a socket of the specified address family to send out a
242 * UDP DNS request to the Internet.
243 *
244 * @param ctx the DNSSTUB context
245 * @return NULL on error
246 */
247static struct GNUNET_DNSSTUB_RequestSocket *
248get_request_socket (struct GNUNET_DNSSTUB_Context *ctx)
249{
250 struct GNUNET_DNSSTUB_RequestSocket *rs;
251
252 for (unsigned int i=0;i<256;i++)
253 {
254 rs = &ctx->sockets[GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
255 ctx->num_sockets)];
256 if (NULL == rs->rc)
257 break;
258 }
259 if (NULL != rs->rc)
260 {
261 /* signal "failure" */
262 rs->rc (rs->rc_cls,
263 NULL,
264 0);
265 rs->rc = NULL;
266 }
267 if (NULL != rs->read_task)
268 {
269 GNUNET_SCHEDULER_cancel (rs->read_task);
270 rs->read_task = NULL;
271 }
272 if (NULL != rs->retry_task)
273 {
274 GNUNET_SCHEDULER_cancel (rs->retry_task);
275 rs->retry_task = NULL;
276 }
277 if (NULL != rs->request)
278 {
279 GNUNET_free (rs->request);
280 rs->request = NULL;
281 }
282 rs->ctx = ctx;
283 return rs;
284}
285
286
287/**
288 * Actually do the reading of a DNS packet from our UDP socket and see
289 * if we have a valid, matching, pending request.
290 *
291 * @param rs request socket with callback details
292 * @param dnsout socket to read from
293 * @return #GNUNET_OK on success, #GNUNET_NO on drop, #GNUNET_SYSERR on IO-errors (closed socket)
294 */
295static int
296do_dns_read (struct GNUNET_DNSSTUB_RequestSocket *rs,
297 struct GNUNET_NETWORK_Handle *dnsout)
298{
299 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
300 ssize_t r;
301 int len;
302
303#ifndef MINGW
304 if (0 != ioctl (GNUNET_NETWORK_get_fd (dnsout),
305 FIONREAD,
306 &len))
307 {
308 /* conservative choice: */
309 len = UINT16_MAX;
310 }
311#else
312 /* port the code above? */
313 len = UINT16_MAX;
314#endif
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Receiving %d byte DNS reply\n",
317 len);
318 {
319 unsigned char buf[len] GNUNET_ALIGN;
320 int found;
321 struct sockaddr_storage addr;
322 socklen_t addrlen;
323 struct GNUNET_TUN_DnsHeader *dns;
324
325 addrlen = sizeof (addr);
326 memset (&addr,
327 0,
328 sizeof (addr));
329 r = GNUNET_NETWORK_socket_recvfrom (dnsout,
330 buf,
331 sizeof (buf),
332 (struct sockaddr*) &addr,
333 &addrlen);
334 if (-1 == r)
335 {
336 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
337 "recvfrom");
338 GNUNET_NETWORK_socket_close (dnsout);
339 return GNUNET_SYSERR;
340 }
341 found = GNUNET_NO;
342 for (struct DnsServer *ds = ctx->dns_head; NULL != ds; ds = ds->next)
343 {
344 if (0 == memcmp (&addr,
345 &ds->ss,
346 GNUNET_MIN (sizeof (struct sockaddr_storage),
347 addrlen)))
348 {
349 found = GNUNET_YES;
350 break;
351 }
352 }
353 if (GNUNET_NO == found)
354 {
355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
356 "Received DNS response from server we never asked (ignored)");
357 return GNUNET_NO;
358 }
359 if (sizeof (struct GNUNET_TUN_DnsHeader) > r)
360 {
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 _("Received DNS response that is too small (%u bytes)"),
363 (unsigned int) r);
364 return GNUNET_NO;
365 }
366 dns = (struct GNUNET_TUN_DnsHeader *) buf;
367 if (NULL == rs->rc)
368 {
369 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
370 "Request timeout or cancelled; ignoring reply\n");
371 return GNUNET_NO;
372 }
373 rs->rc (rs->rc_cls,
374 dns,
375 r);
376 }
377 return GNUNET_OK;
378}
379
380
381/**
382 * Read a DNS response from the (unhindered) UDP-Socket
383 *
384 * @param cls socket to read from
385 */
386static void
387read_response (void *cls);
388
389
390/**
391 * Schedule #read_response() task for @a rs.
392 *
393 * @param rs request to schedule read operation for
394 */
395static void
396schedule_read (struct GNUNET_DNSSTUB_RequestSocket *rs)
397{
398 struct GNUNET_NETWORK_FDSet *rset;
399
400 if (NULL != rs->read_task)
401 GNUNET_SCHEDULER_cancel (rs->read_task);
402 rset = GNUNET_NETWORK_fdset_create ();
403 if (NULL != rs->dnsout4)
404 GNUNET_NETWORK_fdset_set (rset,
405 rs->dnsout4);
406 if (NULL != rs->dnsout6)
407 GNUNET_NETWORK_fdset_set (rset,
408 rs->dnsout6);
409 rs->read_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
410 GNUNET_TIME_UNIT_FOREVER_REL,
411 rset,
412 NULL,
413 &read_response,
414 rs);
415 GNUNET_NETWORK_fdset_destroy (rset);
416}
417
418
419/**
420 * Read a DNS response from the (unhindered) UDP-Socket
421 *
422 * @param cls `struct GNUNET_DNSSTUB_RequestSocket` to read from
423 */
424static void
425read_response (void *cls)
426{
427 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
428 const struct GNUNET_SCHEDULER_TaskContext *tc;
429
430 rs->read_task = NULL;
431 tc = GNUNET_SCHEDULER_get_task_context ();
432 /* read and process ready sockets */
433 if ( (NULL != rs->dnsout4) &&
434 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
435 rs->dnsout4)) &&
436 (GNUNET_SYSERR ==
437 do_dns_read (rs,
438 rs->dnsout4)) )
439 rs->dnsout4 = NULL;
440 if ( (NULL != rs->dnsout6) &&
441 (GNUNET_NETWORK_fdset_isset (tc->read_ready,
442 rs->dnsout6)) &&
443 (GNUNET_SYSERR ==
444 do_dns_read (rs,
445 rs->dnsout6)) )
446 rs->dnsout6 = NULL;
447 /* re-schedule read task */
448 schedule_read (rs);
449}
450
451
452/**
453 * Task to (re)transmit the DNS query, possibly repeatedly until
454 * we succeed.
455 *
456 * @param cls our `struct GNUNET_DNSSTUB_RequestSocket *`
457 */
458static void
459transmit_query (void *cls)
460{
461 struct GNUNET_DNSSTUB_RequestSocket *rs = cls;
462 struct GNUNET_DNSSTUB_Context *ctx = rs->ctx;
463 const struct sockaddr *sa;
464 socklen_t salen;
465 struct DnsServer *ds;
466 struct GNUNET_NETWORK_Handle *dnsout;
467
468 rs->retry_task = GNUNET_SCHEDULER_add_delayed (ctx->retry_freq,
469 &transmit_query,
470 rs);
471 ds = rs->ds_pos;
472 rs->ds_pos = ds->next;
473 if (NULL == rs->ds_pos)
474 rs->ds_pos = ctx->dns_head;
475 GNUNET_assert (NULL != ds);
476 dnsout = NULL;
477 switch (ds->ss.ss_family)
478 {
479 case AF_INET:
480 if (NULL == rs->dnsout4)
481 rs->dnsout4 = open_socket (AF_INET);
482 dnsout = rs->dnsout4;
483 sa = (const struct sockaddr *) &ds->ss;
484 salen = sizeof (struct sockaddr_in);
485 break;
486 case AF_INET6:
487 if (NULL == rs->dnsout6)
488 rs->dnsout6 = open_socket (AF_INET6);
489 dnsout = rs->dnsout6;
490 sa = (const struct sockaddr *) &ds->ss;
491 salen = sizeof (struct sockaddr_in6);
492 break;
493 default:
494 return;
495 }
496 if (NULL == dnsout)
497 {
498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
499 "Unable to use configure DNS server, skipping\n");
500 return;
501 }
502 if (GNUNET_SYSERR ==
503 GNUNET_NETWORK_socket_sendto (dnsout,
504 rs->request,
505 rs->request_len,
506 sa,
507 salen))
508 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
509 _("Failed to send DNS request to %s: %s\n"),
510 GNUNET_a2s (sa,
511 salen),
512 STRERROR (errno));
513 else
514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 _("Sent DNS request to %s\n"),
516 GNUNET_a2s (sa,
517 salen));
518 schedule_read (rs);
519}
520
521
522/**
523 * Perform DNS resolution using our default IP from init.
524 *
525 * @param ctx stub resolver to use
526 * @param request DNS request to transmit
527 * @param request_len number of bytes in msg
528 * @param rc function to call with result
529 * @param rc_cls closure for 'rc'
530 * @return socket used for the request, NULL on error
531 */
532struct GNUNET_DNSSTUB_RequestSocket *
533GNUNET_DNSSTUB_resolve (struct GNUNET_DNSSTUB_Context *ctx,
534 const void *request,
535 size_t request_len,
536 GNUNET_DNSSTUB_ResultCallback rc,
537 void *rc_cls)
538{
539 struct GNUNET_DNSSTUB_RequestSocket *rs;
540
541 if (NULL == ctx->dns_head)
542 {
543 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
544 "No DNS server configured for resolution\n");
545 return NULL;
546 }
547 if (NULL == (rs = get_request_socket (ctx)))
548 {
549 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
550 "No request socket available for DNS resolution\n");
551 return NULL;
552 }
553 rs->ds_pos = ctx->dns_head;
554 rs->rc = rc;
555 rs->rc_cls = rc_cls;
556 rs->request = GNUNET_memdup (request,
557 request_len);
558 rs->request_len = request_len;
559 rs->retry_task = GNUNET_SCHEDULER_add_now (&transmit_query,
560 rs);
561 return rs;
562}
563
564
565/**
566 * Cancel DNS resolution.
567 *
568 * @param rs resolution to cancel
569 */
570void
571GNUNET_DNSSTUB_resolve_cancel (struct GNUNET_DNSSTUB_RequestSocket *rs)
572{
573 rs->rc = NULL;
574 if (NULL != rs->retry_task)
575 {
576 GNUNET_SCHEDULER_cancel (rs->retry_task);
577 rs->retry_task = NULL;
578 }
579 if (NULL != rs->read_task)
580 {
581 GNUNET_SCHEDULER_cancel (rs->read_task);
582 rs->read_task = NULL;
583 }
584}
585
586
587/**
588 * Start a DNS stub resolver.
589 *
590 * @param num_sockets how many sockets should we open
591 * in parallel for DNS queries for this stub?
592 * @return NULL on error
593 */
594struct GNUNET_DNSSTUB_Context *
595GNUNET_DNSSTUB_start (unsigned int num_sockets)
596{
597 struct GNUNET_DNSSTUB_Context *ctx;
598
599 if (0 == num_sockets)
600 {
601 GNUNET_break (0);
602 return NULL;
603 }
604 ctx = GNUNET_new (struct GNUNET_DNSSTUB_Context);
605 ctx->num_sockets = num_sockets;
606 ctx->sockets = GNUNET_new_array (num_sockets,
607 struct GNUNET_DNSSTUB_RequestSocket);
608 ctx->retry_freq = DNS_RETRANSMIT_DELAY;
609 return ctx;
610}
611
612
613/**
614 * Add nameserver for use by the DNSSTUB. We will use
615 * all provided nameservers for resolution (round-robin).
616 *
617 * @param ctx resolver context to modify
618 * @param dns_ip target IP address to use (as string)
619 * @return #GNUNET_OK on success
620 */
621int
622GNUNET_DNSSTUB_add_dns_ip (struct GNUNET_DNSSTUB_Context *ctx,
623 const char *dns_ip)
624{
625 struct DnsServer *ds;
626 struct in_addr i4;
627 struct in6_addr i6;
628
629 ds = GNUNET_new (struct DnsServer);
630 if (1 == inet_pton (AF_INET,
631 dns_ip,
632 &i4))
633 {
634 struct sockaddr_in *s4 = (struct sockaddr_in *) &ds->ss;
635
636 s4->sin_family = AF_INET;
637 s4->sin_port = htons (53);
638 s4->sin_addr = i4;
639#if HAVE_SOCKADDR_IN_SIN_LEN
640 s4->sin_len = (u_char) sizeof (struct sockaddr_in);
641#endif
642 }
643 else if (1 == inet_pton (AF_INET6,
644 dns_ip,
645 &i6))
646 {
647 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) &ds->ss;
648
649 s6->sin6_family = AF_INET6;
650 s6->sin6_port = htons (53);
651 s6->sin6_addr = i6;
652#if HAVE_SOCKADDR_IN_SIN_LEN
653 s6->sin6_len = (u_char) sizeof (struct sockaddr_in6);
654#endif
655 }
656 else
657 {
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Malformed IP address `%s' for DNS server\n",
660 dns_ip);
661 GNUNET_free (ds);
662 return GNUNET_SYSERR;
663 }
664 GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
665 ctx->dns_tail,
666 ds);
667 return GNUNET_OK;
668}
669
670
671/**
672 * Add nameserver for use by the DNSSTUB. We will use
673 * all provided nameservers for resolution (round-robin).
674 *
675 * @param ctx resolver context to modify
676 * @param sa socket address of DNS resolver to use
677 * @return #GNUNET_OK on success
678 */
679int
680GNUNET_DNSSTUB_add_dns_sa (struct GNUNET_DNSSTUB_Context *ctx,
681 const struct sockaddr *sa)
682{
683 struct DnsServer *ds;
684
685 ds = GNUNET_new (struct DnsServer);
686 switch (sa->sa_family)
687 {
688 case AF_INET:
689 GNUNET_memcpy (&ds->ss,
690 sa,
691 sizeof (struct sockaddr_in));
692 break;
693 case AF_INET6:
694 GNUNET_memcpy (&ds->ss,
695 sa,
696 sizeof (struct sockaddr_in6));
697 break;
698 default:
699 GNUNET_break (0);
700 GNUNET_free (ds);
701 return GNUNET_SYSERR;
702 }
703 GNUNET_CONTAINER_DLL_insert (ctx->dns_head,
704 ctx->dns_tail,
705 ds);
706 return GNUNET_OK;
707}
708
709
710/**
711 * How long should we try requests before timing out?
712 * Only effective for requests issued after this call.
713 *
714 * @param ctx resolver context to modify
715 * @param retry_freq how long to wait between retries
716 */
717void
718GNUNET_DNSSTUB_set_retry (struct GNUNET_DNSSTUB_Context *ctx,
719 struct GNUNET_TIME_Relative retry_freq)
720{
721 ctx->retry_freq = retry_freq;
722}
723
724
725/**
726 * Cleanup DNSSTUB resolver.
727 *
728 * @param ctx stub resolver to clean up
729 */
730void
731GNUNET_DNSSTUB_stop (struct GNUNET_DNSSTUB_Context *ctx)
732{
733 struct DnsServer *ds;
734
735 while (NULL != (ds = ctx->dns_head))
736 {
737 GNUNET_CONTAINER_DLL_remove (ctx->dns_head,
738 ctx->dns_tail,
739 ds);
740 GNUNET_free (ds);
741 }
742 for (unsigned int i=0;i<ctx->num_sockets;i++)
743 cleanup_rs (&ctx->sockets[i]);
744 GNUNET_free (ctx->sockets);
745 GNUNET_free (ctx);
746}
747
748
749/* end of dnsstub.c */
diff --git a/src/dns/test_hexcoder.c b/src/dns/test_hexcoder.c
deleted file mode 100644
index 441d7e200..000000000
--- a/src/dns/test_hexcoder.c
+++ /dev/null
@@ -1,54 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014 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*/
19/**
20 * @author Christian Grothoff
21 * @file dns/test_hexcoder.c
22 * @brief test for #GNUNET_DNSPARSER_hex_to_bin() and
23 * #GNUNET_DNSPARSER_bin_to_hex()
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_dnsparser_lib.h"
28
29#define TESTSTRING "Hello World!"
30
31
32int
33main (int argc,
34 char *argv[])
35{
36 char buf[strlen (TESTSTRING) + 1];
37 char *ret;
38
39 GNUNET_log_setup ("test-hexcoder", "WARNING", NULL);
40 ret = GNUNET_DNSPARSER_bin_to_hex (TESTSTRING,
41 strlen (TESTSTRING) + 1);
42 GNUNET_assert (NULL != ret);
43 GNUNET_assert (sizeof (buf) ==
44 GNUNET_DNSPARSER_hex_to_bin (ret,
45 buf));
46 GNUNET_assert (0 == memcmp (TESTSTRING,
47 buf,
48 sizeof (buf)));
49 GNUNET_free (ret);
50 return 0;
51}
52
53
54/* end of test_hexcoder.c */