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