]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-dns-rr.c
Merge pull request #2222 from snakeroot/eventsplat
[thirdparty/systemd.git] / src / resolve / resolved-dns-rr.c
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 "alloc-util.h"
25 #include "dns-domain.h"
26 #include "dns-type.h"
27 #include "hexdecoct.h"
28 #include "resolved-dns-packet.h"
29 #include "resolved-dns-rr.h"
30 #include "string-table.h"
31 #include "string-util.h"
32 #include "strv.h"
33
34 DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) {
35 DnsResourceKey *k;
36 size_t l;
37
38 assert(name);
39
40 l = strlen(name);
41 k = malloc0(sizeof(DnsResourceKey) + l + 1);
42 if (!k)
43 return NULL;
44
45 k->n_ref = 1;
46 k->class = class;
47 k->type = type;
48
49 strcpy((char*) k + sizeof(DnsResourceKey), name);
50
51 return k;
52 }
53
54 DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {
55 int r;
56
57 assert(key);
58 assert(cname);
59
60 assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME));
61
62 if (cname->key->type == DNS_TYPE_CNAME)
63 return dns_resource_key_new(key->class, key->type, cname->cname.name);
64 else {
65 DnsResourceKey *k;
66 char *destination = NULL;
67
68 r = dns_name_change_suffix(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname->key), cname->dname.name, &destination);
69 if (r < 0)
70 return NULL;
71 if (r == 0)
72 return dns_resource_key_ref((DnsResourceKey*) key);
73
74 k = dns_resource_key_new_consume(key->class, key->type, destination);
75 if (!k) {
76 free(destination);
77 return NULL;
78 }
79
80 return k;
81 }
82 }
83
84 int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name) {
85 DnsResourceKey *new_key;
86 char *joined;
87 int r;
88
89 assert(ret);
90 assert(key);
91 assert(name);
92
93 if (dns_name_is_root(name)) {
94 *ret = dns_resource_key_ref(key);
95 return 0;
96 }
97
98 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), name, &joined);
99 if (r < 0)
100 return r;
101
102 new_key = dns_resource_key_new_consume(key->class, key->type, joined);
103 if (!new_key) {
104 free(joined);
105 return -ENOMEM;
106 }
107
108 *ret = new_key;
109 return 0;
110 }
111
112 DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name) {
113 DnsResourceKey *k;
114
115 assert(name);
116
117 k = new0(DnsResourceKey, 1);
118 if (!k)
119 return NULL;
120
121 k->n_ref = 1;
122 k->class = class;
123 k->type = type;
124 k->_name = name;
125
126 return k;
127 }
128
129 DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {
130
131 if (!k)
132 return NULL;
133
134 /* Static/const keys created with DNS_RESOURCE_KEY_CONST will
135 * set this to -1, they should not be reffed/unreffed */
136 assert(k->n_ref != (unsigned) -1);
137
138 assert(k->n_ref > 0);
139 k->n_ref++;
140
141 return k;
142 }
143
144 DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {
145 if (!k)
146 return NULL;
147
148 assert(k->n_ref != (unsigned) -1);
149 assert(k->n_ref > 0);
150
151 if (k->n_ref == 1) {
152 free(k->_name);
153 free(k);
154 } else
155 k->n_ref--;
156
157 return NULL;
158 }
159
160 bool dns_resource_key_is_address(const DnsResourceKey *key) {
161 assert(key);
162
163 /* Check if this is an A or AAAA resource key */
164
165 return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA);
166 }
167
168 int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {
169 int r;
170
171 if (a == b)
172 return 1;
173
174 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b));
175 if (r <= 0)
176 return r;
177
178 if (a->class != b->class)
179 return 0;
180
181 if (a->type != b->type)
182 return 0;
183
184 return 1;
185 }
186
187 int dns_resource_key_match_rr(const DnsResourceKey *key, DnsResourceRecord *rr, const char *search_domain) {
188 int r;
189
190 assert(key);
191 assert(rr);
192
193 if (key == rr->key)
194 return 1;
195
196 /* Checks if an rr matches the specified key. If a search
197 * domain is specified, it will also be checked if the key
198 * with the search domain suffixed might match the RR. */
199
200 if (rr->key->class != key->class && key->class != DNS_CLASS_ANY)
201 return 0;
202
203 if (rr->key->type != key->type && key->type != DNS_TYPE_ANY)
204 return 0;
205
206 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(key));
207 if (r != 0)
208 return r;
209
210 if (search_domain) {
211 _cleanup_free_ char *joined = NULL;
212
213 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
214 if (r < 0)
215 return r;
216
217 return dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), joined);
218 }
219
220 return 0;
221 }
222
223 int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) {
224 int r;
225
226 assert(key);
227 assert(cname);
228
229 if (cname->class != key->class && key->class != DNS_CLASS_ANY)
230 return 0;
231
232 if (cname->type == DNS_TYPE_CNAME)
233 r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
234 else if (cname->type == DNS_TYPE_DNAME)
235 r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname));
236 else
237 return 0;
238
239 if (r != 0)
240 return r;
241
242 if (search_domain) {
243 _cleanup_free_ char *joined = NULL;
244
245 r = dns_name_concat(DNS_RESOURCE_KEY_NAME(key), search_domain, &joined);
246 if (r < 0)
247 return r;
248
249 if (cname->type == DNS_TYPE_CNAME)
250 return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname));
251 else if (cname->type == DNS_TYPE_DNAME)
252 return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname));
253 }
254
255 return 0;
256 }
257
258 int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) {
259 assert(soa);
260 assert(key);
261
262 /* Checks whether 'soa' is a SOA record for the specified key. */
263
264 if (soa->class != key->class)
265 return 0;
266
267 if (soa->type != DNS_TYPE_SOA)
268 return 0;
269
270 return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa));
271 }
272
273 static void dns_resource_key_hash_func(const void *i, struct siphash *state) {
274 const DnsResourceKey *k = i;
275
276 assert(k);
277
278 dns_name_hash_func(DNS_RESOURCE_KEY_NAME(k), state);
279 siphash24_compress(&k->class, sizeof(k->class), state);
280 siphash24_compress(&k->type, sizeof(k->type), state);
281 }
282
283 static int dns_resource_key_compare_func(const void *a, const void *b) {
284 const DnsResourceKey *x = a, *y = b;
285 int ret;
286
287 ret = dns_name_compare_func(DNS_RESOURCE_KEY_NAME(x), DNS_RESOURCE_KEY_NAME(y));
288 if (ret != 0)
289 return ret;
290
291 if (x->type < y->type)
292 return -1;
293 if (x->type > y->type)
294 return 1;
295
296 if (x->class < y->class)
297 return -1;
298 if (x->class > y->class)
299 return 1;
300
301 return 0;
302 }
303
304 const struct hash_ops dns_resource_key_hash_ops = {
305 .hash = dns_resource_key_hash_func,
306 .compare = dns_resource_key_compare_func
307 };
308
309 int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) {
310 char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)];
311 const char *c, *t, *n;
312 char *s;
313
314 /* If we cannot convert the CLASS/TYPE into a known string,
315 use the format recommended by RFC 3597, Section 5. */
316
317 c = dns_class_to_string(key->class);
318 if (!c) {
319 sprintf(cbuf, "CLASS%u", key->class);
320 c = cbuf;
321 }
322
323 t = dns_type_to_string(key->type);
324 if (!t){
325 sprintf(tbuf, "TYPE%u", key->type);
326 t = tbuf;
327 }
328
329 n = DNS_RESOURCE_KEY_NAME(key);
330 if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0)
331 return -ENOMEM;
332
333 *ret = s;
334 return 0;
335 }
336
337 bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) {
338 assert(a);
339 assert(b);
340
341 /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do
342 * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come
343 * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same
344 * superficial data. */
345
346 if (!*a)
347 return false;
348 if (!*b)
349 return false;
350
351 /* We refuse merging const keys */
352 if ((*a)->n_ref == (unsigned) -1)
353 return false;
354 if ((*b)->n_ref == (unsigned) -1)
355 return false;
356
357 /* Already the same? */
358 if (*a == *b)
359 return true;
360
361 /* Are they really identical? */
362 if (dns_resource_key_equal(*a, *b) <= 0)
363 return false;
364
365 /* Keep the one which already has more references. */
366 if ((*a)->n_ref > (*b)->n_ref) {
367 dns_resource_key_unref(*b);
368 *b = dns_resource_key_ref(*a);
369 } else {
370 dns_resource_key_unref(*a);
371 *a = dns_resource_key_ref(*b);
372 }
373
374 return true;
375 }
376
377 DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) {
378 DnsResourceRecord *rr;
379
380 rr = new0(DnsResourceRecord, 1);
381 if (!rr)
382 return NULL;
383
384 rr->n_ref = 1;
385 rr->key = dns_resource_key_ref(key);
386 rr->expiry = USEC_INFINITY;
387 rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1;
388
389 return rr;
390 }
391
392 DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name) {
393 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
394
395 key = dns_resource_key_new(class, type, name);
396 if (!key)
397 return NULL;
398
399 return dns_resource_record_new(key);
400 }
401
402 DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr) {
403 if (!rr)
404 return NULL;
405
406 assert(rr->n_ref > 0);
407 rr->n_ref++;
408
409 return rr;
410 }
411
412 DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {
413 if (!rr)
414 return NULL;
415
416 assert(rr->n_ref > 0);
417
418 if (rr->n_ref > 1) {
419 rr->n_ref--;
420 return NULL;
421 }
422
423 if (rr->key) {
424 switch(rr->key->type) {
425
426 case DNS_TYPE_SRV:
427 free(rr->srv.name);
428 break;
429
430 case DNS_TYPE_PTR:
431 case DNS_TYPE_NS:
432 case DNS_TYPE_CNAME:
433 case DNS_TYPE_DNAME:
434 free(rr->ptr.name);
435 break;
436
437 case DNS_TYPE_HINFO:
438 free(rr->hinfo.cpu);
439 free(rr->hinfo.os);
440 break;
441
442 case DNS_TYPE_TXT:
443 case DNS_TYPE_SPF:
444 dns_txt_item_free_all(rr->txt.items);
445 break;
446
447 case DNS_TYPE_SOA:
448 free(rr->soa.mname);
449 free(rr->soa.rname);
450 break;
451
452 case DNS_TYPE_MX:
453 free(rr->mx.exchange);
454 break;
455
456 case DNS_TYPE_DS:
457 free(rr->ds.digest);
458 break;
459
460 case DNS_TYPE_SSHFP:
461 free(rr->sshfp.fingerprint);
462 break;
463
464 case DNS_TYPE_DNSKEY:
465 free(rr->dnskey.key);
466 break;
467
468 case DNS_TYPE_RRSIG:
469 free(rr->rrsig.signer);
470 free(rr->rrsig.signature);
471 break;
472
473 case DNS_TYPE_NSEC:
474 free(rr->nsec.next_domain_name);
475 bitmap_free(rr->nsec.types);
476 break;
477
478 case DNS_TYPE_NSEC3:
479 free(rr->nsec3.next_hashed_name);
480 free(rr->nsec3.salt);
481 bitmap_free(rr->nsec3.types);
482 break;
483
484 case DNS_TYPE_LOC:
485 case DNS_TYPE_A:
486 case DNS_TYPE_AAAA:
487 break;
488
489 default:
490 free(rr->generic.data);
491 }
492
493 free(rr->wire_format);
494 dns_resource_key_unref(rr->key);
495 }
496
497 free(rr->to_string);
498 free(rr);
499
500 return NULL;
501 }
502
503 int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *hostname) {
504 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
505 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
506 _cleanup_free_ char *ptr = NULL;
507 int r;
508
509 assert(ret);
510 assert(address);
511 assert(hostname);
512
513 r = dns_name_reverse(family, address, &ptr);
514 if (r < 0)
515 return r;
516
517 key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, ptr);
518 if (!key)
519 return -ENOMEM;
520
521 ptr = NULL;
522
523 rr = dns_resource_record_new(key);
524 if (!rr)
525 return -ENOMEM;
526
527 rr->ptr.name = strdup(hostname);
528 if (!rr->ptr.name)
529 return -ENOMEM;
530
531 *ret = rr;
532 rr = NULL;
533
534 return 0;
535 }
536
537 int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name) {
538 DnsResourceRecord *rr;
539
540 assert(ret);
541 assert(address);
542 assert(family);
543
544 if (family == AF_INET) {
545
546 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, name);
547 if (!rr)
548 return -ENOMEM;
549
550 rr->a.in_addr = address->in;
551
552 } else if (family == AF_INET6) {
553
554 rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, name);
555 if (!rr)
556 return -ENOMEM;
557
558 rr->aaaa.in6_addr = address->in6;
559 } else
560 return -EAFNOSUPPORT;
561
562 *ret = rr;
563
564 return 0;
565 }
566
567 int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) {
568 int r;
569
570 assert(a);
571 assert(b);
572
573 if (a == b)
574 return 1;
575
576 r = dns_resource_key_equal(a->key, b->key);
577 if (r <= 0)
578 return r;
579
580 if (a->unparseable != b->unparseable)
581 return 0;
582
583 switch (a->unparseable ? _DNS_TYPE_INVALID : a->key->type) {
584
585 case DNS_TYPE_SRV:
586 r = dns_name_equal(a->srv.name, b->srv.name);
587 if (r <= 0)
588 return r;
589
590 return a->srv.priority == b->srv.priority &&
591 a->srv.weight == b->srv.weight &&
592 a->srv.port == b->srv.port;
593
594 case DNS_TYPE_PTR:
595 case DNS_TYPE_NS:
596 case DNS_TYPE_CNAME:
597 case DNS_TYPE_DNAME:
598 return dns_name_equal(a->ptr.name, b->ptr.name);
599
600 case DNS_TYPE_HINFO:
601 return strcaseeq(a->hinfo.cpu, b->hinfo.cpu) &&
602 strcaseeq(a->hinfo.os, b->hinfo.os);
603
604 case DNS_TYPE_SPF: /* exactly the same as TXT */
605 case DNS_TYPE_TXT:
606 return dns_txt_item_equal(a->txt.items, b->txt.items);
607
608 case DNS_TYPE_A:
609 return memcmp(&a->a.in_addr, &b->a.in_addr, sizeof(struct in_addr)) == 0;
610
611 case DNS_TYPE_AAAA:
612 return memcmp(&a->aaaa.in6_addr, &b->aaaa.in6_addr, sizeof(struct in6_addr)) == 0;
613
614 case DNS_TYPE_SOA:
615 r = dns_name_equal(a->soa.mname, b->soa.mname);
616 if (r <= 0)
617 return r;
618 r = dns_name_equal(a->soa.rname, b->soa.rname);
619 if (r <= 0)
620 return r;
621
622 return a->soa.serial == b->soa.serial &&
623 a->soa.refresh == b->soa.refresh &&
624 a->soa.retry == b->soa.retry &&
625 a->soa.expire == b->soa.expire &&
626 a->soa.minimum == b->soa.minimum;
627
628 case DNS_TYPE_MX:
629 if (a->mx.priority != b->mx.priority)
630 return 0;
631
632 return dns_name_equal(a->mx.exchange, b->mx.exchange);
633
634 case DNS_TYPE_LOC:
635 assert(a->loc.version == b->loc.version);
636
637 return a->loc.size == b->loc.size &&
638 a->loc.horiz_pre == b->loc.horiz_pre &&
639 a->loc.vert_pre == b->loc.vert_pre &&
640 a->loc.latitude == b->loc.latitude &&
641 a->loc.longitude == b->loc.longitude &&
642 a->loc.altitude == b->loc.altitude;
643
644 case DNS_TYPE_DS:
645 return a->ds.key_tag == b->ds.key_tag &&
646 a->ds.algorithm == b->ds.algorithm &&
647 a->ds.digest_type == b->ds.digest_type &&
648 a->ds.digest_size == b->ds.digest_size &&
649 memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0;
650
651 case DNS_TYPE_SSHFP:
652 return a->sshfp.algorithm == b->sshfp.algorithm &&
653 a->sshfp.fptype == b->sshfp.fptype &&
654 a->sshfp.fingerprint_size == b->sshfp.fingerprint_size &&
655 memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0;
656
657 case DNS_TYPE_DNSKEY:
658 return a->dnskey.flags == b->dnskey.flags &&
659 a->dnskey.protocol == b->dnskey.protocol &&
660 a->dnskey.algorithm == b->dnskey.algorithm &&
661 a->dnskey.key_size == b->dnskey.key_size &&
662 memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0;
663
664 case DNS_TYPE_RRSIG:
665 /* do the fast comparisons first */
666 if (a->rrsig.type_covered != b->rrsig.type_covered ||
667 a->rrsig.algorithm != b->rrsig.algorithm ||
668 a->rrsig.labels != b->rrsig.labels ||
669 a->rrsig.original_ttl != b->rrsig.original_ttl ||
670 a->rrsig.expiration != b->rrsig.expiration ||
671 a->rrsig.inception != b->rrsig.inception ||
672 a->rrsig.key_tag != b->rrsig.key_tag ||
673 a->rrsig.signature_size != b->rrsig.signature_size ||
674 memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0)
675 return false;
676
677 return dns_name_equal(a->rrsig.signer, b->rrsig.signer);
678
679 case DNS_TYPE_NSEC:
680 return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) &&
681 bitmap_equal(a->nsec.types, b->nsec.types);
682
683 case DNS_TYPE_NSEC3:
684 return a->nsec3.algorithm == b->nsec3.algorithm &&
685 a->nsec3.flags == b->nsec3.flags &&
686 a->nsec3.iterations == b->nsec3.iterations &&
687 a->nsec3.salt_size == b->nsec3.salt_size &&
688 memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 &&
689 memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 &&
690 bitmap_equal(a->nsec3.types, b->nsec3.types);
691
692 default:
693 return a->generic.size == b->generic.size &&
694 memcmp(a->generic.data, b->generic.data, a->generic.size) == 0;
695 }
696 }
697
698 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
699 uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
700 char *s;
701 char NS = latitude >= 1U<<31 ? 'N' : 'S';
702 char EW = longitude >= 1U<<31 ? 'E' : 'W';
703
704 int lat = latitude >= 1U<<31 ? (int) (latitude - (1U<<31)) : (int) ((1U<<31) - latitude);
705 int lon = longitude >= 1U<<31 ? (int) (longitude - (1U<<31)) : (int) ((1U<<31) - longitude);
706 double alt = altitude >= 10000000u ? altitude - 10000000u : -(double)(10000000u - altitude);
707 double siz = (size >> 4) * exp10((double) (size & 0xF));
708 double hor = (horiz_pre >> 4) * exp10((double) (horiz_pre & 0xF));
709 double ver = (vert_pre >> 4) * exp10((double) (vert_pre & 0xF));
710
711 if (asprintf(&s, "%d %d %.3f %c %d %d %.3f %c %.2fm %.2fm %.2fm %.2fm",
712 (lat / 60000 / 60),
713 (lat / 60000) % 60,
714 (lat % 60000) / 1000.,
715 NS,
716 (lon / 60000 / 60),
717 (lon / 60000) % 60,
718 (lon % 60000) / 1000.,
719 EW,
720 alt / 100.,
721 siz / 100.,
722 hor / 100.,
723 ver / 100.) < 0)
724 return NULL;
725
726 return s;
727 }
728
729 static int format_timestamp_dns(char *buf, size_t l, time_t sec) {
730 struct tm tm;
731
732 assert(buf);
733 assert(l > strlen("YYYYMMDDHHmmSS"));
734
735 if (!gmtime_r(&sec, &tm))
736 return -EINVAL;
737
738 if (strftime(buf, l, "%Y%m%d%H%M%S", &tm) <= 0)
739 return -EINVAL;
740
741 return 0;
742 }
743
744 static char *format_types(Bitmap *types) {
745 _cleanup_strv_free_ char **strv = NULL;
746 _cleanup_free_ char *str = NULL;
747 Iterator i;
748 unsigned type;
749 int r;
750
751 BITMAP_FOREACH(type, types, i) {
752 if (dns_type_to_string(type)) {
753 r = strv_extend(&strv, dns_type_to_string(type));
754 if (r < 0)
755 return NULL;
756 } else {
757 char *t;
758
759 r = asprintf(&t, "TYPE%u", type);
760 if (r < 0)
761 return NULL;
762
763 r = strv_consume(&strv, t);
764 if (r < 0)
765 return NULL;
766 }
767 }
768
769 str = strv_join(strv, " ");
770 if (!str)
771 return NULL;
772
773 return strjoin("( ", str, " )", NULL);
774 }
775
776 static char *format_txt(DnsTxtItem *first) {
777 DnsTxtItem *i;
778 size_t c = 1;
779 char *p, *s;
780
781 LIST_FOREACH(items, i, first)
782 c += i->length * 4 + 3;
783
784 p = s = new(char, c);
785 if (!s)
786 return NULL;
787
788 LIST_FOREACH(items, i, first) {
789 size_t j;
790
791 if (i != first)
792 *(p++) = ' ';
793
794 *(p++) = '"';
795
796 for (j = 0; j < i->length; j++) {
797 if (i->data[j] < ' ' || i->data[j] == '"' || i->data[j] >= 127) {
798 *(p++) = '\\';
799 *(p++) = '0' + (i->data[j] / 100);
800 *(p++) = '0' + ((i->data[j] / 10) % 10);
801 *(p++) = '0' + (i->data[j] % 10);
802 } else
803 *(p++) = i->data[j];
804 }
805
806 *(p++) = '"';
807 }
808
809 *p = 0;
810 return s;
811 }
812
813 const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
814 _cleanup_free_ char *k = NULL, *t = NULL;
815 char *s;
816 int r;
817
818 assert(rr);
819
820 if (rr->to_string)
821 return rr->to_string;
822
823 r = dns_resource_key_to_string(rr->key, &k);
824 if (r < 0)
825 return NULL;
826
827 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
828
829 case DNS_TYPE_SRV:
830 r = asprintf(&s, "%s %u %u %u %s",
831 k,
832 rr->srv.priority,
833 rr->srv.weight,
834 rr->srv.port,
835 strna(rr->srv.name));
836 if (r < 0)
837 return NULL;
838 break;
839
840 case DNS_TYPE_PTR:
841 case DNS_TYPE_NS:
842 case DNS_TYPE_CNAME:
843 case DNS_TYPE_DNAME:
844 s = strjoin(k, " ", rr->ptr.name, NULL);
845 if (!s)
846 return NULL;
847
848 break;
849
850 case DNS_TYPE_HINFO:
851 s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL);
852 if (!s)
853 return NULL;
854 break;
855
856 case DNS_TYPE_SPF: /* exactly the same as TXT */
857 case DNS_TYPE_TXT:
858 t = format_txt(rr->txt.items);
859 if (!t)
860 return NULL;
861
862 s = strjoin(k, " ", t, NULL);
863 if (!s)
864 return NULL;
865 break;
866
867 case DNS_TYPE_A: {
868 _cleanup_free_ char *x = NULL;
869
870 r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x);
871 if (r < 0)
872 return NULL;
873
874 s = strjoin(k, " ", x, NULL);
875 if (!s)
876 return NULL;
877 break;
878 }
879
880 case DNS_TYPE_AAAA:
881 r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t);
882 if (r < 0)
883 return NULL;
884
885 s = strjoin(k, " ", t, NULL);
886 if (!s)
887 return NULL;
888 break;
889
890 case DNS_TYPE_SOA:
891 r = asprintf(&s, "%s %s %s %u %u %u %u %u",
892 k,
893 strna(rr->soa.mname),
894 strna(rr->soa.rname),
895 rr->soa.serial,
896 rr->soa.refresh,
897 rr->soa.retry,
898 rr->soa.expire,
899 rr->soa.minimum);
900 if (r < 0)
901 return NULL;
902 break;
903
904 case DNS_TYPE_MX:
905 r = asprintf(&s, "%s %u %s",
906 k,
907 rr->mx.priority,
908 rr->mx.exchange);
909 if (r < 0)
910 return NULL;
911 break;
912
913 case DNS_TYPE_LOC:
914 assert(rr->loc.version == 0);
915
916 t = format_location(rr->loc.latitude,
917 rr->loc.longitude,
918 rr->loc.altitude,
919 rr->loc.size,
920 rr->loc.horiz_pre,
921 rr->loc.vert_pre);
922 if (!t)
923 return NULL;
924
925 s = strjoin(k, " ", t, NULL);
926 if (!s)
927 return NULL;
928 break;
929
930 case DNS_TYPE_DS:
931 t = hexmem(rr->ds.digest, rr->ds.digest_size);
932 if (!t)
933 return NULL;
934
935 r = asprintf(&s, "%s %u %u %u %s",
936 k,
937 rr->ds.key_tag,
938 rr->ds.algorithm,
939 rr->ds.digest_type,
940 t);
941 if (r < 0)
942 return NULL;
943 break;
944
945 case DNS_TYPE_SSHFP:
946 t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size);
947 if (!t)
948 return NULL;
949
950 r = asprintf(&s, "%s %u %u %s",
951 k,
952 rr->sshfp.algorithm,
953 rr->sshfp.fptype,
954 t);
955 if (r < 0)
956 return NULL;
957 break;
958
959 case DNS_TYPE_DNSKEY: {
960 _cleanup_free_ char *alg = NULL;
961
962 r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg);
963 if (r < 0)
964 return NULL;
965
966 t = base64mem(rr->dnskey.key, rr->dnskey.key_size);
967 if (!t)
968 return NULL;
969
970 r = asprintf(&s, "%s %u %u %s %s",
971 k,
972 rr->dnskey.flags,
973 rr->dnskey.protocol,
974 alg,
975 t);
976 if (r < 0)
977 return NULL;
978 break;
979 }
980
981 case DNS_TYPE_RRSIG: {
982 _cleanup_free_ char *alg = NULL;
983 char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1];
984 const char *type;
985
986 type = dns_type_to_string(rr->rrsig.type_covered);
987
988 r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg);
989 if (r < 0)
990 return NULL;
991
992 t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size);
993 if (!t)
994 return NULL;
995
996 r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration);
997 if (r < 0)
998 return NULL;
999
1000 r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception);
1001 if (r < 0)
1002 return NULL;
1003
1004 /* TYPE?? follows
1005 * http://tools.ietf.org/html/rfc3597#section-5 */
1006
1007 r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %s",
1008 k,
1009 type ?: "TYPE",
1010 type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
1011 alg,
1012 rr->rrsig.labels,
1013 rr->rrsig.original_ttl,
1014 expiration,
1015 inception,
1016 rr->rrsig.key_tag,
1017 rr->rrsig.signer,
1018 t);
1019 if (r < 0)
1020 return NULL;
1021 break;
1022 }
1023
1024 case DNS_TYPE_NSEC:
1025 t = format_types(rr->nsec.types);
1026 if (!t)
1027 return NULL;
1028
1029 r = asprintf(&s, "%s %s %s",
1030 k,
1031 rr->nsec.next_domain_name,
1032 t);
1033 if (r < 0)
1034 return NULL;
1035 break;
1036
1037 case DNS_TYPE_NSEC3: {
1038 _cleanup_free_ char *salt = NULL, *hash = NULL;
1039
1040 if (rr->nsec3.salt_size > 0) {
1041 salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size);
1042 if (!salt)
1043 return NULL;
1044 }
1045
1046 hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false);
1047 if (!hash)
1048 return NULL;
1049
1050 t = format_types(rr->nsec3.types);
1051 if (!t)
1052 return NULL;
1053
1054 r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s",
1055 k,
1056 rr->nsec3.algorithm,
1057 rr->nsec3.flags,
1058 rr->nsec3.iterations,
1059 rr->nsec3.salt_size > 0 ? salt : "-",
1060 hash,
1061 t);
1062 if (r < 0)
1063 return NULL;
1064
1065 break;
1066 }
1067
1068 default:
1069 t = hexmem(rr->generic.data, rr->generic.size);
1070 if (!t)
1071 return NULL;
1072
1073 /* Format as documented in RFC 3597, Section 5 */
1074 r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t);
1075 if (r < 0)
1076 return NULL;
1077 break;
1078 }
1079
1080 rr->to_string = s;
1081 return s;
1082 }
1083
1084 int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) {
1085
1086 DnsPacket packet = {
1087 .n_ref = 1,
1088 .protocol = DNS_PROTOCOL_DNS,
1089 .on_stack = true,
1090 .refuse_compression = true,
1091 .canonical_form = canonical,
1092 };
1093
1094 size_t start, rds;
1095 int r;
1096
1097 assert(rr);
1098
1099 /* Generates the RR in wire-format, optionally in the
1100 * canonical form as discussed in the DNSSEC RFC 4034, Section
1101 * 6.2. We allocate a throw-away DnsPacket object on the stack
1102 * here, because we need some book-keeping for memory
1103 * management, and can reuse the DnsPacket serializer, that
1104 * can generate the canonical form, too, but also knows label
1105 * compression and suchlike. */
1106
1107 if (rr->wire_format && rr->wire_format_canonical == canonical)
1108 return 0;
1109
1110 r = dns_packet_append_rr(&packet, rr, &start, &rds);
1111 if (r < 0)
1112 return r;
1113
1114 assert(start == 0);
1115 assert(packet._data);
1116
1117 free(rr->wire_format);
1118 rr->wire_format = packet._data;
1119 rr->wire_format_size = packet.size;
1120 rr->wire_format_rdata_offset = rds;
1121 rr->wire_format_canonical = canonical;
1122
1123 packet._data = NULL;
1124 dns_packet_unref(&packet);
1125
1126 return 0;
1127 }
1128
1129 int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) {
1130 const char *n;
1131 int r;
1132
1133 assert(rr);
1134 assert(ret);
1135
1136 /* Returns the RRset's signer, if it is known. */
1137
1138 if (rr->n_skip_labels_signer == (unsigned) -1)
1139 return -ENODATA;
1140
1141 n = DNS_RESOURCE_KEY_NAME(rr->key);
1142 r = dns_name_skip(n, rr->n_skip_labels_signer, &n);
1143 if (r < 0)
1144 return r;
1145 if (r == 0)
1146 return -EINVAL;
1147
1148 *ret = n;
1149 return 0;
1150 }
1151
1152 int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) {
1153 const char *n;
1154 int r;
1155
1156 assert(rr);
1157 assert(ret);
1158
1159 /* Returns the RRset's synthesizing source, if it is known. */
1160
1161 if (rr->n_skip_labels_source == (unsigned) -1)
1162 return -ENODATA;
1163
1164 n = DNS_RESOURCE_KEY_NAME(rr->key);
1165 r = dns_name_skip(n, rr->n_skip_labels_source, &n);
1166 if (r < 0)
1167 return r;
1168 if (r == 0)
1169 return -EINVAL;
1170
1171 *ret = n;
1172 return 0;
1173 }
1174
1175 int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) {
1176 const char *signer;
1177 int r;
1178
1179 assert(rr);
1180
1181 r = dns_resource_record_signer(rr, &signer);
1182 if (r < 0)
1183 return r;
1184
1185 return dns_name_equal(zone, signer);
1186 }
1187
1188 int dns_resource_record_is_synthetic(DnsResourceRecord *rr) {
1189 int r;
1190
1191 assert(rr);
1192
1193 /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */
1194
1195 if (rr->n_skip_labels_source == (unsigned) -1)
1196 return -ENODATA;
1197
1198 if (rr->n_skip_labels_source == 0)
1199 return 0;
1200
1201 if (rr->n_skip_labels_source > 1)
1202 return 1;
1203
1204 r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*");
1205 if (r < 0)
1206 return r;
1207
1208 return !r;
1209 }
1210
1211 static void dns_resource_record_hash_func(const void *i, struct siphash *state) {
1212 const DnsResourceRecord *rr = i;
1213
1214 assert(rr);
1215
1216 dns_resource_key_hash_func(rr->key, state);
1217
1218 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
1219
1220 case DNS_TYPE_SRV:
1221 siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state);
1222 siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state);
1223 siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state);
1224 dns_name_hash_func(rr->srv.name, state);
1225 break;
1226
1227 case DNS_TYPE_PTR:
1228 case DNS_TYPE_NS:
1229 case DNS_TYPE_CNAME:
1230 case DNS_TYPE_DNAME:
1231 dns_name_hash_func(rr->ptr.name, state);
1232 break;
1233
1234 case DNS_TYPE_HINFO:
1235 string_hash_func(rr->hinfo.cpu, state);
1236 string_hash_func(rr->hinfo.os, state);
1237 break;
1238
1239 case DNS_TYPE_TXT:
1240 case DNS_TYPE_SPF: {
1241 DnsTxtItem *j;
1242
1243 LIST_FOREACH(items, j, rr->txt.items) {
1244 siphash24_compress(j->data, j->length, state);
1245
1246 /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab"
1247 * followed by "". */
1248 siphash24_compress_byte(0, state);
1249 }
1250 break;
1251 }
1252
1253 case DNS_TYPE_A:
1254 siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state);
1255 break;
1256
1257 case DNS_TYPE_AAAA:
1258 siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state);
1259 break;
1260
1261 case DNS_TYPE_SOA:
1262 dns_name_hash_func(rr->soa.mname, state);
1263 dns_name_hash_func(rr->soa.rname, state);
1264 siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state);
1265 siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state);
1266 siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state);
1267 siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state);
1268 siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state);
1269 break;
1270
1271 case DNS_TYPE_MX:
1272 siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state);
1273 dns_name_hash_func(rr->mx.exchange, state);
1274 break;
1275
1276 case DNS_TYPE_LOC:
1277 siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state);
1278 siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state);
1279 siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state);
1280 siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state);
1281 siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state);
1282 siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state);
1283 siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state);
1284 break;
1285
1286 case DNS_TYPE_SSHFP:
1287 siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state);
1288 siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state);
1289 siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state);
1290 break;
1291
1292 case DNS_TYPE_DNSKEY:
1293 siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state);
1294 siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state);
1295 siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state);
1296 siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state);
1297 break;
1298
1299 case DNS_TYPE_RRSIG:
1300 siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state);
1301 siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state);
1302 siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state);
1303 siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state);
1304 siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state);
1305 siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state);
1306 siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state);
1307 dns_name_hash_func(rr->rrsig.signer, state);
1308 siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state);
1309 break;
1310
1311 case DNS_TYPE_NSEC:
1312 dns_name_hash_func(rr->nsec.next_domain_name, state);
1313 /* FIXME: we leave out the type bitmap here. Hash
1314 * would be better if we'd take it into account
1315 * too. */
1316 break;
1317
1318 case DNS_TYPE_DS:
1319 siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state);
1320 siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state);
1321 siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state);
1322 siphash24_compress(rr->ds.digest, rr->ds.digest_size, state);
1323 break;
1324
1325 case DNS_TYPE_NSEC3:
1326 siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state);
1327 siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state);
1328 siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state);
1329 siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state);
1330 siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state);
1331 /* FIXME: We leave the bitmaps out */
1332 break;
1333
1334 default:
1335 siphash24_compress(rr->generic.data, rr->generic.size, state);
1336 break;
1337 }
1338 }
1339
1340 static int dns_resource_record_compare_func(const void *a, const void *b) {
1341 const DnsResourceRecord *x = a, *y = b;
1342 int ret;
1343
1344 ret = dns_resource_key_compare_func(x->key, y->key);
1345 if (ret != 0)
1346 return ret;
1347
1348 if (dns_resource_record_equal(x, y))
1349 return 0;
1350
1351 /* This is a bit dirty, we don't implement proper odering, but
1352 * the hashtable doesn't need ordering anyway, hence we don't
1353 * care. */
1354 return x < y ? -1 : 1;
1355 }
1356
1357 const struct hash_ops dns_resource_record_hash_ops = {
1358 .hash = dns_resource_record_hash_func,
1359 .compare = dns_resource_record_compare_func,
1360 };
1361
1362 DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) {
1363 DnsTxtItem *n;
1364
1365 if (!i)
1366 return NULL;
1367
1368 n = i->items_next;
1369
1370 free(i);
1371 return dns_txt_item_free_all(n);
1372 }
1373
1374 bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {
1375
1376 if (a == b)
1377 return true;
1378
1379 if (!a != !b)
1380 return false;
1381
1382 if (!a)
1383 return true;
1384
1385 if (a->length != b->length)
1386 return false;
1387
1388 if (memcmp(a->data, b->data, a->length) != 0)
1389 return false;
1390
1391 return dns_txt_item_equal(a->items_next, b->items_next);
1392 }
1393
1394 static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1395 /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */
1396 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1397 [DNSSEC_ALGORITHM_DH] = "DH",
1398 [DNSSEC_ALGORITHM_DSA] = "DSA",
1399 [DNSSEC_ALGORITHM_ECC] = "ECC",
1400 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1401 [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1",
1402 [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1",
1403 [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256",
1404 [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512",
1405 [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST",
1406 [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256",
1407 [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384",
1408 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1409 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1410 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1411 };
1412 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255);
1413
1414 static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = {
1415 /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */
1416 [DNSSEC_DIGEST_SHA1] = "SHA-1",
1417 [DNSSEC_DIGEST_SHA256] = "SHA-256",
1418 [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94",
1419 [DNSSEC_DIGEST_SHA384] = "SHA-384",
1420 };
1421 DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255);