]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/resolve/resolved-dns-rr.c
basic: util - add base32hexmem() function similar to hexmem()
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
... / ...
CommitLineData
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2014 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <math.h>
23
24#include "strv.h"
25
26#include "dns-domain.h"
27#include "resolved-dns-rr.h"
28#include "resolved-dns-packet.h"
29#include "dns-type.h"
30
31DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
32 DnsResourceKey *k;
33 size_t l;
34
35 assert(name);
36
37 l = strlen(name);
38 k = malloc0(sizeof(DnsResourceKey) + l + 1);
39 if (!k)
40 return NULL;
41
42 k->n_ref = 1;
43 k->class = class;
44 k->type = type;
45
46 strcpy((char*) k + sizeof(DnsResourceKey), name);
47
48 return k;
49}
50
51DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
52 DnsResourceKey *k;
53
54 assert(name);
55
56 k = new0(DnsResourceKey, 1);
57 if (!k)
58 return NULL;
59
60 k->n_ref = 1;
61 k->class = class;
62 k->type = type;
63 k->_name = name;
64
65 return k;
66}
67
68DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
69
70 if (!k)
71 return NULL;
72
73 assert(k->n_ref > 0);
74 k->n_ref++;
75
76 return k;
77}
78
79DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
80 if (!k)
81 return NULL;
82
83 assert(k->n_ref > 0);
84
85 if (k->n_ref == 1) {
86 free(k->_name);
87 free(k);
88 } else
89 k->n_ref--;
90
91 return NULL;
92}
93
94int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
95 int r;
96
97 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
98 if (r <= 0)
99 return r;
100
101 if (a->class != b->class)
102 return 0;
103
104 if (a->type != b->type)
105 return 0;
106
107 return 1;
108}
109
110int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr) {
111 assert(key);
112 assert(rr);
113
114 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
115 return 0;
116
117 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
118 return 0;
119
120 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
121}
122
123int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr) {
124 assert(key);
125 assert(rr);
126
127 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
128 return 0;
129
130 if (rr->key->type != DNS_TYPE_CNAME)
131 return 0;
132
133 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
134}
135
136static unsigned long dns_resource_key_hash_func(const void *i, const uint8_t hash_key[HASH_KEY_SIZE]) {
137 const DnsResourceKey *k = i;
138 unsigned long ul;
139
140 ul = dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), hash_key);
141 ul = ul * hash_key[0] + ul + k->class;
142 ul = ul * hash_key[1] + ul + k->type;
143
144 return ul;
145}
146
147static int dns_resource_key_compare_func(const void *a, const void *b) {
148 const DnsResourceKey *x = a, *y = b;
149 int ret;
150
151 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
152 if (ret != 0)
153 return ret;
154
155 if (x->type < y->type)
156 return -1;
157 if (x->type > y->type)
158 return 1;
159
160 if (x->class < y->class)
161 return -1;
162 if (x->class > y->class)
163 return 1;
164
165 return 0;
166}
167
168const struct hash_ops dns_resource_key_hash_ops = {
169 .hash = dns_resource_key_hash_func,
170 .compare = dns_resource_key_compare_func
171};
172
173int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
174 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
175 const char *c, *t;
176 char *s;
177
178 c = dns_class_to_string(key->class);
179 if (!c) {
180 sprintf(cbuf, "CLASS%u", key->class);
181 c = cbuf;
182 }
183
184 t = dns_type_to_string(key->type);
185 if (!t){
186 sprintf(tbuf, "TYPE%u", key->type);
187 t = tbuf;
188 }
189
190 if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0)
191 return -ENOMEM;
192
193 *ret = s;
194 return 0;
195}
196
197DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
198 DnsResourceRecord *rr;
199
200 rr = new0(DnsResourceRecord, 1);
201 if (!rr)
202 return NULL;
203
204 rr->n_ref = 1;
205 rr->key = dns_resource_key_ref(key);
206
207 return rr;
208}
209
210DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
211 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
212
213 key = dns_resource_key_new(class, type, name);
214 if (!key)
215 return NULL;
216
217 return dns_resource_record_new(key);
218}
219
220DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
221 if (!rr)
222 return NULL;
223
224 assert(rr->n_ref > 0);
225 rr->n_ref++;
226
227 return rr;
228}
229
230DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
231 if (!rr)
232 return NULL;
233
234 assert(rr->n_ref > 0);
235
236 if (rr->n_ref > 1) {
237 rr->n_ref--;
238 return NULL;
239 }
240
241 if (rr->key) {
242 switch(rr->key->type) {
243
244 case DNS_TYPE_SRV:
245 free(rr->srv.name);
246 break;
247
248 case DNS_TYPE_PTR:
249 case DNS_TYPE_NS:
250 case DNS_TYPE_CNAME:
251 case DNS_TYPE_DNAME:
252 free(rr->ptr.name);
253 break;
254
255 case DNS_TYPE_HINFO:
256 free(rr->hinfo.cpu);
257 free(rr->hinfo.os);
258 break;
259
260 case DNS_TYPE_TXT:
261 case DNS_TYPE_SPF:
262 strv_free(rr->txt.strings);
263 break;
264
265 case DNS_TYPE_SOA:
266 free(rr->soa.mname);
267 free(rr->soa.rname);
268 break;
269
270 case DNS_TYPE_MX:
271 free(rr->mx.exchange);
272 break;
273
274 case DNS_TYPE_DS:
275 free(rr->ds.digest);
276 break;
277
278 case DNS_TYPE_SSHFP:
279 free(rr->sshfp.key);
280 break;
281
282 case DNS_TYPE_DNSKEY:
283 free(rr->dnskey.key);
284 break;
285
286 case DNS_TYPE_RRSIG:
287 free(rr->rrsig.signer);
288 free(rr->rrsig.signature);
289 break;
290
291 case DNS_TYPE_NSEC:
292 free(rr->nsec.next_domain_name);
293 bitmap_free(rr->nsec.types);
294 break;
295
296 case DNS_TYPE_LOC:
297 case DNS_TYPE_A:
298 case DNS_TYPE_AAAA:
299 break;
300
301 default:
302 free(rr->generic.data);
303 }
304
305 dns_resource_key_unref(rr->key);
306 }
307
308 free(rr);
309
310 return NULL;
311}
312
313int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
314 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
315 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
316 _cleanup_free_ char *ptr = NULL;
317 int r;
318
319 assert(ret);
320 assert(address);
321 assert(hostname);
322
323 r = dns_name_reverse(family, address, &ptr);
324 if (r < 0)
325 return r;
326
327 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
328 if (!key)
329 return -ENOMEM;
330
331 ptr = NULL;
332
333 rr = dns_resource_record_new(key);
334 if (!rr)
335 return -ENOMEM;
336
337 rr->ptr.name = strdup(hostname);
338 if (!rr->ptr.name)
339 return -ENOMEM;
340
341 *ret = rr;
342 rr = NULL;
343
344 return 0;
345}
346
347int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
348 int r;
349
350 assert(a);
351 assert(b);
352
353 r = dns_resource_key_equal(a->key, b->key);
354 if (r <= 0)
355 return r;
356
357 if (a->unparseable != b->unparseable)
358 return 0;
359
360 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
361
362 case DNS_TYPE_SRV:
363 r = dns_name_equal(a->srv.name, b->srv.name);
364 if (r <= 0)
365 return r;
366
367 return a->srv.priority == b->srv.priority &&
368 a->srv.weight == b->srv.weight &&
369 a->srv.port == b->srv.port;
370
371 case DNS_TYPE_PTR:
372 case DNS_TYPE_NS:
373 case DNS_TYPE_CNAME:
374 case DNS_TYPE_DNAME:
375 return dns_name_equal(a->ptr.name, b->ptr.name);
376
377 case DNS_TYPE_HINFO:
378 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
379 strcaseeq(a->hinfo.os, b->hinfo.os);
380
381 case DNS_TYPE_SPF: /* exactly the same as TXT */
382 case DNS_TYPE_TXT:
383 return strv_equal(a->txt.strings, b->txt.strings);
384
385 case DNS_TYPE_A:
386 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
387
388 case DNS_TYPE_AAAA:
389 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
390
391 case DNS_TYPE_SOA:
392 r = dns_name_equal(a->soa.mname, b->soa.mname);
393 if (r <= 0)
394 return r;
395 r = dns_name_equal(a->soa.rname, b->soa.rname);
396 if (r <= 0)
397 return r;
398
399 return a->soa.serial == b->soa.serial &&
400 a->soa.refresh == b->soa.refresh &&
401 a->soa.retry == b->soa.retry &&
402 a->soa.expire == b->soa.expire &&
403 a->soa.minimum == b->soa.minimum;
404
405 case DNS_TYPE_MX:
406 if (a->mx.priority != b->mx.priority)
407 return 0;
408
409 return dns_name_equal(a->mx.exchange, b->mx.exchange);
410
411 case DNS_TYPE_LOC:
412 assert(a->loc.version == b->loc.version);
413
414 return a->loc.size == b->loc.size &&
415 a->loc.horiz_pre == b->loc.horiz_pre &&
416 a->loc.vert_pre == b->loc.vert_pre &&
417 a->loc.latitude == b->loc.latitude &&
418 a->loc.longitude == b->loc.longitude &&
419 a->loc.altitude == b->loc.altitude;
420
421 case DNS_TYPE_DS:
422 return a->ds.key_tag == b->ds.key_tag &&
423 a->ds.algorithm == b->ds.algorithm &&
424 a->ds.digest_type == b->ds.digest_type &&
425 a->ds.digest_size == b->ds.digest_size &&
426 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
427
428 case DNS_TYPE_SSHFP:
429 return a->sshfp.algorithm == b->sshfp.algorithm &&
430 a->sshfp.fptype == b->sshfp.fptype &&
431 a->sshfp.key_size == b->sshfp.key_size &&
432 memcmp(a->sshfp.key, b->sshfp.key, a->sshfp.key_size) == 0;
433
434 case DNS_TYPE_DNSKEY:
435 return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag &&
436 a->dnskey.sep_flag == b->dnskey.sep_flag &&
437 a->dnskey.algorithm == b->dnskey.algorithm &&
438 a->dnskey.key_size == b->dnskey.key_size &&
439 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
440
441 case DNS_TYPE_RRSIG:
442 /* do the fast comparisons first */
443 if (a->rrsig.type_covered != b->rrsig.type_covered ||
444 a->rrsig.algorithm != b->rrsig.algorithm ||
445 a->rrsig.labels != b->rrsig.labels ||
446 a->rrsig.original_ttl != b->rrsig.original_ttl ||
447 a->rrsig.expiration != b->rrsig.expiration ||
448 a->rrsig.inception != b->rrsig.inception ||
449 a->rrsig.key_tag != b->rrsig.key_tag ||
450 a->rrsig.signature_size != b->rrsig.signature_size ||
451 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
452 return false;
453
454 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
455
456 case DNS_TYPE_NSEC:
457 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
458 bitmap_equal(a->nsec.types, b->nsec.types);
459
460 default:
461 return a->generic.size == b->generic.size &&
462 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
463 }
464}
465
466static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
467 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
468 char *s;
469 char NS = latitude >= 1U<<31 ? 'N' : 'S';
470 char EW = longitude >= 1U<<31 ? 'E' : 'W';
471
472 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
473 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
474 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
475 double siz = (size >> 4) * exp10((double) (size & 0xF));
476 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
477 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
478
479 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
480 (lat / 60000 / 60),
481 (lat / 60000) % 60,
482 (lat % 60000) / 1000.,
483 NS,
484 (lon / 60000 / 60),
485 (lon / 60000) % 60,
486 (lon % 60000) / 1000.,
487 EW,
488 alt / 100.,
489 siz / 100.,
490 hor / 100.,
491 ver / 100.) < 0)
492 return NULL;
493
494 return s;
495}
496
497static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
498 struct tm tm;
499
500 assert(buf);
501 assert(l > strlen("YYYYMMDDHHmmSS"));
502
503 if (!gmtime_r(&sec, &tm))
504 return -EINVAL;
505
506 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
507 return -EINVAL;
508
509 return 0;
510}
511
512static char *format_types(Bitmap *types) {
513 _cleanup_strv_free_ char **strv = NULL;
514 _cleanup_free_ char *str = NULL;
515 unsigned type;
516 int r;
517
518 BITMAP_FOREACH(type, types) {
519 if (dns_type_to_string(type)) {
520 r = strv_extend(&strv, strdup(dns_type_to_string(type)));
521 if (r < 0)
522 return NULL;
523 } else {
524 char *t;
525
526 r = asprintf(&t, "TYPE%u", type);
527 if (r < 0)
528 return NULL;
529
530 r = strv_extend(&strv, t);
531 if (r < 0)
532 return NULL;
533 }
534 }
535
536 str = strv_join(strv, " ");
537 if (!str)
538 return NULL;
539
540 return strjoin("( ", str, " )", NULL);
541}
542
543int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {
544 _cleanup_free_ char *k = NULL, *t = NULL;
545 char *s;
546 int r;
547
548 assert(rr);
549
550 r = dns_resource_key_to_string(rr->key, &k);
551 if (r < 0)
552 return r;
553
554 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
555
556 case DNS_TYPE_SRV:
557 r = asprintf(&s, "%s %u %u %u %s",
558 k,
559 rr->srv.priority,
560 rr->srv.weight,
561 rr->srv.port,
562 strna(rr->srv.name));
563 if (r < 0)
564 return -ENOMEM;
565 break;
566
567 case DNS_TYPE_PTR:
568 case DNS_TYPE_NS:
569 case DNS_TYPE_CNAME:
570 case DNS_TYPE_DNAME:
571 s = strjoin(k, " ", rr->ptr.name, NULL);
572 if (!s)
573 return -ENOMEM;
574
575 break;
576
577 case DNS_TYPE_HINFO:
578 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
579 if (!s)
580 return -ENOMEM;
581 break;
582
583 case DNS_TYPE_SPF: /* exactly the same as TXT */
584 case DNS_TYPE_TXT:
585 t = strv_join_quoted(rr->txt.strings);
586 if (!t)
587 return -ENOMEM;
588
589 s = strjoin(k, " ", t, NULL);
590 if (!s)
591 return -ENOMEM;
592
593 break;
594
595 case DNS_TYPE_A: {
596 _cleanup_free_ char *x = NULL;
597
598 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
599 if (r < 0)
600 return r;
601
602 s = strjoin(k, " ", x, NULL);
603 if (!s)
604 return -ENOMEM;
605 break;
606 }
607
608 case DNS_TYPE_AAAA:
609 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
610 if (r < 0)
611 return r;
612
613 s = strjoin(k, " ", t, NULL);
614 if (!s)
615 return -ENOMEM;
616 break;
617
618 case DNS_TYPE_SOA:
619 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
620 k,
621 strna(rr->soa.mname),
622 strna(rr->soa.rname),
623 rr->soa.serial,
624 rr->soa.refresh,
625 rr->soa.retry,
626 rr->soa.expire,
627 rr->soa.minimum);
628 if (r < 0)
629 return -ENOMEM;
630 break;
631
632 case DNS_TYPE_MX:
633 r = asprintf(&s, "%s %u %s",
634 k,
635 rr->mx.priority,
636 rr->mx.exchange);
637 if (r < 0)
638 return -ENOMEM;
639 break;
640
641 case DNS_TYPE_LOC:
642 assert(rr->loc.version == 0);
643
644 t = format_location(rr->loc.latitude,
645 rr->loc.longitude,
646 rr->loc.altitude,
647 rr->loc.size,
648 rr->loc.horiz_pre,
649 rr->loc.vert_pre);
650 if (!t)
651 return -ENOMEM;
652
653 s = strjoin(k, " ", t, NULL);
654 if (!s)
655 return -ENOMEM;
656 break;
657
658 case DNS_TYPE_DS:
659 t = hexmem(rr->ds.digest, rr->ds.digest_size);
660 if (!t)
661 return -ENOMEM;
662
663 r = asprintf(&s, "%s %u %u %u %s",
664 k,
665 rr->ds.key_tag,
666 rr->ds.algorithm,
667 rr->ds.digest_type,
668 t);
669 if (r < 0)
670 return -ENOMEM;
671 break;
672
673 case DNS_TYPE_SSHFP:
674 t = hexmem(rr->sshfp.key, rr->sshfp.key_size);
675 if (!t)
676 return -ENOMEM;
677
678 r = asprintf(&s, "%s %u %u %s",
679 k,
680 rr->sshfp.algorithm,
681 rr->sshfp.fptype,
682 t);
683 if (r < 0)
684 return -ENOMEM;
685 break;
686
687 case DNS_TYPE_DNSKEY: {
688 const char *alg;
689
690 alg = dnssec_algorithm_to_string(rr->dnskey.algorithm);
691
692 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
693 if (!t)
694 return -ENOMEM;
695
696 r = asprintf(&s, "%s %u 3 %.*s%.*u %s",
697 k,
698 dnskey_to_flags(rr),
699 alg ? -1 : 0, alg,
700 alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,
701 t);
702 if (r < 0)
703 return -ENOMEM;
704 break;
705 }
706
707 case DNS_TYPE_RRSIG: {
708 const char *type, *alg;
709 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
710
711 type = dns_type_to_string(rr->rrsig.type_covered);
712 alg = dnssec_algorithm_to_string(rr->rrsig.algorithm);
713
714 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
715 if (!t)
716 return -ENOMEM;
717
718 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
719 if (r < 0)
720 return r;
721
722 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
723 if (r < 0)
724 return r;
725
726 /* TYPE?? follows
727 * http://tools.ietf.org/html/rfc3597#section-5 */
728
729 r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s",
730 k,
731 type ?: "TYPE",
732 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
733 alg ? -1 : 0, alg,
734 alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm,
735 rr->rrsig.labels,
736 rr->rrsig.original_ttl,
737 expiration,
738 inception,
739 rr->rrsig.key_tag,
740 rr->rrsig.signer,
741 t);
742 if (r < 0)
743 return -ENOMEM;
744 break;
745 }
746
747 case DNS_TYPE_NSEC:
748 t = format_types(rr->nsec.types);
749 if (!t)
750 return -ENOMEM;
751
752 r = asprintf(&s, "%s %s %s",
753 k,
754 rr->nsec.next_domain_name,
755 t);
756 if (r < 0)
757 return -ENOMEM;
758 break;
759
760 default:
761 t = hexmem(rr->generic.data, rr->generic.size);
762 if (!t)
763 return -ENOMEM;
764
765 r = asprintf(&s, "%s \\# %"PRIu8" %s", k, rr->generic.size, t);
766 if (r < 0)
767 return -ENOMEM;
768 break;
769 }
770
771 *ret = s;
772 return 0;
773}
774
775const char *dns_class_to_string(uint16_t class) {
776
777 switch (class) {
778
779 case DNS_CLASS_IN:
780 return "IN";
781
782 case DNS_CLASS_ANY:
783 return "ANY";
784 }
785
786 return NULL;
787}
788
789int dns_class_from_string(const char *s, uint16_t *class) {
790 assert(s);
791 assert(class);
792
793 if (strcaseeq(s, "IN"))
794 *class = DNS_CLASS_IN;
795 else if (strcaseeq(s, "ANY"))
796 *class = DNS_TYPE_ANY;
797 else
798 return -EINVAL;
799
800 return 0;
801}