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