aboutsummaryrefslogtreecommitdiff
path: root/src/gnsrecord/plugin_gnsrecord_dns.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2013-10-16 11:58:42 +0000
committerChristian Grothoff <christian@grothoff.org>2013-10-16 11:58:42 +0000
commit7848f548f552b3576dc029e276bbe4aeb4e5392c (patch)
tree87f5122378bf7d0701355da0ead63be0b04bdac5 /src/gnsrecord/plugin_gnsrecord_dns.c
parent5b96183f228a540ea7b90c43955f019f86da8340 (diff)
downloadgnunet-7848f548f552b3576dc029e276bbe4aeb4e5392c.tar.gz
gnunet-7848f548f552b3576dc029e276bbe4aeb4e5392c.zip
-define gnsrecord plugin for DNS
Diffstat (limited to 'src/gnsrecord/plugin_gnsrecord_dns.c')
-rw-r--r--src/gnsrecord/plugin_gnsrecord_dns.c553
1 files changed, 553 insertions, 0 deletions
diff --git a/src/gnsrecord/plugin_gnsrecord_dns.c b/src/gnsrecord/plugin_gnsrecord_dns.c
new file mode 100644
index 000000000..e5475118d
--- /dev/null
+++ b/src/gnsrecord/plugin_gnsrecord_dns.c
@@ -0,0 +1,553 @@
1/*
2 This file is part of GNUnet
3 (C) 2013 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
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
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_dnsparser_lib.h"
30#include "gnunet_gnsrecord_plugin.h"
31
32
33/**
34 * Convert the 'value' of a record to a string.
35 *
36 * @param cls closure, unused
37 * @param type type of the record
38 * @param data value in binary encoding
39 * @param data_size number of bytes in @a data
40 * @return NULL on error, otherwise human-readable representation of the value
41 */
42static char *
43dns_value_to_string (void *cls,
44 uint32_t type,
45 const void *data,
46 size_t data_size)
47{
48 const char *cdata;
49 char* result;
50 char tmp[INET6_ADDRSTRLEN];
51
52 switch (type)
53 {
54 case GNUNET_DNSPARSER_TYPE_A:
55 if (data_size != sizeof (struct in_addr))
56 return NULL;
57 if (NULL == inet_ntop (AF_INET, data, tmp, sizeof (tmp)))
58 return NULL;
59 return GNUNET_strdup (tmp);
60 case GNUNET_DNSPARSER_TYPE_NS:
61 {
62 char *ns;
63 size_t off;
64
65 off = 0;
66 ns = GNUNET_DNSPARSER_parse_name (data,
67 data_size,
68 &off);
69 if ( (NULL == ns) ||
70 (off != data_size) )
71 {
72 GNUNET_break_op (0);
73 return NULL;
74 }
75 return ns;
76 }
77 case GNUNET_DNSPARSER_TYPE_CNAME:
78 {
79 char *cname;
80 size_t off;
81
82 off = 0;
83 cname = GNUNET_DNSPARSER_parse_name (data,
84 data_size,
85 &off);
86 if ( (NULL == cname) ||
87 (off != data_size) )
88 {
89 GNUNET_break_op (0);
90 GNUNET_free_non_null (cname);
91 return NULL;
92 }
93 return cname;
94 }
95 case GNUNET_DNSPARSER_TYPE_SOA:
96 {
97 struct GNUNET_DNSPARSER_SoaRecord *soa;
98 size_t off;
99
100 off = 0;
101 soa = GNUNET_DNSPARSER_parse_soa (data,
102 data_size,
103 &off);
104 if ( (NULL == soa) ||
105 (off != data_size) )
106 {
107 GNUNET_break_op (0);
108 return NULL;
109 }
110 GNUNET_asprintf (&result,
111 "rname=%s mname=%s %lu,%lu,%lu,%lu,%lu",
112 soa->rname,
113 soa->mname,
114 soa->serial,
115 soa->refresh,
116 soa->retry,
117 soa->expire,
118 soa->minimum_ttl);
119 GNUNET_DNSPARSER_free_soa (soa);
120 return result;
121 }
122 case GNUNET_DNSPARSER_TYPE_PTR:
123 {
124 char *ptr;
125 size_t off;
126
127 off = 0;
128 ptr = GNUNET_DNSPARSER_parse_name (data,
129 data_size,
130 &off);
131 if ( (NULL == ptr) ||
132 (off != data_size) )
133 {
134 GNUNET_break_op (0);
135 GNUNET_free_non_null (ptr);
136 return NULL;
137 }
138 return ptr;
139 }
140 case GNUNET_DNSPARSER_TYPE_MX:
141 {
142 struct GNUNET_DNSPARSER_MxRecord *mx;
143 size_t off;
144
145 off = 0;
146 mx = GNUNET_DNSPARSER_parse_mx (data,
147 data_size,
148 &off);
149 if ( (NULL == mx) ||
150 (off != data_size) )
151 {
152 GNUNET_break_op (0);
153 GNUNET_free_non_null (mx);
154 return NULL;
155 }
156 GNUNET_asprintf (&result,
157 "%hu,%s",
158 mx->preference,
159 mx->mxhost);
160 GNUNET_DNSPARSER_free_mx (mx);
161 return result;
162 }
163 case GNUNET_DNSPARSER_TYPE_TXT:
164 return GNUNET_strndup (data, data_size);
165 case GNUNET_DNSPARSER_TYPE_AAAA:
166 if (data_size != sizeof (struct in6_addr))
167 return NULL;
168 if (NULL == inet_ntop (AF_INET6, data, tmp, sizeof (tmp)))
169 return NULL;
170 return GNUNET_strdup (tmp);
171 case GNUNET_DNSPARSER_TYPE_SRV:
172 {
173 struct GNUNET_DNSPARSER_SrvRecord *srv;
174 size_t off;
175
176 off = 0;
177 srv = GNUNET_DNSPARSER_parse_srv ("+", /* FIXME: is this OK? */
178 data,
179 data_size,
180 &off);
181 if ( (NULL == srv) ||
182 (off != data_size) )
183 {
184 GNUNET_break_op (0);
185 return NULL;
186 }
187 GNUNET_asprintf (&result,
188 "%d %d %d _%s._%s.%s",
189 srv->priority,
190 srv->weight,
191 srv->port,
192 srv->service,
193 srv->proto,
194 srv->domain_name);
195 GNUNET_DNSPARSER_free_srv (srv);
196 return result;
197 }
198 case GNUNET_DNSPARSER_TYPE_TLSA:
199 {
200 const struct GNUNET_TUN_DnsTlsaRecord *tlsa;
201 char* tlsa_str;
202
203 cdata = data;
204 if ( (data_size <= sizeof (struct GNUNET_TUN_DnsTlsaRecord)) ||
205 ('\0' != cdata[data_size - 1]) )
206 return NULL; /* malformed */
207 tlsa = data;
208 if (0 == GNUNET_asprintf (&tlsa_str,
209 "%c %c %c %s",
210 tlsa->usage,
211 tlsa->selector,
212 tlsa->matching_type,
213 (const char *) &tlsa[1]))
214 {
215 GNUNET_free (tlsa_str);
216 return NULL;
217 }
218 return tlsa_str;
219 }
220 default:
221 return NULL;
222 }
223}
224
225
226/**
227 * Convert human-readable version of a 'value' of a record to the binary
228 * representation.
229 *
230 * @param cls closure, unused
231 * @param type type of the record
232 * @param s human-readable string
233 * @param data set to value in binary encoding (will be allocated)
234 * @param data_size set to number of bytes in @a data
235 * @return #GNUNET_OK on success
236 */
237static int
238dns_string_to_value (void *cls,
239 uint32_t type,
240 const char *s,
241 void **data,
242 size_t *data_size)
243{
244 struct in_addr value_a;
245 struct in6_addr value_aaaa;
246 struct GNUNET_TUN_DnsTlsaRecord *tlsa;
247
248 if (NULL == s)
249 return GNUNET_SYSERR;
250 switch (type)
251 {
252 case GNUNET_DNSPARSER_TYPE_A:
253 if (1 != inet_pton (AF_INET, s, &value_a))
254 {
255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
256 _("Unable to parse IPv4 address `%s'\n"),
257 s);
258 return GNUNET_SYSERR;
259 }
260 *data = GNUNET_malloc (sizeof (struct in_addr));
261 memcpy (*data, &value_a, sizeof (value_a));
262 *data_size = sizeof (value_a);
263 return GNUNET_OK;
264 case GNUNET_DNSPARSER_TYPE_NS:
265 {
266 char nsbuf[256];
267 size_t off;
268
269 off = 0;
270 if (GNUNET_OK !=
271 GNUNET_DNSPARSER_builder_add_name (nsbuf,
272 sizeof (nsbuf),
273 &off,
274 s))
275 {
276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
277 _("Failed to serialize NS record with value `%s'\n"),
278 s);
279 return GNUNET_SYSERR;
280 }
281 *data_size = off;
282 *data = GNUNET_malloc (off);
283 memcpy (*data, nsbuf, off);
284 return GNUNET_OK;
285 }
286 case GNUNET_DNSPARSER_TYPE_CNAME:
287 {
288 char cnamebuf[256];
289 size_t off;
290
291 off = 0;
292 if (GNUNET_OK !=
293 GNUNET_DNSPARSER_builder_add_name (cnamebuf,
294 sizeof (cnamebuf),
295 &off,
296 s))
297 {
298 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
299 _("Failed to serialize CNAME record with value `%s'\n"),
300 s);
301 return GNUNET_SYSERR;
302 }
303 *data_size = off;
304 *data = GNUNET_malloc (off);
305 memcpy (*data, cnamebuf, off);
306 return GNUNET_OK;
307 }
308 case GNUNET_DNSPARSER_TYPE_SOA:
309 {
310 struct GNUNET_DNSPARSER_SoaRecord soa;
311 char soabuf[540];
312 char soa_rname[253 + 1];
313 char soa_mname[253 + 1];
314 unsigned int soa_serial;
315 unsigned int soa_refresh;
316 unsigned int soa_retry;
317 unsigned int soa_expire;
318 unsigned int soa_min;
319 size_t off;
320
321 if (7 != SSCANF (s,
322 "rname=%253s mname=%253s %u,%u,%u,%u,%u",
323 soa_rname, soa_mname,
324 &soa_serial, &soa_refresh, &soa_retry, &soa_expire, &soa_min))
325 {
326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
327 _("Unable to parse SOA record `%s'\n"),
328 s);
329 return GNUNET_SYSERR;
330 }
331 soa.mname = soa_mname;
332 soa.rname = soa_rname;
333 soa.serial = (uint32_t) soa_serial;
334 soa.refresh =(uint32_t) soa_refresh;
335 soa.retry = (uint32_t) soa_retry;
336 soa.expire = (uint32_t) soa_expire;
337 soa.minimum_ttl = (uint32_t) soa_min;
338 off = 0;
339 if (GNUNET_OK !=
340 GNUNET_DNSPARSER_builder_add_soa (soabuf,
341 sizeof (soabuf),
342 &off,
343 &soa))
344 {
345 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
346 _("Failed to serialize SOA record with mname `%s' and rname `%s'\n"),
347 soa_mname,
348 soa_rname);
349 return GNUNET_SYSERR;
350 }
351 *data_size = off;
352 *data = GNUNET_malloc (off);
353 memcpy (*data, soabuf, off);
354 return GNUNET_OK;
355 }
356 case GNUNET_DNSPARSER_TYPE_PTR:
357 {
358 char ptrbuf[256];
359 size_t off;
360
361 off = 0;
362 if (GNUNET_OK !=
363 GNUNET_DNSPARSER_builder_add_name (ptrbuf,
364 sizeof (ptrbuf),
365 &off,
366 s))
367 {
368 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
369 _("Failed to serialize PTR record with value `%s'\n"),
370 s);
371 return GNUNET_SYSERR;
372 }
373 *data_size = off;
374 *data = GNUNET_malloc (off);
375 memcpy (*data, ptrbuf, off);
376 return GNUNET_OK;
377 }
378 case GNUNET_DNSPARSER_TYPE_MX:
379 {
380 struct GNUNET_DNSPARSER_MxRecord mx;
381 char mxbuf[258];
382 char mxhost[253 + 1];
383 uint16_t mx_pref;
384 size_t off;
385
386 if (2 != SSCANF(s, "%hu,%253s", &mx_pref, mxhost))
387 {
388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
389 _("Unable to parse MX record `%s'\n"),
390 s);
391 return GNUNET_SYSERR;
392 }
393 mx.preference = mx_pref;
394 mx.mxhost = mxhost;
395 off = 0;
396
397 if (GNUNET_OK !=
398 GNUNET_DNSPARSER_builder_add_mx (mxbuf,
399 sizeof (mxbuf),
400 &off,
401 &mx))
402 {
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404 _("Failed to serialize MX record with hostname `%s'\n"),
405 mxhost);
406 return GNUNET_SYSERR;
407 }
408 *data_size = off;
409 *data = GNUNET_malloc (off);
410 memcpy (*data, mxbuf, off);
411 return GNUNET_OK;
412 }
413 case GNUNET_DNSPARSER_TYPE_SRV:
414 GNUNET_break (0); // FIXME: not implemented!
415 return GNUNET_SYSERR;
416 case GNUNET_DNSPARSER_TYPE_TXT:
417 *data = GNUNET_strdup (s);
418 *data_size = strlen (s);
419 return GNUNET_OK;
420 case GNUNET_DNSPARSER_TYPE_AAAA:
421 if (1 != inet_pton (AF_INET6, s, &value_aaaa))
422 {
423 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
424 _("Unable to parse IPv6 address `%s'\n"),
425 s);
426 return GNUNET_SYSERR;
427 }
428 *data = GNUNET_malloc (sizeof (struct in6_addr));
429 *data_size = sizeof (struct in6_addr);
430 memcpy (*data, &value_aaaa, sizeof (value_aaaa));
431 return GNUNET_OK;
432 case GNUNET_DNSPARSER_TYPE_TLSA:
433 *data_size = sizeof (struct GNUNET_TUN_DnsTlsaRecord) + strlen (s) - 6;
434 *data = tlsa = GNUNET_malloc (*data_size);
435 if (4 != SSCANF (s, "%c %c %c %s",
436 &tlsa->usage,
437 &tlsa->selector,
438 &tlsa->matching_type,
439 (char*)&tlsa[1]))
440 {
441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
442 _("Unable to parse TLSA record string `%s'\n"),
443 s);
444 *data_size = 0;
445 GNUNET_free (tlsa);
446 return GNUNET_SYSERR;
447 }
448 return GNUNET_OK;
449 default:
450 return GNUNET_SYSERR;
451 }
452}
453
454
455/**
456 * Mapping of record type numbers to human-readable
457 * record type names.
458 */
459static struct {
460 const char *name;
461 uint32_t number;
462} name_map[] = {
463 { "A", GNUNET_DNSPARSER_TYPE_A },
464 { "NS", GNUNET_DNSPARSER_TYPE_NS },
465 { "CNAME", GNUNET_DNSPARSER_TYPE_CNAME },
466 { "SOA", GNUNET_DNSPARSER_TYPE_SOA },
467 { "PTR", GNUNET_DNSPARSER_TYPE_PTR },
468 { "MX", GNUNET_DNSPARSER_TYPE_MX },
469 { "TXT", GNUNET_DNSPARSER_TYPE_TXT },
470 { "AAAA", GNUNET_DNSPARSER_TYPE_AAAA },
471 { "TLSA", GNUNET_DNSPARSER_TYPE_TLSA },
472 { NULL, UINT32_MAX }
473};
474
475
476/**
477 * Convert a type name (i.e. "AAAA") to the corresponding number.
478 *
479 * @param cls closure, unused
480 * @param dns_typename name to convert
481 * @return corresponding number, UINT32_MAX on error
482 */
483static uint32_t
484dns_typename_to_number (void *cls,
485 const char *dns_typename)
486{
487 unsigned int i;
488
489 i=0;
490 while ( (name_map[i].name != NULL) &&
491 (0 != strcasecmp (dns_typename, name_map[i].name)) )
492 i++;
493 return name_map[i].number;
494}
495
496
497/**
498 * Convert a type number (i.e. 1) to the corresponding type string (i.e. "A")
499 *
500 * @param cls closure, unused
501 * @param type number of a type to convert
502 * @return corresponding typestring, NULL on error
503 */
504static const char *
505dns_number_to_typename (void *cls,
506 uint32_t type)
507{
508 unsigned int i;
509
510 i=0;
511 while ( (name_map[i].name != NULL) &&
512 (type != name_map[i].number) )
513 i++;
514 return name_map[i].name;
515}
516
517
518/**
519 * Entry point for the plugin.
520 *
521 * @param cls NULL
522 * @return the exported block API
523 */
524void *
525libgnunet_plugin_gnsrecord_dns_init (void *cls)
526{
527 struct GNUNET_GNSRECORD_PluginFunctions *api;
528
529 api = GNUNET_new (struct GNUNET_GNSRECORD_PluginFunctions);
530 api->value_to_string = &dns_value_to_string;
531 api->string_to_value = &dns_string_to_value;
532 api->typename_to_number = &dns_typename_to_number;
533 api->number_to_typename = &dns_number_to_typename;
534 return api;
535}
536
537
538/**
539 * Exit point from the plugin.
540 *
541 * @param cls the return value from #libgnunet_plugin_block_test_init
542 * @return NULL
543 */
544void *
545libgnunet_plugin_gnsrecord_dns_done (void *cls)
546{
547 struct GNUNET_GNSRECORD_PluginFunctions *api = cls;
548
549 GNUNET_free (api);
550 return NULL;
551}
552
553/* end of plugin_gnsrecord_dns.c */