aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorlurchi <lurchi@strangeplace.net>2018-06-25 18:38:13 +0200
committerlurchi <lurchi@strangeplace.net>2018-06-25 18:38:27 +0200
commita4186fc2fd00b3fe2899bffcdbbbf8fead31115f (patch)
treed70c5939cc99d43e29ce63a4faa9ef334de0c81d /src/util
parent7da98cf076e9c5101244dfbbf8c3ddff045d298e (diff)
downloadgnunet-a4186fc2fd00b3fe2899bffcdbbbf8fead31115f.tar.gz
gnunet-a4186fc2fd00b3fe2899bffcdbbbf8fead31115f.zip
Revert "integrate dnsparser and dnsstub and tun with libgnunetutil"
This reverts commit 7da98cf076e9c5101244dfbbf8c3ddff045d298e.
Diffstat (limited to 'src/util')
-rw-r--r--src/util/Makefile.am25
-rw-r--r--src/util/dnsparser.c1334
-rw-r--r--src/util/dnsstub.c749
-rw-r--r--src/util/regex.c834
-rw-r--r--src/util/test_hexcoder.c54
-rw-r--r--src/util/test_regex.c179
-rw-r--r--src/util/test_tun.c72
-rw-r--r--src/util/tun.c309
8 files changed, 2 insertions, 3554 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index ec7bcb016..4296199db 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -89,8 +89,6 @@ libgnunetutil_la_SOURCES = \
89 crypto_rsa.c \ 89 crypto_rsa.c \
90 disk.c \ 90 disk.c \
91 disk.h \ 91 disk.h \
92 dnsparser.c \
93 dnsstub.c \
94 getopt.c \ 92 getopt.c \
95 getopt_helpers.c \ 93 getopt_helpers.c \
96 helper.c \ 94 helper.c \
@@ -106,14 +104,12 @@ libgnunetutil_la_SOURCES = \
106 peer.c \ 104 peer.c \
107 plugin.c \ 105 plugin.c \
108 program.c \ 106 program.c \
109 regex.c \
110 resolver_api.c resolver.h \ 107 resolver_api.c resolver.h \
111 scheduler.c \ 108 scheduler.c \
112 service.c \ 109 service.c \
113 signal.c \ 110 signal.c \
114 strings.c \ 111 strings.c \
115 time.c \ 112 time.c \
116 tun.c \
117 speedup.c speedup.h 113 speedup.c speedup.h
118 114
119libgnunetutil_la_LIBADD = \ 115libgnunetutil_la_LIBADD = \
@@ -121,7 +117,7 @@ libgnunetutil_la_LIBADD = \
121 $(LIBGCRYPT_LIBS) \ 117 $(LIBGCRYPT_LIBS) \
122 $(LTLIBICONV) \ 118 $(LTLIBICONV) \
123 $(LTLIBINTL) \ 119 $(LTLIBINTL) \
124 -lltdl -lidn $(Z_LIBS) -lunistring $(XLIB) 120 -lltdl $(Z_LIBS) -lunistring $(XLIB)
125 121
126libgnunetutil_la_LDFLAGS = \ 122libgnunetutil_la_LDFLAGS = \
127 $(GN_LIB_LDFLAGS) \ 123 $(GN_LIB_LDFLAGS) \
@@ -295,22 +291,19 @@ check_PROGRAMS = \
295 test_crypto_rsa \ 291 test_crypto_rsa \
296 test_disk \ 292 test_disk \
297 test_getopt \ 293 test_getopt \
298 test_hexcoder \
299 test_mq \ 294 test_mq \
300 test_os_network \ 295 test_os_network \
301 test_peer \ 296 test_peer \
302 test_plugin \ 297 test_plugin \
303 test_program \ 298 test_program \
304 test_regex \
305 test_resolver_api.nc \ 299 test_resolver_api.nc \
306 test_scheduler \ 300 test_scheduler \
307 test_scheduler_delay \ 301 test_scheduler_delay \
308 test_service \ 302 test_service \
309 test_strings \ 303 test_strings \
310 test_strings_to_data \ 304 test_strings_to_data \
311 test_speedup \
312 test_time \ 305 test_time \
313 test_tun \ 306 test_speedup \
314 $(BENCHMARKS) \ 307 $(BENCHMARKS) \
315 test_os_start_process \ 308 test_os_start_process \
316 test_common_logging_runtime_loglevels 309 test_common_logging_runtime_loglevels
@@ -326,20 +319,6 @@ test_bio_SOURCES = \
326test_bio_LDADD = \ 319test_bio_LDADD = \
327 libgnunetutil.la 320 libgnunetutil.la
328 321
329test_hexcoder_SOURCES = \
330 test_hexcoder.c
331test_hexcoder_LDADD = \
332 libgnunetutil.la
333
334test_tun_SOURCES = \
335 test_tun.c
336test_tun_LDADD = \
337 libgnunetutil.la
338
339test_regex_SOURCES = \
340 test_regex.c
341test_regex_LDADD = \
342 libgnunetutil.la
343 322
344test_os_start_process_SOURCES = \ 323test_os_start_process_SOURCES = \
345 test_os_start_process.c 324 test_os_start_process.c
diff --git a/src/util/dnsparser.c b/src/util/dnsparser.c
deleted file mode 100644
index 32ad7c0c2..000000000
--- a/src/util/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/util/dnsstub.c b/src/util/dnsstub.c
deleted file mode 100644
index 969ff7beb..000000000
--- a/src/util/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/util/regex.c b/src/util/regex.c
deleted file mode 100644
index 7565a9eac..000000000
--- a/src/util/regex.c
+++ /dev/null
@@ -1,834 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013, 2015 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 src/tun/regex.c
20 * @brief functions to convert IP networks to regexes
21 * @author Maximilian Szengel
22 * @author Christian Grothoff
23 */
24#include "platform.h"
25#include "gnunet_util_lib.h"
26#include "gnunet_tun_lib.h"
27
28/**
29 * 'wildcard', matches all possible values (for HEX encoding).
30 */
31#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
32
33
34/**
35 * Create a regex in @a rxstr from the given @a ip and @a netmask.
36 *
37 * @param ip IPv4 representation.
38 * @param port destination port
39 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV4_REGEXLEN
40 * bytes long.
41 */
42void
43GNUNET_TUN_ipv4toregexsearch (const struct in_addr *ip,
44 uint16_t port,
45 char *rxstr)
46{
47 GNUNET_snprintf (rxstr,
48 GNUNET_TUN_IPV4_REGEXLEN,
49 "4-%04X-%08X",
50 (unsigned int) port,
51 ntohl (ip->s_addr));
52}
53
54
55/**
56 * Create a regex in @a rxstr from the given @a ipv6 and @a prefixlen.
57 *
58 * @param ipv6 IPv6 representation.
59 * @param port destination port
60 * @param rxstr generated regex, must be at least #GNUNET_TUN_IPV6_REGEXLEN
61 * bytes long.
62 */
63void
64GNUNET_TUN_ipv6toregexsearch (const struct in6_addr *ipv6,
65 uint16_t port,
66 char *rxstr)
67{
68 const uint32_t *addr;
69
70 addr = (const uint32_t *) ipv6;
71 GNUNET_snprintf (rxstr,
72 GNUNET_TUN_IPV6_REGEXLEN,
73 "6-%04X-%08X%08X%08X%08X",
74 (unsigned int) port,
75 ntohl (addr[0]),
76 ntohl (addr[1]),
77 ntohl (addr[2]),
78 ntohl (addr[3]));
79}
80
81
82/**
83 * Convert the given 4-bit (!) number to a regex.
84 *
85 * @param value the value, only the lowest 4 bits will be looked at
86 * @param mask which bits in value are wildcards (any value)?
87 */
88static char *
89nibble_to_regex (uint8_t value,
90 uint8_t mask)
91{
92 char *ret;
93
94 value &= mask;
95 switch (mask)
96 {
97 case 0:
98 return GNUNET_strdup (DOT);
99 case 8:
100 GNUNET_asprintf (&ret,
101 "(%X|%X|%X|%X|%X|%X|%X|%X)",
102 value,
103 value + 1,
104 value + 2,
105 value + 3,
106 value + 4,
107 value + 5,
108 value + 6,
109 value + 7);
110 return ret;
111 case 12:
112 GNUNET_asprintf (&ret,
113 "(%X|%X|%X|%X)",
114 value,
115 value + 1,
116 value + 2,
117 value + 3);
118 return ret;
119 case 14:
120 GNUNET_asprintf (&ret,
121 "(%X|%X)",
122 value,
123 value + 1);
124 return ret;
125 case 15:
126 GNUNET_asprintf (&ret,
127 "%X",
128 value);
129 return ret;
130 default:
131 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
132 _("Bad mask: %d\n"),
133 mask);
134 GNUNET_break (0);
135 return NULL;
136 }
137}
138
139
140/**
141 * Convert the given 16-bit number to a regex.
142 *
143 * @param value the value
144 * @param mask which bits in value are wildcards (any value)?
145 */
146static char *
147num_to_regex (uint16_t value,
148 uint16_t mask)
149{
150 const uint8_t *v = (const uint8_t *) &value;
151 const uint8_t *m = (const uint8_t *) &mask;
152 char *a;
153 char *b;
154 char *c;
155 char *d;
156 char *ret;
157
158 a = nibble_to_regex (v[0] >> 4, m[0] >> 4);
159 b = nibble_to_regex (v[0] & 15, m[0] & 15);
160 c = nibble_to_regex (v[1] >> 4, m[1] >> 4);
161 d = nibble_to_regex (v[1] & 15, m[1] & 15);
162 ret = NULL;
163 if ( (NULL != a) &&
164 (NULL != b) &&
165 (NULL != c) &&
166 (NULL != d) )
167 GNUNET_asprintf (&ret,
168 "%s%s%s%s",
169 a, b, c, d);
170 GNUNET_free_non_null (a);
171 GNUNET_free_non_null (b);
172 GNUNET_free_non_null (c);
173 GNUNET_free_non_null (d);
174 return ret;
175}
176
177
178/**
179 * Do we need to put parents around the given argument?
180 *
181 * @param arg part of a regular expression
182 * @return #GNUNET_YES if we should parens,
183 * #GNUNET_NO if not
184 */
185static int
186needs_parens (const char *arg)
187{
188 size_t off;
189 size_t len;
190 unsigned int op;
191
192 op = 0;
193 len = strlen (arg);
194 for (off=0;off<len;off++)
195 {
196 switch (arg[off])
197 {
198 case '(':
199 op++;
200 break;
201 case ')':
202 GNUNET_assert (op > 0);
203 op--;
204 break;
205 case '|':
206 if (0 == op)
207 return GNUNET_YES;
208 break;
209 default:
210 break;
211 }
212 }
213 return GNUNET_NO;
214}
215
216
217/**
218 * Compute port policy for the given range of
219 * port numbers.
220 *
221 * @param start starting offset
222 * @param end end offset
223 * @param step increment level (power of 16)
224 * @param pp port policy to convert
225 * @return corresponding regex
226 */
227static char *
228compute_policy (unsigned int start,
229 unsigned int end,
230 unsigned int step,
231 const struct GNUNET_STRINGS_PortPolicy *pp)
232{
233 unsigned int i;
234 char before[36]; /* 16 * 2 + 3 dots + 0-terminator */
235 char middlel[33]; /* 16 * 2 + 0-terminator */
236 char middleh[33]; /* 16 * 2 + 0-terminator */
237 char after[36]; /* 16 * 2 + 3 dots + 0-terminator */
238 char beforep[36+2]; /* 16 * 2 + 3 dots + 0-terminator + ()*/
239 char middlehp[33+2]; /* 16 * 2 + 0-terminator + () */
240 char middlelp[33+2]; /* 16 * 2 + 0-terminator + () */
241 char afterp[36+2]; /* 16 * 2 + 3 dots + 0-terminator + () */
242 char dots[5 * strlen (DOT)];
243 char buf[3];
244 char *middle;
245 char *ret;
246 unsigned int xstep;
247 char *recl;
248 char *rech;
249 char *reclp;
250 char *rechp;
251 unsigned int start_port;
252 unsigned int end_port;
253
254 GNUNET_assert (GNUNET_YES == pp->negate_portrange);
255 start_port = pp->start_port;
256 if (1 == start_port)
257 start_port = 0;
258 end_port = pp->end_port;
259 GNUNET_assert ((end - start) / step <= 0xF);
260 before[0] = '\0';
261 middlel[0] = '\0';
262 middleh[0] = '\0';
263 after[0] = '\0';
264 for (i=start;i<=end;i+=step)
265 {
266 GNUNET_snprintf (buf,
267 sizeof (buf),
268 "%X|",
269 (i - start) / step);
270 if (i / step < start_port / step)
271 strcat (before, buf);
272 else if (i / step > end_port / step)
273 strcat (after, buf);
274 else if (i / step == start_port / step)
275 strcat (middlel, buf);
276 else if (i / step == end_port / step)
277 strcat (middleh, buf);
278 }
279 if (strlen (before) > 0)
280 before[strlen (before)-1] = '\0';
281 if (strlen (middlel) > 0)
282 middlel[strlen (middlel)-1] = '\0';
283 if (strlen (middleh) > 0)
284 middleh[strlen (middleh)-1] = '\0';
285 if (strlen (after) > 0)
286 after[strlen (after)-1] = '\0';
287 if (needs_parens (before))
288 GNUNET_snprintf (beforep,
289 sizeof (beforep),
290 "(%s)",
291 before);
292 else
293 strcpy (beforep, before);
294 if (needs_parens (middlel))
295 GNUNET_snprintf (middlelp,
296 sizeof (middlelp),
297 "(%s)",
298 middlel);
299 else
300 strcpy (middlelp, middlel);
301 if (needs_parens (middleh))
302 GNUNET_snprintf (middlehp,
303 sizeof (middlehp),
304 "(%s)",
305 middleh);
306 else
307 strcpy (middlehp, middleh);
308 if (needs_parens (after))
309 GNUNET_snprintf (afterp,
310 sizeof (afterp),
311 "(%s)",
312 after);
313 else
314 strcpy (afterp, after);
315 dots[0] = '\0';
316 for (xstep=step/16;xstep>0;xstep/=16)
317 strcat (dots, DOT);
318 if (step >= 16)
319 {
320 if (strlen (middlel) > 0)
321 recl = compute_policy ((start_port / step) * step,
322 (start_port / step) * step + step - 1,
323 step / 16,
324 pp);
325 else
326 recl = GNUNET_strdup ("");
327 if (strlen (middleh) > 0)
328 rech = compute_policy ((end_port / step) * step,
329 (end_port / step) * step + step - 1,
330 step / 16,
331 pp);
332 else
333 rech = GNUNET_strdup ("");
334 }
335 else
336 {
337 recl = GNUNET_strdup ("");
338 rech = GNUNET_strdup ("");
339 middlel[0] = '\0';
340 middlelp[0] = '\0';
341 middleh[0] = '\0';
342 middlehp[0] = '\0';
343 }
344 if (needs_parens (recl))
345 GNUNET_asprintf (&reclp,
346 "(%s)",
347 recl);
348 else
349 reclp = GNUNET_strdup (recl);
350 if (needs_parens (rech))
351 GNUNET_asprintf (&rechp,
352 "(%s)",
353 rech);
354 else
355 rechp = GNUNET_strdup (rech);
356
357 if ( (strlen (middleh) > 0) &&
358 (strlen (rech) > 0) &&
359 (strlen (middlel) > 0) &&
360 (strlen (recl) > 0) )
361 {
362 GNUNET_asprintf (&middle,
363 "%s%s|%s%s",
364 middlel,
365 reclp,
366 middleh,
367 rechp);
368 }
369 else if ( (strlen (middleh) > 0) &&
370 (strlen (rech) > 0) )
371 {
372 GNUNET_asprintf (&middle,
373 "%s%s",
374 middleh,
375 rechp);
376 }
377 else if ( (strlen (middlel) > 0) &&
378 (strlen (recl) > 0) )
379 {
380 GNUNET_asprintf (&middle,
381 "%s%s",
382 middlel,
383 reclp);
384 }
385 else
386 {
387 middle = GNUNET_strdup ("");
388 }
389 if ( (strlen(before) > 0) &&
390 (strlen(after) > 0) )
391 {
392 if (strlen (dots) > 0)
393 {
394 if (strlen (middle) > 0)
395 GNUNET_asprintf (&ret,
396 "(%s%s|%s|%s%s)",
397 beforep, dots,
398 middle,
399 afterp, dots);
400 else
401 GNUNET_asprintf (&ret,
402 "(%s|%s)%s",
403 beforep,
404 afterp,
405 dots);
406 }
407 else
408 {
409 if (strlen (middle) > 0)
410 GNUNET_asprintf (&ret,
411 "(%s|%s|%s)",
412 before,
413 middle,
414 after);
415 else if (1 == step)
416 GNUNET_asprintf (&ret,
417 "%s|%s",
418 before,
419 after);
420 else
421 GNUNET_asprintf (&ret,
422 "(%s|%s)",
423 before,
424 after);
425 }
426 }
427 else if (strlen (before) > 0)
428 {
429 if (strlen (dots) > 0)
430 {
431 if (strlen (middle) > 0)
432 GNUNET_asprintf (&ret,
433 "(%s%s|%s)",
434 beforep, dots,
435 middle);
436 else
437 GNUNET_asprintf (&ret,
438 "%s%s",
439 beforep, dots);
440 }
441 else
442 {
443 if (strlen (middle) > 0)
444 GNUNET_asprintf (&ret,
445 "(%s|%s)",
446 before,
447 middle);
448 else
449 GNUNET_asprintf (&ret,
450 "%s",
451 before);
452 }
453 }
454 else if (strlen (after) > 0)
455 {
456 if (strlen (dots) > 0)
457 {
458 if (strlen (middle) > 0)
459 GNUNET_asprintf (&ret,
460 "(%s|%s%s)",
461 middle,
462 afterp, dots);
463 else
464 GNUNET_asprintf (&ret,
465 "%s%s",
466 afterp, dots);
467 }
468 else
469 {
470 if (strlen (middle) > 0)
471 GNUNET_asprintf (&ret,
472 "%s|%s",
473 middle,
474 after);
475 else
476 GNUNET_asprintf (&ret,
477 "%s",
478 after);
479 }
480 }
481 else if (strlen (middle) > 0)
482 {
483 GNUNET_asprintf (&ret,
484 "%s",
485 middle);
486 }
487 else
488 {
489 ret = GNUNET_strdup ("");
490 }
491 GNUNET_free (middle);
492 GNUNET_free (reclp);
493 GNUNET_free (rechp);
494 GNUNET_free (recl);
495 GNUNET_free (rech);
496 return ret;
497}
498
499
500/**
501 * Convert a port policy to a regular expression. Note: this is a
502 * very simplistic implementation, we might want to consider doing
503 * something more sophisiticated (resulting in smaller regular
504 * expressions) at a later time.
505 *
506 * @param pp port policy to convert
507 * @return NULL on error
508 */
509static char *
510port_to_regex (const struct GNUNET_STRINGS_PortPolicy *pp)
511{
512 char *reg;
513 char *ret;
514 char *pos;
515 unsigned int i;
516 unsigned int cnt;
517
518 if ( (0 == pp->start_port) ||
519 ( (1 == pp->start_port) &&
520 (0xFFFF == pp->end_port) &&
521 (GNUNET_NO == pp->negate_portrange)) )
522 return GNUNET_strdup (DOT DOT DOT DOT);
523 if ( (pp->start_port == pp->end_port) &&
524 (GNUNET_NO == pp->negate_portrange))
525 {
526 GNUNET_asprintf (&ret,
527 "%04X",
528 pp->start_port);
529 return ret;
530 }
531 if (pp->end_port < pp->start_port)
532 return NULL;
533
534 if (GNUNET_YES == pp->negate_portrange)
535 {
536 ret = compute_policy (0, 0xFFFF, 0x1000, pp);
537 }
538 else
539 {
540 cnt = pp->end_port - pp->start_port + 1;
541 reg = GNUNET_malloc (cnt * 5 + 1);
542 pos = reg;
543 for (i=1;i<=0xFFFF;i++)
544 {
545 if ( (i >= pp->start_port) && (i <= pp->end_port) )
546 {
547 if (pos == reg)
548 {
549 GNUNET_snprintf (pos,
550 5,
551 "%04X",
552 i);
553 }
554 else
555 {
556 GNUNET_snprintf (pos,
557 6,
558 "|%04X",
559 i);
560 }
561 pos += strlen (pos);
562 }
563 }
564 GNUNET_asprintf (&ret,
565 "(%s)",
566 reg);
567 GNUNET_free (reg);
568 }
569 return ret;
570}
571
572
573/**
574 * Convert an address (IPv4 or IPv6) to a regex.
575 *
576 * @param addr address
577 * @param mask network mask
578 * @param len number of bytes in @a addr and @a mask
579 * @return NULL on error, otherwise regex for the address
580 */
581static char *
582address_to_regex (const void *addr,
583 const void *mask,
584 size_t len)
585{
586 const uint16_t *a = addr;
587 const uint16_t *m = mask;
588 char *ret;
589 char *tmp;
590 char *reg;
591 unsigned int i;
592
593 ret = NULL;
594 GNUNET_assert (1 != (len % 2));
595 for (i=0;i<len / 2;i++)
596 {
597 reg = num_to_regex (a[i], m[i]);
598 if (NULL == reg)
599 {
600 GNUNET_free_non_null (ret);
601 return NULL;
602 }
603 if (NULL == ret)
604 {
605 ret = reg;
606 }
607 else
608 {
609 GNUNET_asprintf (&tmp,
610 "%s%s",
611 ret, reg);
612 GNUNET_free (ret);
613 GNUNET_free (reg);
614 ret = tmp;
615 }
616 }
617 return ret;
618}
619
620
621/**
622 * Convert a single line of an IPv4 policy to a regular expression.
623 *
624 * @param v4 line to convert
625 * @return NULL on error
626 */
627static char *
628ipv4_to_regex (const struct GNUNET_STRINGS_IPv4NetworkPolicy *v4)
629{
630 char *reg;
631 char *pp;
632 char *ret;
633
634 reg = address_to_regex (&v4->network,
635 &v4->netmask,
636 sizeof (struct in_addr));
637 if (NULL == reg)
638 return NULL;
639 pp = port_to_regex (&v4->pp);
640 if (NULL == pp)
641 {
642 GNUNET_free (reg);
643 return NULL;
644 }
645 GNUNET_asprintf (&ret,
646 "4-%s-%s",
647 pp, reg);
648 GNUNET_free (pp);
649 GNUNET_free (reg);
650 return ret;
651}
652
653
654/**
655 * Convert a single line of an IPv4 policy to a regular expression.
656 *
657 * @param v6 line to convert
658 * @return NULL on error
659 */
660static char *
661ipv6_to_regex (const struct GNUNET_STRINGS_IPv6NetworkPolicy *v6)
662{
663 char *reg;
664 char *pp;
665 char *ret;
666
667 reg = address_to_regex (&v6->network,
668 &v6->netmask,
669 sizeof (struct in6_addr));
670 if (NULL == reg)
671 return NULL;
672 pp = port_to_regex (&v6->pp);
673 if (NULL == pp)
674 {
675 GNUNET_free (reg);
676 return NULL;
677 }
678 GNUNET_asprintf (&ret,
679 "6-%s-%s",
680 pp, reg);
681 GNUNET_free (pp);
682 GNUNET_free (reg);
683 return ret;
684}
685
686
687/**
688 * Convert an exit policy to a regular expression. The exit policy
689 * specifies a set of subnets this peer is willing to serve as an
690 * exit for; the resulting regular expression will match the
691 * IPv4 address strings as returned by #GNUNET_TUN_ipv4toregexsearch().
692 *
693 * @param policy exit policy specification
694 * @return regular expression, NULL on error
695 */
696char *
697GNUNET_TUN_ipv4policy2regex (const char *policy)
698{
699 struct GNUNET_STRINGS_IPv4NetworkPolicy *np;
700 char *reg;
701 char *tmp;
702 char *line;
703 unsigned int i;
704
705 np = GNUNET_STRINGS_parse_ipv4_policy (policy);
706 if (NULL == np)
707 return NULL;
708 reg = NULL;
709 for (i=0; (0 == i) || (0 != np[i].network.s_addr); i++)
710 {
711 line = ipv4_to_regex (&np[i]);
712 if (NULL == line)
713 {
714 GNUNET_free_non_null (reg);
715 GNUNET_free (np);
716 return NULL;
717 }
718 if (NULL == reg)
719 {
720 reg = line;
721 }
722 else
723 {
724 GNUNET_asprintf (&tmp,
725 "%s|(%s)",
726 reg, line);
727 GNUNET_free (reg);
728 GNUNET_free (line);
729 reg = tmp;
730 }
731 if (0 == np[i].network.s_addr)
732 break;
733 }
734 GNUNET_free (np);
735 return reg;
736}
737
738
739/**
740 * Convert an exit policy to a regular expression. The exit policy
741 * specifies a set of subnets this peer is willing to serve as an
742 * exit for; the resulting regular expression will match the
743 * IPv6 address strings as returned by #GNUNET_TUN_ipv6toregexsearch().
744 *
745 * @param policy exit policy specification
746 * @return regular expression, NULL on error
747 */
748char *
749GNUNET_TUN_ipv6policy2regex (const char *policy)
750{
751 struct in6_addr zero;
752 struct GNUNET_STRINGS_IPv6NetworkPolicy *np;
753 char *reg;
754 char *tmp;
755 char *line;
756 unsigned int i;
757
758 np = GNUNET_STRINGS_parse_ipv6_policy (policy);
759 if (NULL == np)
760 return NULL;
761 reg = NULL;
762 memset (&zero, 0, sizeof (struct in6_addr));
763 for (i=0; (0 == i) || (0 != memcmp (&zero, &np[i].network, sizeof (struct in6_addr))); i++)
764 {
765 line = ipv6_to_regex (&np[i]);
766 if (NULL == line)
767 {
768 GNUNET_free_non_null (reg);
769 GNUNET_free (np);
770 return NULL;
771 }
772 if (NULL == reg)
773 {
774 reg = line;
775 }
776 else
777 {
778 GNUNET_asprintf (&tmp,
779 "%s|(%s)",
780 reg, line);
781 GNUNET_free (reg);
782 GNUNET_free (line);
783 reg = tmp;
784 }
785 if (0 == memcmp (&zero, &np[i].network, sizeof (struct in6_addr)))
786 break;
787 }
788 GNUNET_free (np);
789 return reg;
790}
791
792
793/**
794 * Hash the service name of a hosted service to the
795 * hash code that is used to identify the service on
796 * the network.
797 *
798 * @param service_name a string
799 * @param hc corresponding hash
800 */
801void
802GNUNET_TUN_service_name_to_hash (const char *service_name,
803 struct GNUNET_HashCode *hc)
804{
805 GNUNET_CRYPTO_hash (service_name,
806 strlen (service_name),
807 hc);
808}
809
810
811/**
812 * Compute the CADET port given a service descriptor
813 * (returned from #GNUNET_TUN_service_name_to_hash) and
814 * a TCP/UDP port @a ip_port.
815 *
816 * @param desc service shared secret
817 * @param ip_port TCP/UDP port, use 0 for ICMP
818 * @param[out] cadet_port CADET port to use
819 */
820void
821GNUNET_TUN_compute_service_cadet_port (const struct GNUNET_HashCode *desc,
822 uint16_t ip_port,
823 struct GNUNET_HashCode *cadet_port)
824{
825 uint16_t be_port = htons (ip_port);
826
827 *cadet_port = *desc;
828 GNUNET_memcpy (cadet_port,
829 &be_port,
830 sizeof (uint16_t));
831}
832
833
834/* end of regex.c */
diff --git a/src/util/test_hexcoder.c b/src/util/test_hexcoder.c
deleted file mode 100644
index 441d7e200..000000000
--- a/src/util/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 */
diff --git a/src/util/test_regex.c b/src/util/test_regex.c
deleted file mode 100644
index 2e7d52828..000000000
--- a/src/util/test_regex.c
+++ /dev/null
@@ -1,179 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2012, 2013 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18/**
19 * @file tun/test_regex.c
20 * @brief simple test for regex.c iptoregex functions
21 * @author Maximilian Szengel
22 */
23#include "platform.h"
24#include "gnunet_tun_lib.h"
25
26/**
27 * 'wildcard', matches all possible values (for HEX encoding).
28 */
29#define DOT "(0|1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"
30
31
32static int
33test_iptoregex (const char *ipv4,
34 uint16_t port,
35 const char *expectedv4,
36 const char *ipv6,
37 uint16_t port6,
38 const char *expectedv6)
39{
40 int error = 0;
41
42 struct in_addr a;
43 struct in6_addr b;
44 char rxv4[GNUNET_TUN_IPV4_REGEXLEN];
45 char rxv6[GNUNET_TUN_IPV6_REGEXLEN];
46
47 GNUNET_assert (1 == inet_pton (AF_INET, ipv4, &a));
48 GNUNET_TUN_ipv4toregexsearch (&a, port, rxv4);
49
50 if (0 != strcmp (rxv4, expectedv4))
51 {
52 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
53 "Expected: %s but got: %s\n",
54 expectedv4,
55 rxv4);
56 error++;
57 }
58
59 GNUNET_assert (1 == inet_pton (AF_INET6, ipv6, &b));
60 GNUNET_TUN_ipv6toregexsearch (&b, port6, rxv6);
61 if (0 != strcmp (rxv6, expectedv6))
62 {
63 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
64 "Expected: %s but got: %s\n",
65 expectedv6, rxv6);
66 error++;
67 }
68 return error;
69}
70
71
72static int
73test_policy4toregex (const char *policy,
74 const char *regex)
75{
76 char *r;
77 int ret;
78
79 ret = 0;
80 r = GNUNET_TUN_ipv4policy2regex (policy);
81 if (NULL == r)
82 {
83 GNUNET_break (0);
84 return 1;
85 }
86 if (0 != strcmp (regex, r))
87 {
88 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
89 "Expected: `%s' but got: `%s'\n",
90 regex, r);
91 ret = 2;
92 }
93 GNUNET_free (r);
94 return ret;
95}
96
97
98static int
99test_policy6toregex (const char *policy,
100 const char *regex)
101{
102 char *r;
103 int ret;
104
105 ret = 0;
106 r = GNUNET_TUN_ipv6policy2regex (policy);
107 if (NULL == r)
108 {
109 GNUNET_break (0);
110 return 1;
111 }
112 if (0 != strcmp (regex, r))
113 {
114 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
115 "Expected: `%s' but got: `%s'\n",
116 regex, r);
117 ret = 2;
118 }
119 GNUNET_free (r);
120 return ret;
121}
122
123
124int
125main (int argc, char *argv[])
126{
127 int error;
128 char *r;
129
130 GNUNET_log_setup ("test-regex", "WARNING", NULL);
131 error = 0;
132
133 /* this is just a performance test ... */
134 r = GNUNET_TUN_ipv4policy2regex ("1.2.3.4/16:!25;");
135 GNUNET_break (NULL != r);
136 GNUNET_free (r);
137
138 error +=
139 test_iptoregex ("192.1.2.3", 2086,
140 "4-0826-C0010203",
141 "FFFF::1", 8080,
142 "6-1F90-FFFF0000000000000000000000000001");
143 error +=
144 test_iptoregex ("187.238.255.0", 80,
145 "4-0050-BBEEFF00",
146 "E1E1:73F9:51BE::0", 49,
147 "6-0031-E1E173F951BE00000000000000000000");
148 error +=
149 test_policy4toregex ("192.1.2.0/24:80;",
150 "4-0050-C00102" DOT DOT);
151 error +=
152 test_policy4toregex ("192.1.0.0/16;",
153 "4-" DOT DOT DOT DOT "-C001" DOT DOT DOT DOT);
154 error +=
155 test_policy4toregex ("192.1.0.0/16:80-81;",
156 "4-(0050|0051)-C001" DOT DOT DOT DOT);
157 error +=
158 test_policy4toregex ("192.1.0.0/8:!3-65535;",
159 "4-000(0|1|2)-C0" DOT DOT DOT DOT DOT DOT);
160 error +=
161 test_policy4toregex ("192.1.0.0/8:!25-56;",
162 "4-(0(0(0"DOT"|1(0|1|2|3|4|5|6|7|8)|3(9|A|B|C|D|E|F)|(4|5|6|7|8|9|A|B|C|D|E|F)"DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT")|(1|2|3|4|5|6|7|8|9|A|B|C|D|E|F)"DOT DOT DOT")-C0"DOT DOT DOT DOT DOT DOT);
163 error +=
164 test_policy6toregex ("E1E1::1;",
165 "6-"DOT DOT DOT DOT"-E1E10000000000000000000000000001");
166 error +=
167 test_policy6toregex ("E1E1:ABCD::1/120;",
168 "6-"DOT DOT DOT DOT"-E1E1ABCD0000000000000000000000" DOT DOT);
169 error +=
170 test_policy6toregex ("E1E1:ABCD::ABCD/126;",
171 "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D|E|F)");
172 error +=
173 test_policy6toregex ("E1E1:ABCD::ABCD/127;",
174 "6-"DOT DOT DOT DOT"-E1E1ABCD00000000000000000000ABC(C|D)");
175 error +=
176 test_policy6toregex ("E1E1:ABCD::ABCD/128:80;",
177 "6-0050-E1E1ABCD00000000000000000000ABCD");
178 return error;
179}
diff --git a/src/util/test_tun.c b/src/util/test_tun.c
deleted file mode 100644
index edbd4c05d..000000000
--- a/src/util/test_tun.c
+++ /dev/null
@@ -1,72 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
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 tun/test_tun.c
21 * @brief test for tun.c
22 * @author Christian Grothoff
23 */
24#include "platform.h"
25#include "gnunet_tun_lib.h"
26
27static int ret;
28
29static void
30test_udp (size_t pll,
31 int pl_fill,
32 uint16_t crc)
33{
34 struct GNUNET_TUN_IPv4Header ip;
35 struct GNUNET_TUN_UdpHeader udp;
36 char payload[pll];
37 struct in_addr src;
38 struct in_addr dst;
39
40 GNUNET_assert (1 == inet_pton (AF_INET, "1.2.3.4", &src));
41 GNUNET_assert (1 == inet_pton (AF_INET, "122.2.3.5", &dst));
42 memset (payload, pl_fill, sizeof (payload));
43 GNUNET_TUN_initialize_ipv4_header (&ip,
44 IPPROTO_UDP,
45 pll + sizeof (udp),
46 &src,
47 &dst);
48 udp.source_port = htons (4242);
49 udp.destination_port = htons (4242);
50 udp.len = htons (pll);
51 GNUNET_TUN_calculate_udp4_checksum (&ip,
52 &udp,
53 payload,
54 pll);
55 if (crc != ntohs (udp.crc))
56 {
57 fprintf (stderr, "Got CRC: %u, wanted: %u\n",
58 ntohs (udp.crc),
59 crc);
60 ret = 1;
61 }
62}
63
64int main (int argc,
65 char **argv)
66{
67 test_udp (4, 3, 22439);
68 test_udp (4, 1, 23467);
69 test_udp (7, 17, 6516);
70 test_udp (12451, 251, 42771);
71 return ret;
72}
diff --git a/src/util/tun.c b/src/util/tun.c
deleted file mode 100644
index 7c35a76da..000000000
--- a/src/util/tun.c
+++ /dev/null
@@ -1,309 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 Christian Grothoff
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 tun/tun.c
21 * @brief standard IP calculations for TUN interaction
22 * @author Philipp Toelke
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27
28/**
29 * IP TTL we use for packets that we assemble (8 bit unsigned integer)
30 */
31#define FRESH_TTL 64
32
33
34/**
35 * Initialize an IPv4 header.
36 *
37 * @param ip header to initialize
38 * @param protocol protocol to use (i.e. IPPROTO_UDP)
39 * @param payload_length number of bytes of payload that follow (excluding IPv4 header)
40 * @param src source IP address to use
41 * @param dst destination IP address to use
42 */
43void
44GNUNET_TUN_initialize_ipv4_header (struct GNUNET_TUN_IPv4Header *ip,
45 uint8_t protocol,
46 uint16_t payload_length,
47 const struct in_addr *src,
48 const struct in_addr *dst)
49{
50 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_IPv4Header));
51 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv4Header));
52 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv4Header));
53 ip->header_length = sizeof (struct GNUNET_TUN_IPv4Header) / 4;
54 ip->version = 4;
55 ip->total_length = htons (sizeof (struct GNUNET_TUN_IPv4Header) + payload_length);
56 ip->identification = (uint16_t) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
57 65536);
58 ip->ttl = FRESH_TTL;
59 ip->protocol = protocol;
60 ip->source_address = *src;
61 ip->destination_address = *dst;
62 ip->checksum = GNUNET_CRYPTO_crc16_n (ip, sizeof (struct GNUNET_TUN_IPv4Header));
63}
64
65
66/**
67 * Initialize an IPv6 header.
68 *
69 * @param ip header to initialize
70 * @param protocol protocol to use (i.e. IPPROTO_UDP), technically "next_header" for IPv6
71 * @param payload_length number of bytes of payload that follow (excluding IPv6 header)
72 * @param src source IP address to use
73 * @param dst destination IP address to use
74 */
75void
76GNUNET_TUN_initialize_ipv6_header (struct GNUNET_TUN_IPv6Header *ip,
77 uint8_t protocol,
78 uint16_t payload_length,
79 const struct in6_addr *src,
80 const struct in6_addr *dst)
81{
82 GNUNET_assert (40 == sizeof (struct GNUNET_TUN_IPv6Header));
83 GNUNET_assert (payload_length <= UINT16_MAX - sizeof (struct GNUNET_TUN_IPv6Header));
84 memset (ip, 0, sizeof (struct GNUNET_TUN_IPv6Header));
85 ip->version = 6;
86 ip->next_header = protocol;
87 ip->payload_length = htons ((uint16_t) payload_length);
88 ip->hop_limit = FRESH_TTL;
89 ip->destination_address = *dst;
90 ip->source_address = *src;
91}
92
93
94/**
95 * Calculate IPv4 TCP checksum.
96 *
97 * @param ip ipv4 header fully initialized
98 * @param tcp TCP header (initialized except for CRC)
99 * @param payload the TCP payload
100 * @param payload_length number of bytes of TCP payload
101 */
102void
103GNUNET_TUN_calculate_tcp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
104 struct GNUNET_TUN_TcpHeader *tcp,
105 const void *payload,
106 uint16_t payload_length)
107{
108 uint32_t sum;
109 uint16_t tmp;
110
111 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
112 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_TcpHeader) ==
113 ntohs (ip->total_length));
114 GNUNET_assert (IPPROTO_TCP == ip->protocol);
115
116 tcp->crc = 0;
117 sum = GNUNET_CRYPTO_crc16_step (0,
118 &ip->source_address,
119 sizeof (struct in_addr) * 2);
120 tmp = htons (IPPROTO_TCP);
121 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
122 tmp = htons (payload_length + sizeof (struct GNUNET_TUN_TcpHeader));
123 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint16_t));
124 sum = GNUNET_CRYPTO_crc16_step (sum, tcp, sizeof (struct GNUNET_TUN_TcpHeader));
125 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
126 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
127}
128
129
130/**
131 * Calculate IPv6 TCP checksum.
132 *
133 * @param ip ipv6 header fully initialized
134 * @param tcp header (initialized except for CRC)
135 * @param payload the TCP payload
136 * @param payload_length number of bytes of TCP payload
137 */
138void
139GNUNET_TUN_calculate_tcp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
140 struct GNUNET_TUN_TcpHeader *tcp,
141 const void *payload,
142 uint16_t payload_length)
143{
144 uint32_t sum;
145 uint32_t tmp;
146
147 GNUNET_assert (20 == sizeof (struct GNUNET_TUN_TcpHeader));
148 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_TcpHeader) ==
149 ntohs (ip->payload_length));
150 GNUNET_assert (IPPROTO_TCP == ip->next_header);
151 tcp->crc = 0;
152 sum = GNUNET_CRYPTO_crc16_step (0, &ip->source_address, 2 * sizeof (struct in6_addr));
153 tmp = htonl (sizeof (struct GNUNET_TUN_TcpHeader) + payload_length);
154 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
155 tmp = htonl (IPPROTO_TCP);
156 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
157 sum = GNUNET_CRYPTO_crc16_step (sum, tcp,
158 sizeof (struct GNUNET_TUN_TcpHeader));
159 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
160 tcp->crc = GNUNET_CRYPTO_crc16_finish (sum);
161}
162
163
164/**
165 * Calculate IPv4 UDP checksum.
166 *
167 * @param ip ipv4 header fully initialized
168 * @param udp UDP header (initialized except for CRC)
169 * @param payload the UDP payload
170 * @param payload_length number of bytes of UDP payload
171 */
172void
173GNUNET_TUN_calculate_udp4_checksum (const struct GNUNET_TUN_IPv4Header *ip,
174 struct GNUNET_TUN_UdpHeader *udp,
175 const void *payload,
176 uint16_t payload_length)
177{
178 uint32_t sum;
179 uint16_t tmp;
180
181 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_UdpHeader));
182 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_IPv4Header) + sizeof (struct GNUNET_TUN_UdpHeader) ==
183 ntohs (ip->total_length));
184 GNUNET_assert (IPPROTO_UDP == ip->protocol);
185
186 udp->crc = 0; /* technically optional, but we calculate it anyway, just to be sure */
187 sum = GNUNET_CRYPTO_crc16_step (0,
188 &ip->source_address,
189 sizeof (struct in_addr) * 2);
190 tmp = htons (IPPROTO_UDP);
191 sum = GNUNET_CRYPTO_crc16_step (sum,
192 &tmp,
193 sizeof (uint16_t));
194 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length);
195 sum = GNUNET_CRYPTO_crc16_step (sum,
196 &tmp,
197 sizeof (uint16_t));
198 sum = GNUNET_CRYPTO_crc16_step (sum,
199 udp,
200 sizeof (struct GNUNET_TUN_UdpHeader));
201 sum = GNUNET_CRYPTO_crc16_step (sum,
202 payload,
203 payload_length);
204 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
205}
206
207
208/**
209 * Calculate IPv6 UDP checksum.
210 *
211 * @param ip ipv6 header fully initialized
212 * @param udp UDP header (initialized except for CRC)
213 * @param payload the UDP payload
214 * @param payload_length number of bytes of UDP payload
215 */
216void
217GNUNET_TUN_calculate_udp6_checksum (const struct GNUNET_TUN_IPv6Header *ip,
218 struct GNUNET_TUN_UdpHeader *udp,
219 const void *payload,
220 uint16_t payload_length)
221{
222 uint32_t sum;
223 uint32_t tmp;
224
225 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
226 ntohs (ip->payload_length));
227 GNUNET_assert (payload_length + sizeof (struct GNUNET_TUN_UdpHeader) ==
228 ntohs (udp->len));
229 GNUNET_assert (IPPROTO_UDP == ip->next_header);
230
231 udp->crc = 0;
232 sum = GNUNET_CRYPTO_crc16_step (0,
233 &ip->source_address,
234 sizeof (struct in6_addr) * 2);
235 tmp = htons (sizeof (struct GNUNET_TUN_UdpHeader) + payload_length); /* aka udp->len */
236 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
237 tmp = htons (ip->next_header);
238 sum = GNUNET_CRYPTO_crc16_step (sum, &tmp, sizeof (uint32_t));
239 sum = GNUNET_CRYPTO_crc16_step (sum, udp, sizeof (struct GNUNET_TUN_UdpHeader));
240 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
241 udp->crc = GNUNET_CRYPTO_crc16_finish (sum);
242}
243
244
245/**
246 * Calculate ICMP checksum.
247 *
248 * @param icmp IMCP header (initialized except for CRC)
249 * @param payload the ICMP payload
250 * @param payload_length number of bytes of ICMP payload
251 */
252void
253GNUNET_TUN_calculate_icmp_checksum (struct GNUNET_TUN_IcmpHeader *icmp,
254 const void *payload,
255 uint16_t payload_length)
256{
257 uint32_t sum;
258
259 GNUNET_assert (8 == sizeof (struct GNUNET_TUN_IcmpHeader));
260 icmp->crc = 0;
261 sum = GNUNET_CRYPTO_crc16_step (0,
262 icmp,
263 sizeof (struct GNUNET_TUN_IcmpHeader));
264 sum = GNUNET_CRYPTO_crc16_step (sum, payload, payload_length);
265 icmp->crc = GNUNET_CRYPTO_crc16_finish (sum);
266}
267
268
269/**
270 * Check if two sockaddrs are equal.
271 *
272 * @param sa one address
273 * @param sb another address
274 * @param include_port also check ports
275 * @return #GNUNET_YES if they are equal
276 */
277int
278GNUNET_TUN_sockaddr_cmp (const struct sockaddr *sa,
279 const struct sockaddr *sb,
280 int include_port)
281{
282 if (sa->sa_family != sb->sa_family)
283 return GNUNET_NO;
284
285 switch (sa->sa_family)
286 {
287 case AF_INET:
288 {
289 const struct sockaddr_in *sa4 = (const struct sockaddr_in *) sa;
290 const struct sockaddr_in *sb4 = (const struct sockaddr_in *) sb;
291 return (sa4->sin_addr.s_addr == sb4->sin_addr.s_addr);
292 }
293 case AF_INET6:
294 {
295 const struct sockaddr_in6 *sa6 = (const struct sockaddr_in6 *) sa;
296 const struct sockaddr_in6 *sb6 = (const struct sockaddr_in6 *) sb;
297
298 return (0 == memcmp(&sa6->sin6_addr,
299 &sb6->sin6_addr,
300 sizeof (struct in6_addr)));
301 }
302 default:
303 GNUNET_break (0);
304 return GNUNET_SYSERR;
305 }
306}
307
308
309/* end of tun.c */