diff options
Diffstat (limited to 'src/gnsrecord/plugin_gnsrecord_dns.c')
-rw-r--r-- | src/gnsrecord/plugin_gnsrecord_dns.c | 812 |
1 files changed, 0 insertions, 812 deletions
diff --git a/src/gnsrecord/plugin_gnsrecord_dns.c b/src/gnsrecord/plugin_gnsrecord_dns.c deleted file mode 100644 index 123c59905..000000000 --- a/src/gnsrecord/plugin_gnsrecord_dns.c +++ /dev/null | |||
@@ -1,812 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | Copyright (C) 2013, 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 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file gnsrecord/plugin_gnsrecord_dns.c | ||
23 | * @brief gnsrecord plugin to provide the API for basic DNS records | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_dnsparser_lib.h" | ||
29 | #include "gnunet_gnsrecord_plugin.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Convert the 'value' of a record to a string. | ||
34 | * | ||
35 | * @param cls closure, unused | ||
36 | * @param type type of the record | ||
37 | * @param data value in binary encoding | ||
38 | * @param data_size number of bytes in @a data | ||
39 | * @return NULL on error, otherwise human-readable representation of the value | ||
40 | */ | ||
41 | static char * | ||
42 | dns_value_to_string (void *cls, | ||
43 | uint32_t type, | ||
44 | const void *data, | ||
45 | size_t data_size) | ||
46 | { | ||
47 | char *result; | ||
48 | char tmp[INET6_ADDRSTRLEN]; | ||
49 | |||
50 | switch (type) | ||
51 | { | ||
52 | case GNUNET_DNSPARSER_TYPE_A: | ||
53 | if (data_size != sizeof(struct in_addr)) | ||
54 | return NULL; | ||
55 | if (NULL == inet_ntop (AF_INET, data, tmp, sizeof(tmp))) | ||
56 | return NULL; | ||
57 | return GNUNET_strdup (tmp); | ||
58 | |||
59 | case GNUNET_DNSPARSER_TYPE_NS: { | ||
60 | char *ns; | ||
61 | size_t off; | ||
62 | |||
63 | off = 0; | ||
64 | ns = GNUNET_DNSPARSER_parse_name (data, data_size, &off); | ||
65 | if ((NULL == ns) || (off != data_size)) | ||
66 | { | ||
67 | GNUNET_break_op (0); | ||
68 | GNUNET_free (ns); | ||
69 | return NULL; | ||
70 | } | ||
71 | return ns; | ||
72 | } | ||
73 | |||
74 | case GNUNET_DNSPARSER_TYPE_CNAME: { | ||
75 | char *cname; | ||
76 | size_t off; | ||
77 | |||
78 | off = 0; | ||
79 | cname = GNUNET_DNSPARSER_parse_name (data, data_size, &off); | ||
80 | if ((NULL == cname) || (off != data_size)) | ||
81 | { | ||
82 | GNUNET_break_op (0); | ||
83 | GNUNET_free (cname); | ||
84 | return NULL; | ||
85 | } | ||
86 | return cname; | ||
87 | } | ||
88 | |||
89 | case GNUNET_DNSPARSER_TYPE_SOA: { | ||
90 | struct GNUNET_DNSPARSER_SoaRecord *soa; | ||
91 | size_t off; | ||
92 | |||
93 | off = 0; | ||
94 | soa = GNUNET_DNSPARSER_parse_soa (data, data_size, &off); | ||
95 | if ((NULL == soa) || (off != data_size)) | ||
96 | { | ||
97 | GNUNET_break_op (0); | ||
98 | if (NULL != soa) | ||
99 | GNUNET_DNSPARSER_free_soa (soa); | ||
100 | return NULL; | ||
101 | } | ||
102 | GNUNET_asprintf (&result, | ||
103 | "rname=%s mname=%s %u,%u,%u,%u,%u", | ||
104 | soa->rname, | ||
105 | soa->mname, | ||
106 | soa->serial, | ||
107 | soa->refresh, | ||
108 | soa->retry, | ||
109 | soa->expire, | ||
110 | soa->minimum_ttl); | ||
111 | GNUNET_DNSPARSER_free_soa (soa); | ||
112 | return result; | ||
113 | } | ||
114 | |||
115 | case GNUNET_DNSPARSER_TYPE_PTR: { | ||
116 | char *ptr; | ||
117 | size_t off; | ||
118 | |||
119 | off = 0; | ||
120 | ptr = GNUNET_DNSPARSER_parse_name (data, data_size, &off); | ||
121 | if ((NULL == ptr) || (off != data_size)) | ||
122 | { | ||
123 | GNUNET_break_op (0); | ||
124 | GNUNET_free (ptr); | ||
125 | return NULL; | ||
126 | } | ||
127 | return ptr; | ||
128 | } | ||
129 | |||
130 | case GNUNET_DNSPARSER_TYPE_CERT: { | ||
131 | struct GNUNET_DNSPARSER_CertRecord *cert; | ||
132 | size_t off; | ||
133 | char *base64; | ||
134 | int len; | ||
135 | |||
136 | off = 0; | ||
137 | cert = GNUNET_DNSPARSER_parse_cert (data, data_size, &off); | ||
138 | if ((NULL == cert) || (off != data_size)) | ||
139 | { | ||
140 | GNUNET_break_op (0); | ||
141 | GNUNET_DNSPARSER_free_cert (cert); | ||
142 | return NULL; | ||
143 | } | ||
144 | len = GNUNET_STRINGS_base64_encode (cert->certificate_data, | ||
145 | cert->certificate_size, | ||
146 | &base64); | ||
147 | GNUNET_asprintf (&result, | ||
148 | "%u %u %u %.*s", | ||
149 | cert->cert_type, | ||
150 | cert->cert_tag, | ||
151 | cert->algorithm, | ||
152 | len, | ||
153 | base64); | ||
154 | GNUNET_free (base64); | ||
155 | GNUNET_DNSPARSER_free_cert (cert); | ||
156 | return result; | ||
157 | } | ||
158 | |||
159 | case GNUNET_DNSPARSER_TYPE_MX: { | ||
160 | struct GNUNET_DNSPARSER_MxRecord *mx; | ||
161 | size_t off; | ||
162 | |||
163 | off = 0; | ||
164 | mx = GNUNET_DNSPARSER_parse_mx (data, data_size, &off); | ||
165 | if ((NULL == mx) || (off != data_size)) | ||
166 | { | ||
167 | GNUNET_break_op (0); | ||
168 | GNUNET_DNSPARSER_free_mx (mx); | ||
169 | return NULL; | ||
170 | } | ||
171 | GNUNET_asprintf (&result, | ||
172 | "%u,%s", | ||
173 | (unsigned int) mx->preference, | ||
174 | mx->mxhost); | ||
175 | GNUNET_DNSPARSER_free_mx (mx); | ||
176 | return result; | ||
177 | } | ||
178 | |||
179 | case GNUNET_DNSPARSER_TYPE_TXT: | ||
180 | return GNUNET_strndup (data, data_size); | ||
181 | |||
182 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
183 | if (data_size != sizeof(struct in6_addr)) | ||
184 | return NULL; | ||
185 | if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof(tmp))) | ||
186 | return NULL; | ||
187 | return GNUNET_strdup (tmp); | ||
188 | |||
189 | case GNUNET_DNSPARSER_TYPE_SRV: { | ||
190 | struct GNUNET_DNSPARSER_SrvRecord *srv; | ||
191 | size_t off; | ||
192 | |||
193 | off = 0; | ||
194 | srv = GNUNET_DNSPARSER_parse_srv (data, data_size, &off); | ||
195 | if ((NULL == srv) || (off != data_size)) | ||
196 | { | ||
197 | GNUNET_break_op (0); | ||
198 | if (NULL != srv) | ||
199 | GNUNET_DNSPARSER_free_srv (srv); | ||
200 | return NULL; | ||
201 | } | ||
202 | GNUNET_asprintf (&result, | ||
203 | "%d %d %d %s", | ||
204 | srv->priority, | ||
205 | srv->weight, | ||
206 | srv->port, | ||
207 | srv->target); | ||
208 | GNUNET_DNSPARSER_free_srv (srv); | ||
209 | return result; | ||
210 | } | ||
211 | |||
212 | case GNUNET_DNSPARSER_TYPE_TLSA: { | ||
213 | const struct GNUNET_TUN_DnsTlsaRecord *tlsa; | ||
214 | char *tlsa_str; | ||
215 | char *hex; | ||
216 | |||
217 | if (data_size < sizeof(struct GNUNET_TUN_DnsTlsaRecord)) | ||
218 | return NULL; /* malformed */ | ||
219 | tlsa = data; | ||
220 | hex = | ||
221 | GNUNET_DNSPARSER_bin_to_hex (&tlsa[1], | ||
222 | data_size | ||
223 | - sizeof(struct GNUNET_TUN_DnsTlsaRecord)); | ||
224 | if (0 == GNUNET_asprintf (&tlsa_str, | ||
225 | "%u %u %u %s", | ||
226 | (unsigned int) tlsa->usage, | ||
227 | (unsigned int) tlsa->selector, | ||
228 | (unsigned int) tlsa->matching_type, | ||
229 | hex)) | ||
230 | { | ||
231 | GNUNET_free (hex); | ||
232 | GNUNET_free (tlsa_str); | ||
233 | return NULL; | ||
234 | } | ||
235 | GNUNET_free (hex); | ||
236 | return tlsa_str; | ||
237 | } | ||
238 | |||
239 | case GNUNET_DNSPARSER_TYPE_CAA: { // RFC6844 | ||
240 | const struct GNUNET_DNSPARSER_CaaRecord *caa; | ||
241 | char tag[15]; // between 1 and 15 bytes | ||
242 | char value[data_size]; | ||
243 | char *caa_str; | ||
244 | if (data_size < sizeof(struct GNUNET_DNSPARSER_CaaRecord)) | ||
245 | return NULL; /* malformed */ | ||
246 | caa = data; | ||
247 | if ((1 > caa->tag_len) || (15 < caa->tag_len)) | ||
248 | return NULL; /* malformed */ | ||
249 | memset (tag, 0, sizeof(tag)); | ||
250 | memset (value, 0, data_size); | ||
251 | memcpy (tag, &caa[1], caa->tag_len); | ||
252 | memcpy (value, | ||
253 | (char *) &caa[1] + caa->tag_len, | ||
254 | data_size - caa->tag_len - 2); | ||
255 | if (0 == GNUNET_asprintf (&caa_str, | ||
256 | "%u %s %s", | ||
257 | (unsigned int) caa->flags, | ||
258 | tag, | ||
259 | value)) | ||
260 | { | ||
261 | GNUNET_free (caa_str); | ||
262 | return NULL; | ||
263 | } | ||
264 | return caa_str; | ||
265 | } | ||
266 | |||
267 | default: | ||
268 | return NULL; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Convert RFC 4394 Mnemonics to the corresponding integer values. | ||
275 | * | ||
276 | * @param mnemonic string to look up | ||
277 | * @return the value, 0 if not found | ||
278 | */ | ||
279 | static unsigned int | ||
280 | rfc4398_mnemonic_to_value (const char *mnemonic) | ||
281 | { | ||
282 | static struct | ||
283 | { | ||
284 | const char *mnemonic; | ||
285 | unsigned int val; | ||
286 | } table[] = { { "PKIX", 1 }, | ||
287 | { "SPKI", 2 }, | ||
288 | { "PGP", 3 }, | ||
289 | { "IPKIX", 4 }, | ||
290 | { "ISPKI", 5 }, | ||
291 | { "IPGP", 6 }, | ||
292 | { "ACPKIX", 7 }, | ||
293 | { "IACPKIX", 8 }, | ||
294 | { "URI", 253 }, | ||
295 | { "OID", 254 }, | ||
296 | { NULL, 0 } }; | ||
297 | unsigned int i; | ||
298 | |||
299 | for (i = 0; NULL != table[i].mnemonic; i++) | ||
300 | if (0 == strcasecmp (mnemonic, table[i].mnemonic)) | ||
301 | return table[i].val; | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Convert RFC 4034 algorithm types to the corresponding integer values. | ||
308 | * | ||
309 | * @param mnemonic string to look up | ||
310 | * @return the value, 0 if not found | ||
311 | */ | ||
312 | static unsigned int | ||
313 | rfc4034_mnemonic_to_value (const char *mnemonic) | ||
314 | { | ||
315 | static struct | ||
316 | { | ||
317 | const char *mnemonic; | ||
318 | unsigned int val; | ||
319 | } table[] = { { "RSAMD5", 1 }, | ||
320 | { "DH", 2 }, | ||
321 | { "DSA", 3 }, | ||
322 | { "ECC", 4 }, | ||
323 | { "RSASHA1", 5 }, | ||
324 | { "INDIRECT", 252 }, | ||
325 | { "PRIVATEDNS", 253 }, | ||
326 | { "PRIVATEOID", 254 }, | ||
327 | { NULL, 0 } }; | ||
328 | unsigned int i; | ||
329 | |||
330 | for (i = 0; NULL != table[i].mnemonic; i++) | ||
331 | if (0 == strcasecmp (mnemonic, table[i].mnemonic)) | ||
332 | return table[i].val; | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Convert human-readable version of a 'value' of a record to the binary | ||
339 | * representation. | ||
340 | * | ||
341 | * @param cls closure, unused | ||
342 | * @param type type of the record | ||
343 | * @param s human-readable string | ||
344 | * @param data set to value in binary encoding (will be allocated) | ||
345 | * @param data_size set to number of bytes in @a data | ||
346 | * @return #GNUNET_OK on success | ||
347 | */ | ||
348 | static int | ||
349 | dns_string_to_value (void *cls, | ||
350 | uint32_t type, | ||
351 | const char *s, | ||
352 | void **data, | ||
353 | size_t *data_size) | ||
354 | { | ||
355 | struct in_addr value_a; | ||
356 | struct in6_addr value_aaaa; | ||
357 | struct GNUNET_TUN_DnsTlsaRecord *tlsa; | ||
358 | |||
359 | if (NULL == s) | ||
360 | return GNUNET_SYSERR; | ||
361 | switch (type) | ||
362 | { | ||
363 | case GNUNET_DNSPARSER_TYPE_A: | ||
364 | if (1 != inet_pton (AF_INET, s, &value_a)) | ||
365 | { | ||
366 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
367 | _ ("Unable to parse IPv4 address `%s'\n"), | ||
368 | s); | ||
369 | return GNUNET_SYSERR; | ||
370 | } | ||
371 | *data = GNUNET_new (struct in_addr); | ||
372 | GNUNET_memcpy (*data, &value_a, sizeof(value_a)); | ||
373 | *data_size = sizeof(value_a); | ||
374 | return GNUNET_OK; | ||
375 | |||
376 | case GNUNET_DNSPARSER_TYPE_NS: { | ||
377 | char nsbuf[256]; | ||
378 | size_t off; | ||
379 | |||
380 | off = 0; | ||
381 | if (GNUNET_OK != | ||
382 | GNUNET_DNSPARSER_builder_add_name (nsbuf, sizeof(nsbuf), &off, s)) | ||
383 | { | ||
384 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
385 | _ ("Failed to serialize NS record with value `%s'\n"), | ||
386 | s); | ||
387 | return GNUNET_SYSERR; | ||
388 | } | ||
389 | *data_size = off; | ||
390 | *data = GNUNET_malloc (off); | ||
391 | GNUNET_memcpy (*data, nsbuf, off); | ||
392 | return GNUNET_OK; | ||
393 | } | ||
394 | |||
395 | case GNUNET_DNSPARSER_TYPE_CNAME: { | ||
396 | char cnamebuf[256]; | ||
397 | size_t off; | ||
398 | |||
399 | off = 0; | ||
400 | if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_name (cnamebuf, | ||
401 | sizeof(cnamebuf), | ||
402 | &off, | ||
403 | s)) | ||
404 | { | ||
405 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
406 | _ ("Failed to serialize CNAME record with value `%s'\n"), | ||
407 | s); | ||
408 | return GNUNET_SYSERR; | ||
409 | } | ||
410 | *data_size = off; | ||
411 | *data = GNUNET_malloc (off); | ||
412 | GNUNET_memcpy (*data, cnamebuf, off); | ||
413 | return GNUNET_OK; | ||
414 | } | ||
415 | |||
416 | case GNUNET_DNSPARSER_TYPE_CERT: { | ||
417 | char *sdup; | ||
418 | const char *typep; | ||
419 | const char *keyp; | ||
420 | const char *algp; | ||
421 | const char *certp; | ||
422 | unsigned int type; | ||
423 | unsigned int key; | ||
424 | unsigned int alg; | ||
425 | size_t cert_size; | ||
426 | char *cert_data; | ||
427 | struct GNUNET_DNSPARSER_CertRecord cert; | ||
428 | |||
429 | sdup = GNUNET_strdup (s); | ||
430 | typep = strtok (sdup, " "); | ||
431 | if ((NULL == typep) || | ||
432 | ((0 == (type = rfc4398_mnemonic_to_value (typep))) && | ||
433 | ((1 != sscanf (typep, "%u", &type)) || (type > UINT16_MAX)))) | ||
434 | { | ||
435 | GNUNET_free (sdup); | ||
436 | return GNUNET_SYSERR; | ||
437 | } | ||
438 | keyp = strtok (NULL, " "); | ||
439 | if ((NULL == keyp) || (1 != sscanf (keyp, "%u", &key)) || | ||
440 | (key > UINT16_MAX)) | ||
441 | { | ||
442 | GNUNET_free (sdup); | ||
443 | return GNUNET_SYSERR; | ||
444 | } | ||
445 | alg = 0; | ||
446 | algp = strtok (NULL, " "); | ||
447 | if ((NULL == algp) || | ||
448 | ((0 == (type = rfc4034_mnemonic_to_value (typep))) && | ||
449 | ((1 != sscanf (algp, "%u", &alg)) || (alg > UINT8_MAX)))) | ||
450 | { | ||
451 | GNUNET_free (sdup); | ||
452 | return GNUNET_SYSERR; | ||
453 | } | ||
454 | certp = strtok (NULL, " "); | ||
455 | if ((NULL == certp) || (0 == strlen (certp))) | ||
456 | { | ||
457 | GNUNET_free (sdup); | ||
458 | return GNUNET_SYSERR; | ||
459 | } | ||
460 | cert_size = GNUNET_STRINGS_base64_decode (certp, | ||
461 | strlen (certp), | ||
462 | (void **) &cert_data); | ||
463 | GNUNET_free (sdup); | ||
464 | cert.cert_type = type; | ||
465 | cert.cert_tag = key; | ||
466 | cert.algorithm = alg; | ||
467 | cert.certificate_size = cert_size; | ||
468 | cert.certificate_data = cert_data; | ||
469 | { | ||
470 | char certbuf[cert_size + sizeof(struct GNUNET_TUN_DnsCertRecord)]; | ||
471 | size_t off; | ||
472 | |||
473 | off = 0; | ||
474 | if (GNUNET_OK != GNUNET_DNSPARSER_builder_add_cert (certbuf, | ||
475 | sizeof(certbuf), | ||
476 | &off, | ||
477 | &cert)) | ||
478 | { | ||
479 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
480 | _ ("Failed to serialize CERT record with %u bytes\n"), | ||
481 | (unsigned int) cert_size); | ||
482 | GNUNET_free (cert_data); | ||
483 | return GNUNET_SYSERR; | ||
484 | } | ||
485 | *data_size = off; | ||
486 | *data = GNUNET_malloc (off); | ||
487 | GNUNET_memcpy (*data, certbuf, off); | ||
488 | } | ||
489 | GNUNET_free (cert_data); | ||
490 | return GNUNET_OK; | ||
491 | } | ||
492 | |||
493 | case GNUNET_DNSPARSER_TYPE_SOA: { | ||
494 | struct GNUNET_DNSPARSER_SoaRecord soa; | ||
495 | char soabuf[540]; | ||
496 | char soa_rname[253 + 1]; | ||
497 | char soa_mname[253 + 1]; | ||
498 | unsigned int soa_serial; | ||
499 | unsigned int soa_refresh; | ||
500 | unsigned int soa_retry; | ||
501 | unsigned int soa_expire; | ||
502 | unsigned int soa_min; | ||
503 | size_t off; | ||
504 | |||
505 | if (7 != sscanf (s, | ||
506 | "rname=%253s mname=%253s %u,%u,%u,%u,%u", | ||
507 | soa_rname, | ||
508 | soa_mname, | ||
509 | &soa_serial, | ||
510 | &soa_refresh, | ||
511 | &soa_retry, | ||
512 | &soa_expire, | ||
513 | &soa_min)) | ||
514 | { | ||
515 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
516 | _ ("Unable to parse SOA record `%s'\n"), | ||
517 | s); | ||
518 | return GNUNET_SYSERR; | ||
519 | } | ||
520 | soa.mname = soa_mname; | ||
521 | soa.rname = soa_rname; | ||
522 | soa.serial = (uint32_t) soa_serial; | ||
523 | soa.refresh = (uint32_t) soa_refresh; | ||
524 | soa.retry = (uint32_t) soa_retry; | ||
525 | soa.expire = (uint32_t) soa_expire; | ||
526 | soa.minimum_ttl = (uint32_t) soa_min; | ||
527 | off = 0; | ||
528 | if (GNUNET_OK != | ||
529 | GNUNET_DNSPARSER_builder_add_soa (soabuf, sizeof(soabuf), &off, &soa)) | ||
530 | { | ||
531 | GNUNET_log ( | ||
532 | GNUNET_ERROR_TYPE_ERROR, | ||
533 | _ ("Failed to serialize SOA record with mname `%s' and rname `%s'\n"), | ||
534 | soa_mname, | ||
535 | soa_rname); | ||
536 | return GNUNET_SYSERR; | ||
537 | } | ||
538 | *data_size = off; | ||
539 | *data = GNUNET_malloc (off); | ||
540 | GNUNET_memcpy (*data, soabuf, off); | ||
541 | return GNUNET_OK; | ||
542 | } | ||
543 | |||
544 | case GNUNET_DNSPARSER_TYPE_PTR: { | ||
545 | char ptrbuf[256]; | ||
546 | size_t off; | ||
547 | |||
548 | off = 0; | ||
549 | if (GNUNET_OK != | ||
550 | GNUNET_DNSPARSER_builder_add_name (ptrbuf, sizeof(ptrbuf), &off, s)) | ||
551 | { | ||
552 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
553 | _ ("Failed to serialize PTR record with value `%s'\n"), | ||
554 | s); | ||
555 | return GNUNET_SYSERR; | ||
556 | } | ||
557 | *data_size = off; | ||
558 | *data = GNUNET_malloc (off); | ||
559 | GNUNET_memcpy (*data, ptrbuf, off); | ||
560 | return GNUNET_OK; | ||
561 | } | ||
562 | |||
563 | case GNUNET_DNSPARSER_TYPE_MX: { | ||
564 | struct GNUNET_DNSPARSER_MxRecord mx; | ||
565 | char mxbuf[258]; | ||
566 | char mxhost[253 + 1]; | ||
567 | unsigned int mx_pref; | ||
568 | size_t off; | ||
569 | |||
570 | if (2 != sscanf (s, "%u,%253s", &mx_pref, mxhost)) | ||
571 | { | ||
572 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
573 | _ ("Unable to parse MX record `%s'\n"), | ||
574 | s); | ||
575 | return GNUNET_SYSERR; | ||
576 | } | ||
577 | mx.preference = (uint16_t) mx_pref; | ||
578 | mx.mxhost = mxhost; | ||
579 | off = 0; | ||
580 | |||
581 | if (GNUNET_OK != | ||
582 | GNUNET_DNSPARSER_builder_add_mx (mxbuf, sizeof(mxbuf), &off, &mx)) | ||
583 | { | ||
584 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
585 | _ ("Failed to serialize MX record with hostname `%s'\n"), | ||
586 | mxhost); | ||
587 | return GNUNET_SYSERR; | ||
588 | } | ||
589 | *data_size = off; | ||
590 | *data = GNUNET_malloc (off); | ||
591 | GNUNET_memcpy (*data, mxbuf, off); | ||
592 | return GNUNET_OK; | ||
593 | } | ||
594 | |||
595 | case GNUNET_DNSPARSER_TYPE_SRV: { | ||
596 | struct GNUNET_DNSPARSER_SrvRecord srv; | ||
597 | char srvbuf[270]; | ||
598 | char srvtarget[253 + 1]; | ||
599 | unsigned int priority; | ||
600 | unsigned int weight; | ||
601 | unsigned int port; | ||
602 | size_t off; | ||
603 | |||
604 | if (4 != sscanf (s, "%u %u %u %253s", &priority, &weight, &port, | ||
605 | srvtarget)) | ||
606 | { | ||
607 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
608 | _ ("Unable to parse SRV record `%s'\n"), | ||
609 | s); | ||
610 | return GNUNET_SYSERR; | ||
611 | } | ||
612 | srv.priority = (uint16_t) priority; | ||
613 | srv.weight = (uint16_t) weight; | ||
614 | srv.port = (uint16_t) port; | ||
615 | srv.target = srvtarget; | ||
616 | off = 0; | ||
617 | if (GNUNET_OK != | ||
618 | GNUNET_DNSPARSER_builder_add_srv (srvbuf, sizeof(srvbuf), &off, &srv)) | ||
619 | { | ||
620 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
621 | _ ("Failed to serialize SRV record with target `%s'\n"), | ||
622 | srvtarget); | ||
623 | return GNUNET_SYSERR; | ||
624 | } | ||
625 | *data_size = off; | ||
626 | *data = GNUNET_malloc (off); | ||
627 | GNUNET_memcpy (*data, srvbuf, off); | ||
628 | return GNUNET_OK; | ||
629 | } | ||
630 | |||
631 | case GNUNET_DNSPARSER_TYPE_TXT: | ||
632 | *data = GNUNET_strdup (s); | ||
633 | *data_size = strlen (s); | ||
634 | return GNUNET_OK; | ||
635 | |||
636 | case GNUNET_DNSPARSER_TYPE_AAAA: | ||
637 | if (1 != inet_pton (AF_INET6, s, &value_aaaa)) | ||
638 | { | ||
639 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
640 | _ ("Unable to parse IPv6 address `%s'\n"), | ||
641 | s); | ||
642 | return GNUNET_SYSERR; | ||
643 | } | ||
644 | *data = GNUNET_new (struct in6_addr); | ||
645 | *data_size = sizeof(struct in6_addr); | ||
646 | GNUNET_memcpy (*data, &value_aaaa, sizeof(value_aaaa)); | ||
647 | return GNUNET_OK; | ||
648 | |||
649 | case GNUNET_DNSPARSER_TYPE_TLSA: { | ||
650 | unsigned int usage; | ||
651 | unsigned int selector; | ||
652 | unsigned int matching_type; | ||
653 | size_t slen = strlen (s) + 1; | ||
654 | char hex[slen]; | ||
655 | |||
656 | if (4 != sscanf (s, "%u %u %u %s", &usage, &selector, &matching_type, | ||
657 | hex)) | ||
658 | { | ||
659 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
660 | _ ("Unable to parse TLSA record string `%s'\n"), | ||
661 | s); | ||
662 | *data_size = 0; | ||
663 | return GNUNET_SYSERR; | ||
664 | } | ||
665 | |||
666 | *data_size = sizeof(struct GNUNET_TUN_DnsTlsaRecord) + strlen (hex) / 2; | ||
667 | *data = tlsa = GNUNET_malloc (*data_size); | ||
668 | tlsa->usage = (uint8_t) usage; | ||
669 | tlsa->selector = (uint8_t) selector; | ||
670 | tlsa->matching_type = (uint8_t) matching_type; | ||
671 | if (strlen (hex) / 2 != GNUNET_DNSPARSER_hex_to_bin (hex, &tlsa[1])) | ||
672 | { | ||
673 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
674 | _ ("Unable to parse TLSA record string `%s'\n"), | ||
675 | s); | ||
676 | GNUNET_free (*data); | ||
677 | *data = NULL; | ||
678 | *data_size = 0; | ||
679 | return GNUNET_SYSERR; | ||
680 | } | ||
681 | return GNUNET_OK; | ||
682 | } | ||
683 | |||
684 | case GNUNET_DNSPARSER_TYPE_CAA: { // RFC6844 | ||
685 | struct GNUNET_DNSPARSER_CaaRecord *caa; | ||
686 | unsigned int flags; | ||
687 | char tag[15]; // Max tag length 15 | ||
688 | char value[strlen (s) + 1]; // Should be more than enough | ||
689 | |||
690 | if (3 != sscanf (s, "%u %s %[^\n]", &flags, tag, value)) | ||
691 | { | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
693 | _ ("Unable to parse CAA record string `%s'\n"), | ||
694 | s); | ||
695 | *data_size = 0; | ||
696 | return GNUNET_SYSERR; | ||
697 | } | ||
698 | *data_size = sizeof(struct GNUNET_DNSPARSER_CaaRecord) + strlen (tag) | ||
699 | + strlen (value); | ||
700 | *data = caa = GNUNET_malloc (*data_size); | ||
701 | caa->flags = flags; | ||
702 | memcpy (&caa[1], tag, strlen (tag)); | ||
703 | caa->tag_len = strlen (tag); | ||
704 | memcpy ((char *) &caa[1] + caa->tag_len, value, strlen (value)); | ||
705 | return GNUNET_OK; | ||
706 | } | ||
707 | |||
708 | default: | ||
709 | return GNUNET_SYSERR; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
715 | * Mapping of record type numbers to human-readable | ||
716 | * record type names. | ||
717 | */ | ||
718 | static struct | ||
719 | { | ||
720 | const char *name; | ||
721 | uint32_t number; | ||
722 | } name_map[] = { { "A", GNUNET_DNSPARSER_TYPE_A }, | ||
723 | { "NS", GNUNET_DNSPARSER_TYPE_NS }, | ||
724 | { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME }, | ||
725 | { "SOA", GNUNET_DNSPARSER_TYPE_SOA }, | ||
726 | { "PTR", GNUNET_DNSPARSER_TYPE_PTR }, | ||
727 | { "MX", GNUNET_DNSPARSER_TYPE_MX }, | ||
728 | { "TXT", GNUNET_DNSPARSER_TYPE_TXT }, | ||
729 | { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA }, | ||
730 | { "SRV", GNUNET_DNSPARSER_TYPE_SRV }, | ||
731 | { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA }, | ||
732 | { "CERT", GNUNET_DNSPARSER_TYPE_CERT }, | ||
733 | { "CAA", GNUNET_DNSPARSER_TYPE_CAA }, | ||
734 | { NULL, UINT32_MAX } }; | ||
735 | |||
736 | |||
737 | /** | ||
738 | * Convert a type name (e.g. "AAAA") to the corresponding number. | ||
739 | * | ||
740 | * @param cls closure, unused | ||
741 | * @param dns_typename name to convert | ||
742 | * @return corresponding number, UINT32_MAX on error | ||
743 | */ | ||
744 | static uint32_t | ||
745 | dns_typename_to_number (void *cls, const char *dns_typename) | ||
746 | { | ||
747 | unsigned int i; | ||
748 | |||
749 | i = 0; | ||
750 | while ((NULL != name_map[i].name) && | ||
751 | (0 != strcasecmp (dns_typename, name_map[i].name))) | ||
752 | i++; | ||
753 | return name_map[i].number; | ||
754 | } | ||
755 | |||
756 | |||
757 | /** | ||
758 | * Convert a type number to the corresponding type string (e.g. 1 to "A") | ||
759 | * | ||
760 | * @param cls closure, unused | ||
761 | * @param type number of a type to convert | ||
762 | * @return corresponding typestring, NULL on error | ||
763 | */ | ||
764 | static const char * | ||
765 | dns_number_to_typename (void *cls, uint32_t type) | ||
766 | { | ||
767 | unsigned int i; | ||
768 | |||
769 | i = 0; | ||
770 | while ((NULL != name_map[i].name) && (type != name_map[i].number)) | ||
771 | i++; | ||
772 | return name_map[i].name; | ||
773 | } | ||
774 | |||
775 | |||
776 | /** | ||
777 | * Entry point for the plugin. | ||
778 | * | ||
779 | * @param cls NULL | ||
780 | * @return the exported block API | ||
781 | */ | ||
782 | void * | ||
783 | libgnunet_plugin_gnsrecord_dns_init (void *cls) | ||
784 | { | ||
785 | struct GNUNET_GNSRECORD_PluginFunctions *api; | ||
786 | |||
787 | api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions); | ||
788 | api->value_to_string = &dns_value_to_string; | ||
789 | api->string_to_value = &dns_string_to_value; | ||
790 | api->typename_to_number = &dns_typename_to_number; | ||
791 | api->number_to_typename = &dns_number_to_typename; | ||
792 | return api; | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Exit point from the plugin. | ||
798 | * | ||
799 | * @param cls the return value from #libgnunet_plugin_block_test_init | ||
800 | * @return NULL | ||
801 | */ | ||
802 | void * | ||
803 | libgnunet_plugin_gnsrecord_dns_done (void *cls) | ||
804 | { | ||
805 | struct GNUNET_GNSRECORD_PluginFunctions *api = cls; | ||
806 | |||
807 | GNUNET_free (api); | ||
808 | return NULL; | ||
809 | } | ||
810 | |||
811 | |||
812 | /* end of plugin_gnsrecord_dns.c */ | ||