]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-dns-packet.c
Merge pull request #147 from poettering/cmsg
[thirdparty/systemd.git] / src / resolve / resolved-dns-packet.c
CommitLineData
74b2466e
LP
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 "utf8.h"
c73ce96b 23#include "util.h"
2e276efc 24#include "strv.h"
725ca0e5 25#include "unaligned.h"
74b2466e
LP
26#include "resolved-dns-domain.h"
27#include "resolved-dns-packet.h"
28
1716f6dc 29int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
30 DnsPacket *p;
31 size_t a;
32
33 assert(ret);
34
35 if (mtu <= 0)
36 a = DNS_PACKET_SIZE_START;
37 else
38 a = mtu;
39
40 if (a < DNS_PACKET_HEADER_SIZE)
41 a = DNS_PACKET_HEADER_SIZE;
42
c73ce96b
LP
43 /* round up to next page size */
44 a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
45
46 /* make sure we never allocate more than useful */
47 if (a > DNS_PACKET_SIZE_MAX)
48 a = DNS_PACKET_SIZE_MAX;
49
74b2466e
LP
50 p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
51 if (!p)
52 return -ENOMEM;
53
54 p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
55 p->allocated = a;
1716f6dc 56 p->protocol = protocol;
74b2466e
LP
57 p->n_ref = 1;
58
59 *ret = p;
60
61 return 0;
62}
63
1716f6dc 64int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
74b2466e
LP
65 DnsPacket *p;
66 DnsPacketHeader *h;
67 int r;
68
69 assert(ret);
70
1716f6dc 71 r = dns_packet_new(&p, protocol, mtu);
74b2466e
LP
72 if (r < 0)
73 return r;
74
75 h = DNS_PACKET_HEADER(p);
1716f6dc 76
ea917db9
LP
77 if (protocol == DNS_PROTOCOL_LLMNR)
78 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
79 0 /* opcode */,
80 0 /* c */,
81 0 /* tc */,
82 0 /* t */,
83 0 /* ra */,
84 0 /* ad */,
85 0 /* cd */,
86 0 /* rcode */));
1716f6dc 87 else
ea917db9
LP
88 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,
89 0 /* opcode */,
90 0 /* aa */,
91 0 /* tc */,
92 1 /* rd (ask for recursion) */,
93 0 /* ra */,
94 0 /* ad */,
95 0 /* cd */,
96 0 /* rcode */));
74b2466e
LP
97
98 *ret = p;
99 return 0;
100}
101
102DnsPacket *dns_packet_ref(DnsPacket *p) {
103
104 if (!p)
105 return NULL;
106
107 assert(p->n_ref > 0);
108 p->n_ref++;
109 return p;
110}
111
112static void dns_packet_free(DnsPacket *p) {
113 char *s;
114
115 assert(p);
116
faa133f3
LP
117 dns_question_unref(p->question);
118 dns_answer_unref(p->answer);
322345fd 119
74b2466e
LP
120 while ((s = hashmap_steal_first_key(p->names)))
121 free(s);
122 hashmap_free(p->names);
123
faa133f3 124 free(p->_data);
74b2466e
LP
125 free(p);
126}
127
128DnsPacket *dns_packet_unref(DnsPacket *p) {
129 if (!p)
130 return NULL;
131
132 assert(p->n_ref > 0);
133
134 if (p->n_ref == 1)
135 dns_packet_free(p);
136 else
137 p->n_ref--;
138
139 return NULL;
140}
141
142int dns_packet_validate(DnsPacket *p) {
143 assert(p);
144
145 if (p->size < DNS_PACKET_HEADER_SIZE)
146 return -EBADMSG;
147
c73ce96b
LP
148 if (p->size > DNS_PACKET_SIZE_MAX)
149 return -EBADMSG;
150
623a4c97 151 return 1;
74b2466e
LP
152}
153
154int dns_packet_validate_reply(DnsPacket *p) {
74b2466e
LP
155 int r;
156
157 assert(p);
158
159 r = dns_packet_validate(p);
160 if (r < 0)
161 return r;
162
623a4c97
LP
163 if (DNS_PACKET_QR(p) != 1)
164 return 0;
165
166 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
167 return -EBADMSG;
168
ea917db9
LP
169 /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */
170 if (p->protocol == DNS_PROTOCOL_LLMNR &&
171 DNS_PACKET_QDCOUNT(p) != 1)
172 return -EBADMSG;
173
623a4c97
LP
174 return 1;
175}
176
177int dns_packet_validate_query(DnsPacket *p) {
178 int r;
179
180 assert(p);
181
182 r = dns_packet_validate(p);
183 if (r < 0)
184 return r;
185
186 if (DNS_PACKET_QR(p) != 0)
187 return 0;
188
3cb10d3a 189 if (DNS_PACKET_OPCODE(p) != 0)
74b2466e
LP
190 return -EBADMSG;
191
623a4c97
LP
192 if (DNS_PACKET_TC(p))
193 return -EBADMSG;
194
ea917db9 195 /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */
623a4c97
LP
196 if (p->protocol == DNS_PROTOCOL_LLMNR &&
197 DNS_PACKET_QDCOUNT(p) != 1)
198 return -EBADMSG;
199
ea917db9 200 /* RFC 4795, Section 2.1.1. says to discard all queries with ANCOUNT != 0 */
623a4c97
LP
201 if (DNS_PACKET_ANCOUNT(p) > 0)
202 return -EBADMSG;
203
ea917db9 204 /* RFC 4795, Section 2.1.1. says to discard all queries with NSCOUNT != 0 */
623a4c97
LP
205 if (DNS_PACKET_NSCOUNT(p) > 0)
206 return -EBADMSG;
207
208 return 1;
74b2466e
LP
209}
210
211static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
212 assert(p);
213
c73ce96b
LP
214 if (p->size + add > p->allocated) {
215 size_t a;
216
217 a = PAGE_ALIGN((p->size + add) * 2);
218 if (a > DNS_PACKET_SIZE_MAX)
219 a = DNS_PACKET_SIZE_MAX;
220
221 if (p->size + add > a)
222 return -EMSGSIZE;
223
faa133f3 224 if (p->_data) {
c73ce96b
LP
225 void *d;
226
faa133f3 227 d = realloc(p->_data, a);
c73ce96b
LP
228 if (!d)
229 return -ENOMEM;
230
faa133f3 231 p->_data = d;
c73ce96b 232 } else {
faa133f3
LP
233 p->_data = malloc(a);
234 if (!p->_data)
c73ce96b
LP
235 return -ENOMEM;
236
faa133f3
LP
237 memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
238 memzero((uint8_t*) p->_data + p->size, a - p->size);
c73ce96b
LP
239 }
240
241 p->allocated = a;
242 }
74b2466e
LP
243
244 if (start)
245 *start = p->size;
246
247 if (ret)
248 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
249
250 p->size += add;
251 return 0;
252}
253
254static void dns_packet_truncate(DnsPacket *p, size_t sz) {
255 Iterator i;
256 char *s;
257 void *n;
258
259 assert(p);
260
261 if (p->size <= sz)
262 return;
263
264 HASHMAP_FOREACH_KEY(s, n, p->names, i) {
265
266 if (PTR_TO_SIZE(n) < sz)
267 continue;
268
269 hashmap_remove(p->names, s);
270 free(s);
271 }
272
273 p->size = sz;
274}
275
623a4c97
LP
276int dns_packet_append_blob(DnsPacket *p, const void *d, size_t l, size_t *start) {
277 void *q;
278 int r;
279
280 assert(p);
281
282 r = dns_packet_extend(p, l, &q, start);
283 if (r < 0)
284 return r;
285
286 memcpy(q, d, l);
287 return 0;
288}
289
74b2466e
LP
290int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
291 void *d;
292 int r;
293
294 assert(p);
295
296 r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
297 if (r < 0)
298 return r;
299
300 ((uint8_t*) d)[0] = v;
301
302 return 0;
303}
304
305int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
306 void *d;
307 int r;
308
309 assert(p);
310
311 r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
312 if (r < 0)
313 return r;
314
725ca0e5 315 unaligned_write_be16(d, v);
623a4c97
LP
316
317 return 0;
318}
319
320int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {
321 void *d;
322 int r;
323
324 assert(p);
325
326 r = dns_packet_extend(p, sizeof(uint32_t), &d, start);
327 if (r < 0)
328 return r;
329
725ca0e5 330 unaligned_write_be32(d, v);
74b2466e
LP
331
332 return 0;
333}
334
335int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
336 void *d;
337 size_t l;
338 int r;
339
340 assert(p);
341 assert(s);
342
343 l = strlen(s);
344 if (l > 255)
345 return -E2BIG;
346
347 r = dns_packet_extend(p, 1 + l, &d, start);
348 if (r < 0)
349 return r;
350
351 ((uint8_t*) d)[0] = (uint8_t) l;
352 memcpy(((uint8_t*) d) + 1, s, l);
353
354 return 0;
355}
356
357int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
358 void *w;
359 int r;
360
361 assert(p);
362 assert(d);
363
364 if (l > DNS_LABEL_MAX)
365 return -E2BIG;
366
367 r = dns_packet_extend(p, 1 + l, &w, start);
368 if (r < 0)
369 return r;
370
371 ((uint8_t*) w)[0] = (uint8_t) l;
372 memcpy(((uint8_t*) w) + 1, d, l);
373
374 return 0;
375}
376
151226ab
ZJS
377int dns_packet_append_name(DnsPacket *p, const char *name,
378 bool allow_compression, size_t *start) {
74b2466e
LP
379 size_t saved_size;
380 int r;
381
382 assert(p);
383 assert(name);
384
385 saved_size = p->size;
386
387 while (*name) {
388 _cleanup_free_ char *s = NULL;
389 char label[DNS_LABEL_MAX];
151226ab 390 size_t n = 0;
bdf10b5b 391 int k;
74b2466e 392
151226ab
ZJS
393 if (allow_compression)
394 n = PTR_TO_SIZE(hashmap_get(p->names, name));
74b2466e
LP
395 if (n > 0) {
396 assert(n < p->size);
397
398 if (n < 0x4000) {
399 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
400 if (r < 0)
401 goto fail;
402
403 goto done;
404 }
405 }
406
407 s = strdup(name);
408 if (!s) {
409 r = -ENOMEM;
410 goto fail;
411 }
412
413 r = dns_label_unescape(&name, label, sizeof(label));
414 if (r < 0)
415 goto fail;
416
bdf10b5b
LP
417 if (p->protocol == DNS_PROTOCOL_DNS)
418 k = dns_label_apply_idna(label, r, label, sizeof(label));
419 else
420 k = dns_label_undo_idna(label, r, label, sizeof(label));
421 if (k < 0) {
422 r = k;
423 goto fail;
424 }
425 if (k > 0)
426 r = k;
427
74b2466e
LP
428 r = dns_packet_append_label(p, label, r, &n);
429 if (r < 0)
430 goto fail;
431
151226ab 432 if (allow_compression) {
d5099efc 433 r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops);
151226ab
ZJS
434 if (r < 0)
435 goto fail;
74b2466e 436
151226ab
ZJS
437 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
438 if (r < 0)
439 goto fail;
74b2466e 440
151226ab
ZJS
441 s = NULL;
442 }
74b2466e
LP
443 }
444
445 r = dns_packet_append_uint8(p, 0, NULL);
446 if (r < 0)
447 return r;
448
449done:
450 if (start)
451 *start = saved_size;
452
453 return 0;
454
455fail:
456 dns_packet_truncate(p, saved_size);
457 return r;
458}
459
460int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
461 size_t saved_size;
462 int r;
463
464 assert(p);
465 assert(k);
466
467 saved_size = p->size;
468
151226ab 469 r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL);
74b2466e
LP
470 if (r < 0)
471 goto fail;
472
473 r = dns_packet_append_uint16(p, k->type, NULL);
474 if (r < 0)
475 goto fail;
476
477 r = dns_packet_append_uint16(p, k->class, NULL);
478 if (r < 0)
479 goto fail;
480
481 if (start)
482 *start = saved_size;
483
484 return 0;
485
486fail:
487 dns_packet_truncate(p, saved_size);
488 return r;
489}
490
623a4c97
LP
491int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) {
492 size_t saved_size, rdlength_offset, end, rdlength;
493 int r;
494
495 assert(p);
496 assert(rr);
497
498 saved_size = p->size;
499
500 r = dns_packet_append_key(p, rr->key, NULL);
501 if (r < 0)
502 goto fail;
503
504 r = dns_packet_append_uint32(p, rr->ttl, NULL);
505 if (r < 0)
506 goto fail;
507
508 /* Initially we write 0 here */
509 r = dns_packet_append_uint16(p, 0, &rdlength_offset);
510 if (r < 0)
511 goto fail;
512
0dae31d4 513 switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {
623a4c97 514
9c92ce6d
LP
515 case DNS_TYPE_SRV:
516 r = dns_packet_append_uint16(p, rr->srv.priority, NULL);
517 if (r < 0)
518 goto fail;
519
520 r = dns_packet_append_uint16(p, rr->srv.weight, NULL);
521 if (r < 0)
522 goto fail;
523
524 r = dns_packet_append_uint16(p, rr->srv.port, NULL);
525 if (r < 0)
526 goto fail;
527
151226ab 528 r = dns_packet_append_name(p, rr->srv.name, true, NULL);
9c92ce6d
LP
529 break;
530
623a4c97
LP
531 case DNS_TYPE_PTR:
532 case DNS_TYPE_NS:
533 case DNS_TYPE_CNAME:
8ac4e9e1 534 case DNS_TYPE_DNAME:
151226ab 535 r = dns_packet_append_name(p, rr->ptr.name, true, NULL);
623a4c97
LP
536 break;
537
538 case DNS_TYPE_HINFO:
539 r = dns_packet_append_string(p, rr->hinfo.cpu, NULL);
540 if (r < 0)
541 goto fail;
542
543 r = dns_packet_append_string(p, rr->hinfo.os, NULL);
544 break;
545
9de3e329 546 case DNS_TYPE_SPF: /* exactly the same as TXT */
2e276efc
ZJS
547 case DNS_TYPE_TXT: {
548 char **s;
549
1ccda9b7
LP
550 if (strv_isempty(rr->txt.strings)) {
551 /* RFC 6763, section 6.1 suggests to generate
552 * single empty string for an empty array. */
553
554 r = dns_packet_append_string(p, "", NULL);
2e276efc
ZJS
555 if (r < 0)
556 goto fail;
1ccda9b7
LP
557 } else {
558 STRV_FOREACH(s, rr->txt.strings) {
559 r = dns_packet_append_string(p, *s, NULL);
560 if (r < 0)
561 goto fail;
562 }
2e276efc
ZJS
563 }
564
6a6fc3df 565 r = 0;
2e276efc
ZJS
566 break;
567 }
568
623a4c97
LP
569 case DNS_TYPE_A:
570 r = dns_packet_append_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
571 break;
572
573 case DNS_TYPE_AAAA:
574 r = dns_packet_append_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
575 break;
576
577 case DNS_TYPE_SOA:
151226ab 578 r = dns_packet_append_name(p, rr->soa.mname, true, NULL);
623a4c97
LP
579 if (r < 0)
580 goto fail;
581
151226ab 582 r = dns_packet_append_name(p, rr->soa.rname, true, NULL);
623a4c97
LP
583 if (r < 0)
584 goto fail;
585
586 r = dns_packet_append_uint32(p, rr->soa.serial, NULL);
587 if (r < 0)
588 goto fail;
589
590 r = dns_packet_append_uint32(p, rr->soa.refresh, NULL);
591 if (r < 0)
592 goto fail;
593
594 r = dns_packet_append_uint32(p, rr->soa.retry, NULL);
595 if (r < 0)
596 goto fail;
597
598 r = dns_packet_append_uint32(p, rr->soa.expire, NULL);
599 if (r < 0)
600 goto fail;
601
602 r = dns_packet_append_uint32(p, rr->soa.minimum, NULL);
603 break;
604
605 case DNS_TYPE_MX:
946c7094
ZJS
606 r = dns_packet_append_uint16(p, rr->mx.priority, NULL);
607 if (r < 0)
608 goto fail;
609
151226ab 610 r = dns_packet_append_name(p, rr->mx.exchange, true, NULL);
946c7094
ZJS
611 break;
612
0dae31d4
ZJS
613 case DNS_TYPE_LOC:
614 r = dns_packet_append_uint8(p, rr->loc.version, NULL);
615 if (r < 0)
616 goto fail;
617
618 r = dns_packet_append_uint8(p, rr->loc.size, NULL);
619 if (r < 0)
620 goto fail;
621
622 r = dns_packet_append_uint8(p, rr->loc.horiz_pre, NULL);
623 if (r < 0)
624 goto fail;
625
626 r = dns_packet_append_uint8(p, rr->loc.vert_pre, NULL);
627 if (r < 0)
628 goto fail;
629
afbc4f26 630 r = dns_packet_append_uint32(p, rr->loc.latitude, NULL);
0dae31d4
ZJS
631 if (r < 0)
632 goto fail;
633
afbc4f26 634 r = dns_packet_append_uint32(p, rr->loc.longitude, NULL);
0dae31d4
ZJS
635 if (r < 0)
636 goto fail;
637
afbc4f26 638 r = dns_packet_append_uint32(p, rr->loc.altitude, NULL);
0dae31d4
ZJS
639 break;
640
623a4c97 641 case DNS_TYPE_SSHFP:
42cc2eeb
LP
642 r = dns_packet_append_uint8(p, rr->sshfp.algorithm, NULL);
643 if (r < 0)
644 goto fail;
8db0d2f5 645
42cc2eeb
LP
646 r = dns_packet_append_uint8(p, rr->sshfp.fptype, NULL);
647 if (r < 0)
648 goto fail;
649
650 r = dns_packet_append_blob(p, rr->sshfp.key, rr->sshfp.key_size, NULL);
651 break;
652
8db0d2f5
ZJS
653 case DNS_TYPE_DNSKEY:
654 r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL);
655 if (r < 0)
656 goto fail;
657
658 r = dns_packet_append_uint8(p, 3u, NULL);
659 if (r < 0)
660 goto fail;
661
662 r = dns_packet_append_uint8(p, rr->dnskey.algorithm, NULL);
663 if (r < 0)
664 goto fail;
665
666 r = dns_packet_append_blob(p, rr->dnskey.key, rr->dnskey.key_size, NULL);
667 break;
668
151226ab
ZJS
669 case DNS_TYPE_RRSIG:
670 r = dns_packet_append_uint16(p, rr->rrsig.type_covered, NULL);
671 if (r < 0)
672 goto fail;
673
674 r = dns_packet_append_uint8(p, rr->rrsig.algorithm, NULL);
675 if (r < 0)
676 goto fail;
677
678 r = dns_packet_append_uint8(p, rr->rrsig.labels, NULL);
679 if (r < 0)
680 goto fail;
681
682 r = dns_packet_append_uint32(p, rr->rrsig.original_ttl, NULL);
683 if (r < 0)
684 goto fail;
685
686 r = dns_packet_append_uint32(p, rr->rrsig.expiration, NULL);
687 if (r < 0)
688 goto fail;
689
690 r = dns_packet_append_uint32(p, rr->rrsig.inception, NULL);
691 if (r < 0)
692 goto fail;
693
694 r = dns_packet_append_uint8(p, rr->rrsig.key_tag, NULL);
695 if (r < 0)
696 goto fail;
697
698 r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL);
699 if (r < 0)
700 goto fail;
701
702 r = dns_packet_append_blob(p, rr->rrsig.signature, rr->rrsig.signature_size, NULL);
703 break;
704
0dae31d4 705 case _DNS_TYPE_INVALID: /* unparseable */
623a4c97 706 default:
0dae31d4 707
623a4c97
LP
708 r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL);
709 break;
710 }
711 if (r < 0)
712 goto fail;
713
714 /* Let's calculate the actual data size and update the field */
715 rdlength = p->size - rdlength_offset - sizeof(uint16_t);
716 if (rdlength > 0xFFFF) {
717 r = ENOSPC;
718 goto fail;
719 }
720
721 end = p->size;
722 p->size = rdlength_offset;
723 r = dns_packet_append_uint16(p, rdlength, NULL);
724 if (r < 0)
725 goto fail;
726 p->size = end;
727
351e6342
LP
728 if (start)
729 *start = saved_size;
730
623a4c97
LP
731 return 0;
732
733fail:
734 dns_packet_truncate(p, saved_size);
735 return r;
736}
737
738
74b2466e
LP
739int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
740 assert(p);
741
742 if (p->rindex + sz > p->size)
743 return -EMSGSIZE;
744
745 if (ret)
746 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
747
748 if (start)
749 *start = p->rindex;
750
751 p->rindex += sz;
752 return 0;
753}
754
8ba9fd9c 755void dns_packet_rewind(DnsPacket *p, size_t idx) {
74b2466e
LP
756 assert(p);
757 assert(idx <= p->size);
758 assert(idx >= DNS_PACKET_HEADER_SIZE);
759
760 p->rindex = idx;
761}
762
623a4c97
LP
763int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start) {
764 const void *q;
765 int r;
766
767 assert(p);
768 assert(d);
769
770 r = dns_packet_read(p, sz, &q, start);
771 if (r < 0)
772 return r;
773
774 memcpy(d, q, sz);
775 return 0;
776}
777
74b2466e
LP
778int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
779 const void *d;
780 int r;
781
782 assert(p);
783
784 r = dns_packet_read(p, sizeof(uint8_t), &d, start);
785 if (r < 0)
786 return r;
787
788 *ret = ((uint8_t*) d)[0];
789 return 0;
790}
791
792int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
793 const void *d;
794 int r;
795
796 assert(p);
797
798 r = dns_packet_read(p, sizeof(uint16_t), &d, start);
799 if (r < 0)
800 return r;
801
725ca0e5
TG
802 *ret = unaligned_read_be16(d);
803
74b2466e
LP
804 return 0;
805}
806
807int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
808 const void *d;
809 int r;
810
811 assert(p);
812
813 r = dns_packet_read(p, sizeof(uint32_t), &d, start);
814 if (r < 0)
815 return r;
816
725ca0e5 817 *ret = unaligned_read_be32(d);
74b2466e
LP
818
819 return 0;
820}
821
822int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
823 size_t saved_rindex;
824 const void *d;
825 char *t;
826 uint8_t c;
827 int r;
828
829 assert(p);
830
831 saved_rindex = p->rindex;
832
833 r = dns_packet_read_uint8(p, &c, NULL);
834 if (r < 0)
835 goto fail;
836
837 r = dns_packet_read(p, c, &d, NULL);
838 if (r < 0)
839 goto fail;
840
841 if (memchr(d, 0, c)) {
842 r = -EBADMSG;
843 goto fail;
844 }
845
846 t = strndup(d, c);
847 if (!t) {
848 r = -ENOMEM;
849 goto fail;
850 }
851
852 if (!utf8_is_valid(t)) {
853 free(t);
854 r = -EBADMSG;
855 goto fail;
856 }
857
858 *ret = t;
859
860 if (start)
861 *start = saved_rindex;
862
863 return 0;
864
865fail:
866 dns_packet_rewind(p, saved_rindex);
867 return r;
868}
869
151226ab
ZJS
870int dns_packet_read_name(DnsPacket *p, char **_ret,
871 bool allow_compression, size_t *start) {
c75dbf9b 872 size_t saved_rindex, after_rindex = 0, jump_barrier;
74b2466e
LP
873 _cleanup_free_ char *ret = NULL;
874 size_t n = 0, allocated = 0;
875 bool first = true;
876 int r;
877
878 assert(p);
879 assert(_ret);
880
881 saved_rindex = p->rindex;
c75dbf9b 882 jump_barrier = p->rindex;
74b2466e
LP
883
884 for (;;) {
885 uint8_t c, d;
886
887 r = dns_packet_read_uint8(p, &c, NULL);
888 if (r < 0)
889 goto fail;
890
891 if (c == 0)
892 /* End of name */
893 break;
894 else if (c <= 63) {
895 _cleanup_free_ char *t = NULL;
896 const char *label;
897
898 /* Literal label */
899 r = dns_packet_read(p, c, (const void**) &label, NULL);
900 if (r < 0)
901 goto fail;
902
903 r = dns_label_escape(label, c, &t);
904 if (r < 0)
905 goto fail;
906
907 if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
908 r = -ENOMEM;
909 goto fail;
910 }
911
912 if (!first)
913 ret[n++] = '.';
914 else
915 first = false;
916
85818582 917 memcpy(ret + n, t, r);
74b2466e
LP
918 n += r;
919 continue;
151226ab 920 } else if (allow_compression && (c & 0xc0) == 0xc0) {
74b2466e
LP
921 uint16_t ptr;
922
923 /* Pointer */
924 r = dns_packet_read_uint8(p, &d, NULL);
925 if (r < 0)
926 goto fail;
927
928 ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
c75dbf9b 929 if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= jump_barrier) {
74b2466e
LP
930 r = -EBADMSG;
931 goto fail;
932 }
933
934 if (after_rindex == 0)
935 after_rindex = p->rindex;
936
f131770b 937 /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */
c75dbf9b 938 jump_barrier = ptr;
74b2466e 939 p->rindex = ptr;
59aa5821
SP
940 } else {
941 r = -EBADMSG;
74b2466e 942 goto fail;
59aa5821 943 }
74b2466e
LP
944 }
945
946 if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
947 r = -ENOMEM;
948 goto fail;
949 }
950
951 ret[n] = 0;
952
953 if (after_rindex != 0)
954 p->rindex= after_rindex;
955
956 *_ret = ret;
957 ret = NULL;
958
959 if (start)
960 *start = saved_rindex;
961
962 return 0;
963
964fail:
965 dns_packet_rewind(p, saved_rindex);
966 return r;
967}
968
faa133f3
LP
969int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
970 _cleanup_free_ char *name = NULL;
971 uint16_t class, type;
972 DnsResourceKey *key;
74b2466e
LP
973 size_t saved_rindex;
974 int r;
975
976 assert(p);
977 assert(ret);
978
979 saved_rindex = p->rindex;
980
151226ab 981 r = dns_packet_read_name(p, &name, true, NULL);
74b2466e
LP
982 if (r < 0)
983 goto fail;
984
faa133f3 985 r = dns_packet_read_uint16(p, &type, NULL);
74b2466e
LP
986 if (r < 0)
987 goto fail;
988
faa133f3 989 r = dns_packet_read_uint16(p, &class, NULL);
74b2466e
LP
990 if (r < 0)
991 goto fail;
992
faa133f3
LP
993 key = dns_resource_key_new_consume(class, type, name);
994 if (!key) {
995 r = -ENOMEM;
996 goto fail;
997 }
998
999 name = NULL;
1000 *ret = key;
74b2466e
LP
1001
1002 if (start)
1003 *start = saved_rindex;
1004
1005 return 0;
1006fail:
1007 dns_packet_rewind(p, saved_rindex);
1008 return r;
1009}
1010
8db0d2f5
ZJS
1011static int dns_packet_read_public_key(DnsPacket *p, size_t length,
1012 void **dp, size_t *lengthp,
1013 size_t *start) {
1014 int r;
1015 const void *d;
1016 void *d2;
1017
1018 r = dns_packet_read(p, length, &d, NULL);
1019 if (r < 0)
1020 return r;
1021
1022 d2 = memdup(d, length);
1023 if (!d2)
1024 return -ENOMEM;
1025
1026 *dp = d2;
1027 *lengthp = length;
1028 return 0;
1029}
1030
afbc4f26
ZJS
1031static bool loc_size_ok(uint8_t size) {
1032 uint8_t m = size >> 4, e = size & 0xF;
1033
1034 return m <= 9 && e <= 9 && (m > 0 || e == 0);
1035}
1036
8db0d2f5 1037static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) {
3ef77d04
LP
1038 assert(rr);
1039
8db0d2f5
ZJS
1040 if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY))
1041 return -EBADMSG;
1042
1043 rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY;
1044 rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP;
1045 return 0;
1046}
1047
74b2466e 1048int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
faa133f3
LP
1049 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
1050 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e
LP
1051 size_t saved_rindex, offset;
1052 uint16_t rdlength;
1053 const void *d;
1054 int r;
1055
1056 assert(p);
1057 assert(ret);
1058
4e0296a9 1059 saved_rindex = p->rindex;
74b2466e 1060
faa133f3 1061 r = dns_packet_read_key(p, &key, NULL);
74b2466e
LP
1062 if (r < 0)
1063 goto fail;
1064
0e2bcd6a
LP
1065 if (key->class == DNS_CLASS_ANY ||
1066 key->type == DNS_TYPE_ANY) {
1067 r = -EBADMSG;
1068 goto fail;
1069 }
1070
faa133f3
LP
1071 rr = dns_resource_record_new(key);
1072 if (!rr) {
1073 r = -ENOMEM;
1074 goto fail;
1075 }
1076
74b2466e
LP
1077 r = dns_packet_read_uint32(p, &rr->ttl, NULL);
1078 if (r < 0)
1079 goto fail;
1080
1081 r = dns_packet_read_uint16(p, &rdlength, NULL);
1082 if (r < 0)
1083 goto fail;
1084
1085 if (p->rindex + rdlength > p->size) {
1086 r = -EBADMSG;
1087 goto fail;
1088 }
1089
1090 offset = p->rindex;
1091
faa133f3 1092 switch (rr->key->type) {
74b2466e 1093
9c92ce6d
LP
1094 case DNS_TYPE_SRV:
1095 r = dns_packet_read_uint16(p, &rr->srv.priority, NULL);
1096 if (r < 0)
1097 goto fail;
1098 r = dns_packet_read_uint16(p, &rr->srv.weight, NULL);
1099 if (r < 0)
1100 goto fail;
1101 r = dns_packet_read_uint16(p, &rr->srv.port, NULL);
1102 if (r < 0)
1103 goto fail;
151226ab 1104 r = dns_packet_read_name(p, &rr->srv.name, true, NULL);
9c92ce6d
LP
1105 break;
1106
74b2466e
LP
1107 case DNS_TYPE_PTR:
1108 case DNS_TYPE_NS:
1109 case DNS_TYPE_CNAME:
8ac4e9e1 1110 case DNS_TYPE_DNAME:
151226ab 1111 r = dns_packet_read_name(p, &rr->ptr.name, true, NULL);
74b2466e
LP
1112 break;
1113
1114 case DNS_TYPE_HINFO:
1115 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
1116 if (r < 0)
1117 goto fail;
1118
1119 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
1120 break;
1121
9de3e329 1122 case DNS_TYPE_SPF: /* exactly the same as TXT */
1ccda9b7
LP
1123 case DNS_TYPE_TXT:
1124 if (rdlength <= 0) {
1125 /* RFC 6763, section 6.1 suggests to treat
1126 * empty TXT RRs as equivalent to a TXT record
1127 * with a single empty string. */
0e3434ae 1128
1ccda9b7 1129 r = strv_extend(&rr->txt.strings, "");
2e276efc
ZJS
1130 if (r < 0)
1131 goto fail;
1ccda9b7
LP
1132 } else {
1133 while (p->rindex < offset + rdlength) {
1134 char *s;
2e276efc 1135
1ccda9b7
LP
1136 r = dns_packet_read_string(p, &s, NULL);
1137 if (r < 0)
1138 goto fail;
1139
1140 r = strv_consume(&rr->txt.strings, s);
1141 if (r < 0)
1142 goto fail;
1143 }
6a6fc3df
LP
1144 }
1145
1146 r = 0;
2e276efc 1147 break;
2e276efc 1148
74b2466e 1149 case DNS_TYPE_A:
623a4c97 1150 r = dns_packet_read_blob(p, &rr->a.in_addr, sizeof(struct in_addr), NULL);
74b2466e
LP
1151 break;
1152
1153 case DNS_TYPE_AAAA:
623a4c97 1154 r = dns_packet_read_blob(p, &rr->aaaa.in6_addr, sizeof(struct in6_addr), NULL);
74b2466e
LP
1155 break;
1156
7e8e0422 1157 case DNS_TYPE_SOA:
151226ab 1158 r = dns_packet_read_name(p, &rr->soa.mname, true, NULL);
7e8e0422
LP
1159 if (r < 0)
1160 goto fail;
1161
151226ab 1162 r = dns_packet_read_name(p, &rr->soa.rname, true, NULL);
7e8e0422
LP
1163 if (r < 0)
1164 goto fail;
1165
1166 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
1167 if (r < 0)
1168 goto fail;
1169
1170 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
1171 if (r < 0)
1172 goto fail;
1173
1174 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
1175 if (r < 0)
1176 goto fail;
1177
1178 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
1179 if (r < 0)
1180 goto fail;
1181
1182 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
1183 break;
1184
623a4c97 1185 case DNS_TYPE_MX:
946c7094
ZJS
1186 r = dns_packet_read_uint16(p, &rr->mx.priority, NULL);
1187 if (r < 0)
1188 goto fail;
1189
151226ab 1190 r = dns_packet_read_name(p, &rr->mx.exchange, true, NULL);
946c7094
ZJS
1191 break;
1192
0dae31d4
ZJS
1193 case DNS_TYPE_LOC: {
1194 uint8_t t;
1195 size_t pos;
1196
1197 r = dns_packet_read_uint8(p, &t, &pos);
1198 if (r < 0)
1199 goto fail;
1200
1201 if (t == 0) {
1202 rr->loc.version = t;
1203
1204 r = dns_packet_read_uint8(p, &rr->loc.size, NULL);
1205 if (r < 0)
1206 goto fail;
1207
afbc4f26
ZJS
1208 if (!loc_size_ok(rr->loc.size)) {
1209 r = -EBADMSG;
1210 goto fail;
1211 }
1212
0dae31d4
ZJS
1213 r = dns_packet_read_uint8(p, &rr->loc.horiz_pre, NULL);
1214 if (r < 0)
1215 goto fail;
1216
afbc4f26
ZJS
1217 if (!loc_size_ok(rr->loc.horiz_pre)) {
1218 r = -EBADMSG;
1219 goto fail;
1220 }
1221
0dae31d4
ZJS
1222 r = dns_packet_read_uint8(p, &rr->loc.vert_pre, NULL);
1223 if (r < 0)
1224 goto fail;
1225
afbc4f26
ZJS
1226 if (!loc_size_ok(rr->loc.vert_pre)) {
1227 r = -EBADMSG;
1228 goto fail;
1229 }
1230
0dae31d4
ZJS
1231 r = dns_packet_read_uint32(p, &rr->loc.latitude, NULL);
1232 if (r < 0)
1233 goto fail;
1234
1235 r = dns_packet_read_uint32(p, &rr->loc.longitude, NULL);
1236 if (r < 0)
1237 goto fail;
1238
1239 r = dns_packet_read_uint32(p, &rr->loc.altitude, NULL);
1240 if (r < 0)
1241 goto fail;
1242
1243 break;
1244 } else {
1245 dns_packet_rewind(p, pos);
1246 rr->unparseable = true;
afbc4f26 1247 goto unparseable;
0dae31d4
ZJS
1248 }
1249 }
1250
623a4c97 1251 case DNS_TYPE_SSHFP:
42cc2eeb
LP
1252 r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL);
1253 if (r < 0)
1254 goto fail;
1255
1256 r = dns_packet_read_uint8(p, &rr->sshfp.fptype, NULL);
1257 if (r < 0)
1258 goto fail;
1259
8db0d2f5
ZJS
1260 r = dns_packet_read_public_key(p, rdlength - 2,
1261 &rr->sshfp.key, &rr->sshfp.key_size,
1262 NULL);
1263 break;
1264
1265 case DNS_TYPE_DNSKEY: {
1266 uint16_t flags;
1267 uint8_t proto;
1268
1269 r = dns_packet_read_uint16(p, &flags, NULL);
42cc2eeb
LP
1270 if (r < 0)
1271 goto fail;
1272
8db0d2f5
ZJS
1273 r = dnskey_parse_flags(rr, flags);
1274 if (r < 0)
1275 goto fail;
1276
1277 r = dns_packet_read_uint8(p, &proto, NULL);
1278 if (r < 0)
1279 goto fail;
1280
1281 /* protocol is required to be always 3 */
1282 if (proto != 3) {
1283 r = -EBADMSG;
42cc2eeb
LP
1284 goto fail;
1285 }
1286
8db0d2f5
ZJS
1287 r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);
1288 if (r < 0)
1289 goto fail;
1290
1291 r = dns_packet_read_public_key(p, rdlength - 4,
1292 &rr->dnskey.key, &rr->dnskey.key_size,
1293 NULL);
42cc2eeb 1294 break;
8db0d2f5 1295 }
42cc2eeb 1296
151226ab
ZJS
1297 case DNS_TYPE_RRSIG:
1298 r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL);
1299 if (r < 0)
1300 goto fail;
1301
1302 r = dns_packet_read_uint8(p, &rr->rrsig.algorithm, NULL);
1303 if (r < 0)
1304 goto fail;
1305
1306 r = dns_packet_read_uint8(p, &rr->rrsig.labels, NULL);
1307 if (r < 0)
1308 goto fail;
1309
1310 r = dns_packet_read_uint32(p, &rr->rrsig.original_ttl, NULL);
1311 if (r < 0)
1312 goto fail;
1313
1314 r = dns_packet_read_uint32(p, &rr->rrsig.expiration, NULL);
1315 if (r < 0)
1316 goto fail;
1317
1318 r = dns_packet_read_uint32(p, &rr->rrsig.inception, NULL);
1319 if (r < 0)
1320 goto fail;
1321
1322 r = dns_packet_read_uint16(p, &rr->rrsig.key_tag, NULL);
1323 if (r < 0)
1324 goto fail;
1325
1326 r = dns_packet_read_name(p, &rr->rrsig.signer, false, NULL);
1327 if (r < 0)
1328 goto fail;
1329
1330 r = dns_packet_read_public_key(p, offset + rdlength - p->rindex,
1331 &rr->rrsig.signature, &rr->rrsig.signature_size,
1332 NULL);
1333 break;
1334
74b2466e 1335 default:
afbc4f26 1336 unparseable:
74b2466e
LP
1337 r = dns_packet_read(p, rdlength, &d, NULL);
1338 if (r < 0)
1339 goto fail;
1340
1341 rr->generic.data = memdup(d, rdlength);
1342 if (!rr->generic.data) {
1343 r = -ENOMEM;
1344 goto fail;
1345 }
1346
1347 rr->generic.size = rdlength;
1348 break;
1349 }
1350 if (r < 0)
1351 goto fail;
1352 if (p->rindex != offset + rdlength) {
1353 r = -EBADMSG;
1354 goto fail;
1355 }
1356
1357 *ret = rr;
1358 rr = NULL;
1359
1360 if (start)
1361 *start = saved_rindex;
1362
1363 return 0;
1364fail:
1365 dns_packet_rewind(p, saved_rindex);
1366 return r;
1367}
1368
faa133f3
LP
1369int dns_packet_extract(DnsPacket *p) {
1370 _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
1371 _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
1372 size_t saved_rindex;
1373 unsigned n, i;
74b2466e
LP
1374 int r;
1375
a4076574
LP
1376 if (p->extracted)
1377 return 0;
1378
faa133f3 1379 saved_rindex = p->rindex;
322345fd
LP
1380 dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
1381
3cb10d3a 1382 n = DNS_PACKET_QDCOUNT(p);
faa133f3
LP
1383 if (n > 0) {
1384 question = dns_question_new(n);
1385 if (!question) {
1386 r = -ENOMEM;
1387 goto finish;
1388 }
74b2466e 1389
faa133f3
LP
1390 for (i = 0; i < n; i++) {
1391 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
74b2466e 1392
faa133f3
LP
1393 r = dns_packet_read_key(p, &key, NULL);
1394 if (r < 0)
1395 goto finish;
74b2466e 1396
faa133f3
LP
1397 r = dns_question_add(question, key);
1398 if (r < 0)
1399 goto finish;
1400 }
1401 }
322345fd 1402
faa133f3
LP
1403 n = DNS_PACKET_RRCOUNT(p);
1404 if (n > 0) {
1405 answer = dns_answer_new(n);
1406 if (!answer) {
1407 r = -ENOMEM;
1408 goto finish;
1409 }
322345fd 1410
faa133f3
LP
1411 for (i = 0; i < n; i++) {
1412 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
322345fd 1413
faa133f3
LP
1414 r = dns_packet_read_rr(p, &rr, NULL);
1415 if (r < 0)
1416 goto finish;
322345fd 1417
faa133f3
LP
1418 r = dns_answer_add(answer, rr);
1419 if (r < 0)
1420 goto finish;
1421 }
322345fd
LP
1422 }
1423
faa133f3
LP
1424 p->question = question;
1425 question = NULL;
322345fd 1426
faa133f3
LP
1427 p->answer = answer;
1428 answer = NULL;
322345fd 1429
a4076574
LP
1430 p->extracted = true;
1431
faa133f3 1432 r = 0;
322345fd
LP
1433
1434finish:
1435 p->rindex = saved_rindex;
1436 return r;
1437}
1438
74b2466e
LP
1439static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
1440 [DNS_RCODE_SUCCESS] = "SUCCESS",
1441 [DNS_RCODE_FORMERR] = "FORMERR",
1442 [DNS_RCODE_SERVFAIL] = "SERVFAIL",
1443 [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
1444 [DNS_RCODE_NOTIMP] = "NOTIMP",
1445 [DNS_RCODE_REFUSED] = "REFUSED",
1446 [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
1447 [DNS_RCODE_YXRRSET] = "YRRSET",
1448 [DNS_RCODE_NXRRSET] = "NXRRSET",
1449 [DNS_RCODE_NOTAUTH] = "NOTAUTH",
1450 [DNS_RCODE_NOTZONE] = "NOTZONE",
1451 [DNS_RCODE_BADVERS] = "BADVERS",
1452 [DNS_RCODE_BADKEY] = "BADKEY",
1453 [DNS_RCODE_BADTIME] = "BADTIME",
1454 [DNS_RCODE_BADMODE] = "BADMODE",
1455 [DNS_RCODE_BADNAME] = "BADNAME",
1456 [DNS_RCODE_BADALG] = "BADALG",
1457 [DNS_RCODE_BADTRUNC] = "BADTRUNC",
1458};
1459DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
1716f6dc
LP
1460
1461static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
1462 [DNS_PROTOCOL_DNS] = "dns",
1463 [DNS_PROTOCOL_MDNS] = "mdns",
1464 [DNS_PROTOCOL_LLMNR] = "llmnr",
1465};
1466DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);
ff3d6560
ZJS
1467
1468static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = {
1469 [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5",
1470 [DNSSEC_ALGORITHM_DH] = "DH",
1471 [DNSSEC_ALGORITHM_DSA] = "DSA",
1472 [DNSSEC_ALGORITHM_ECC] = "ECC",
1473 [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1",
1474 [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT",
1475 [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS",
1476 [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID",
1477};
1478DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int);