chiark / gitweb /
resolved: most DNS servers can't handle more than one question per packet, hence...
[elogind.git] / src / resolve / resolved-dns-packet.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 "utf8.h"
23 #include "util.h"
24 #include "resolved-dns-domain.h"
25 #include "resolved-dns-packet.h"
26
27 int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
28         DnsPacket *p;
29         size_t a;
30
31         assert(ret);
32
33         if (mtu <= 0)
34                 a = DNS_PACKET_SIZE_START;
35         else
36                 a = mtu;
37
38         if (a < DNS_PACKET_HEADER_SIZE)
39                 a = DNS_PACKET_HEADER_SIZE;
40
41         /* round up to next page size */
42         a = PAGE_ALIGN(ALIGN(sizeof(DnsPacket)) + a) - ALIGN(sizeof(DnsPacket));
43
44         /* make sure we never allocate more than useful */
45         if (a > DNS_PACKET_SIZE_MAX)
46                 a = DNS_PACKET_SIZE_MAX;
47
48         p = malloc0(ALIGN(sizeof(DnsPacket)) + a);
49         if (!p)
50                 return -ENOMEM;
51
52         p->size = p->rindex = DNS_PACKET_HEADER_SIZE;
53         p->allocated = a;
54         p->protocol = protocol;
55         p->n_ref = 1;
56
57         *ret = p;
58
59         return 0;
60 }
61
62 int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {
63         DnsPacket *p;
64         DnsPacketHeader *h;
65         int r;
66
67         assert(ret);
68
69         r = dns_packet_new(&p, protocol, mtu);
70         if (r < 0)
71                 return r;
72
73         h = DNS_PACKET_HEADER(p);
74
75         if (protocol == DNS_PROTOCOL_DNS)
76                 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 1, 0, 0, 0, 0)); /* ask for recursion */
77         else
78                 h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0, 0, 0, 0, 0, 0, 0, 0, 0));
79
80         *ret = p;
81         return 0;
82 }
83
84 DnsPacket *dns_packet_ref(DnsPacket *p) {
85
86         if (!p)
87                 return NULL;
88
89         assert(p->n_ref > 0);
90         p->n_ref++;
91         return p;
92 }
93
94 static void dns_packet_free(DnsPacket *p) {
95         char *s;
96
97         assert(p);
98
99         dns_question_unref(p->question);
100         dns_answer_unref(p->answer);
101
102         while ((s = hashmap_steal_first_key(p->names)))
103                 free(s);
104         hashmap_free(p->names);
105
106         free(p->_data);
107         free(p);
108 }
109
110 DnsPacket *dns_packet_unref(DnsPacket *p) {
111         if (!p)
112                 return NULL;
113
114         assert(p->n_ref > 0);
115
116         if (p->n_ref == 1)
117                 dns_packet_free(p);
118         else
119                 p->n_ref--;
120
121         return NULL;
122 }
123
124 int dns_packet_validate(DnsPacket *p) {
125         assert(p);
126
127         if (p->size < DNS_PACKET_HEADER_SIZE)
128                 return -EBADMSG;
129
130         if (p->size > DNS_PACKET_SIZE_MAX)
131                 return -EBADMSG;
132
133         return 0;
134 }
135
136 int dns_packet_validate_reply(DnsPacket *p) {
137         int r;
138
139         assert(p);
140
141         r = dns_packet_validate(p);
142         if (r < 0)
143                 return r;
144
145         if (DNS_PACKET_QR(p) == 0)
146                 return -EBADMSG;
147
148         if (DNS_PACKET_OPCODE(p) != 0)
149                 return -EBADMSG;
150
151         return 0;
152 }
153
154 static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start) {
155         assert(p);
156
157         if (p->size + add > p->allocated) {
158                 size_t a;
159
160                 a = PAGE_ALIGN((p->size + add) * 2);
161                 if (a > DNS_PACKET_SIZE_MAX)
162                         a = DNS_PACKET_SIZE_MAX;
163
164                 if (p->size + add > a)
165                         return -EMSGSIZE;
166
167                 if (p->_data) {
168                         void *d;
169
170                         d = realloc(p->_data, a);
171                         if (!d)
172                                 return -ENOMEM;
173
174                         p->_data = d;
175                 } else {
176                         p->_data = malloc(a);
177                         if (!p->_data)
178                                 return -ENOMEM;
179
180                         memcpy(p->_data, (uint8_t*) p + ALIGN(sizeof(DnsPacket)), p->size);
181                         memzero((uint8_t*) p->_data + p->size, a - p->size);
182                 }
183
184                 p->allocated = a;
185         }
186
187         if (start)
188                 *start = p->size;
189
190         if (ret)
191                 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->size;
192
193         p->size += add;
194         return 0;
195 }
196
197 static void dns_packet_truncate(DnsPacket *p, size_t sz) {
198         Iterator i;
199         char *s;
200         void *n;
201
202         assert(p);
203
204         if (p->size <= sz)
205                 return;
206
207         HASHMAP_FOREACH_KEY(s, n, p->names, i) {
208
209                 if (PTR_TO_SIZE(n) < sz)
210                         continue;
211
212                 hashmap_remove(p->names, s);
213                 free(s);
214         }
215
216         p->size = sz;
217 }
218
219 int dns_packet_append_uint8(DnsPacket *p, uint8_t v, size_t *start) {
220         void *d;
221         int r;
222
223         assert(p);
224
225         r = dns_packet_extend(p, sizeof(uint8_t), &d, start);
226         if (r < 0)
227                 return r;
228
229         ((uint8_t*) d)[0] = v;
230
231         return 0;
232 }
233
234 int dns_packet_append_uint16(DnsPacket *p, uint16_t v, size_t *start) {
235         void *d;
236         int r;
237
238         assert(p);
239
240         r = dns_packet_extend(p, sizeof(uint16_t), &d, start);
241         if (r < 0)
242                 return r;
243
244         ((uint8_t*) d)[0] = (uint8_t) (v >> 8);
245         ((uint8_t*) d)[1] = (uint8_t) (v & 255);
246
247         return 0;
248 }
249
250 int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) {
251         void *d;
252         size_t l;
253         int r;
254
255         assert(p);
256         assert(s);
257
258         l = strlen(s);
259         if (l > 255)
260                 return -E2BIG;
261
262         r = dns_packet_extend(p, 1 + l, &d, start);
263         if (r < 0)
264                 return r;
265
266         ((uint8_t*) d)[0] = (uint8_t) l;
267         memcpy(((uint8_t*) d) + 1, s, l);
268
269         return 0;
270 }
271
272 int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) {
273         void *w;
274         int r;
275
276         assert(p);
277         assert(d);
278
279         if (l > DNS_LABEL_MAX)
280                 return -E2BIG;
281
282         r = dns_packet_extend(p, 1 + l, &w, start);
283         if (r < 0)
284                 return r;
285
286         ((uint8_t*) w)[0] = (uint8_t) l;
287         memcpy(((uint8_t*) w) + 1, d, l);
288
289         return 0;
290 }
291
292 int dns_packet_append_name(DnsPacket *p, const char *name, size_t *start) {
293         size_t saved_size;
294         int r;
295
296         assert(p);
297         assert(name);
298
299         saved_size = p->size;
300
301         while (*name) {
302                 _cleanup_free_ char *s = NULL;
303                 char label[DNS_LABEL_MAX];
304                 size_t n;
305
306                 n = PTR_TO_SIZE(hashmap_get(p->names, name));
307                 if (n > 0) {
308                         assert(n < p->size);
309
310                         if (n < 0x4000) {
311                                 r = dns_packet_append_uint16(p, 0xC000 | n, NULL);
312                                 if (r < 0)
313                                         goto fail;
314
315                                 goto done;
316                         }
317                 }
318
319                 s = strdup(name);
320                 if (!s) {
321                         r = -ENOMEM;
322                         goto fail;
323                 }
324
325                 r = dns_label_unescape(&name, label, sizeof(label));
326                 if (r < 0)
327                         goto fail;
328
329                 r = dns_packet_append_label(p, label, r, &n);
330                 if (r < 0)
331                         goto fail;
332
333                 r = hashmap_ensure_allocated(&p->names, dns_name_hash_func, dns_name_compare_func);
334                 if (r < 0)
335                         goto fail;
336
337                 r = hashmap_put(p->names, s, SIZE_TO_PTR(n));
338                 if (r < 0)
339                         goto fail;
340
341                 s = NULL;
342         }
343
344         r = dns_packet_append_uint8(p, 0, NULL);
345         if (r < 0)
346                 return r;
347
348 done:
349         if (start)
350                 *start = saved_size;
351
352         return 0;
353
354 fail:
355         dns_packet_truncate(p, saved_size);
356         return r;
357 }
358
359 int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) {
360         size_t saved_size;
361         int r;
362
363         assert(p);
364         assert(k);
365
366         saved_size = p->size;
367
368         r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), NULL);
369         if (r < 0)
370                 goto fail;
371
372         r = dns_packet_append_uint16(p, k->type, NULL);
373         if (r < 0)
374                 goto fail;
375
376         r = dns_packet_append_uint16(p, k->class, NULL);
377         if (r < 0)
378                 goto fail;
379
380         if (start)
381                 *start = saved_size;
382
383         return 0;
384
385 fail:
386         dns_packet_truncate(p, saved_size);
387         return r;
388 }
389
390 int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) {
391         assert(p);
392
393         if (p->rindex + sz > p->size)
394                 return -EMSGSIZE;
395
396         if (ret)
397                 *ret = (uint8_t*) DNS_PACKET_DATA(p) + p->rindex;
398
399         if (start)
400                 *start = p->rindex;
401
402         p->rindex += sz;
403         return 0;
404 }
405
406 void dns_packet_rewind(DnsPacket *p, size_t idx) {
407         assert(p);
408         assert(idx <= p->size);
409         assert(idx >= DNS_PACKET_HEADER_SIZE);
410
411         p->rindex = idx;
412 }
413
414 int dns_packet_read_uint8(DnsPacket *p, uint8_t *ret, size_t *start) {
415         const void *d;
416         int r;
417
418         assert(p);
419
420         r = dns_packet_read(p, sizeof(uint8_t), &d, start);
421         if (r < 0)
422                 return r;
423
424         *ret = ((uint8_t*) d)[0];
425         return 0;
426 }
427
428 int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) {
429         const void *d;
430         int r;
431
432         assert(p);
433
434         r = dns_packet_read(p, sizeof(uint16_t), &d, start);
435         if (r < 0)
436                 return r;
437
438         *ret = (((uint16_t) ((uint8_t*) d)[0]) << 8) |
439                 ((uint16_t) ((uint8_t*) d)[1]);
440         return 0;
441 }
442
443 int dns_packet_read_uint32(DnsPacket *p, uint32_t *ret, size_t *start) {
444         const void *d;
445         int r;
446
447         assert(p);
448
449         r = dns_packet_read(p, sizeof(uint32_t), &d, start);
450         if (r < 0)
451                 return r;
452
453         *ret = (((uint32_t) ((uint8_t*) d)[0]) << 24) |
454                (((uint32_t) ((uint8_t*) d)[1]) << 16) |
455                (((uint32_t) ((uint8_t*) d)[2]) << 8) |
456                 ((uint32_t) ((uint8_t*) d)[3]);
457
458         return 0;
459 }
460
461 int dns_packet_read_string(DnsPacket *p, char **ret, size_t *start) {
462         size_t saved_rindex;
463         const void *d;
464         char *t;
465         uint8_t c;
466         int r;
467
468         assert(p);
469
470         saved_rindex = p->rindex;
471
472         r = dns_packet_read_uint8(p, &c, NULL);
473         if (r < 0)
474                 goto fail;
475
476         r = dns_packet_read(p, c, &d, NULL);
477         if (r < 0)
478                 goto fail;
479
480         if (memchr(d, 0, c)) {
481                 r = -EBADMSG;
482                 goto fail;
483         }
484
485         t = strndup(d, c);
486         if (!t) {
487                 r = -ENOMEM;
488                 goto fail;
489         }
490
491         if (!utf8_is_valid(t)) {
492                 free(t);
493                 r = -EBADMSG;
494                 goto fail;
495         }
496
497         *ret = t;
498
499         if (start)
500                 *start = saved_rindex;
501
502         return 0;
503
504 fail:
505         dns_packet_rewind(p, saved_rindex);
506         return r;
507 }
508
509 int dns_packet_read_name(DnsPacket *p, char **_ret, size_t *start) {
510         size_t saved_rindex, after_rindex = 0;
511         _cleanup_free_ char *ret = NULL;
512         size_t n = 0, allocated = 0;
513         bool first = true;
514         int r;
515
516         assert(p);
517         assert(_ret);
518
519         saved_rindex = p->rindex;
520
521         for (;;) {
522                 uint8_t c, d;
523
524                 r = dns_packet_read_uint8(p, &c, NULL);
525                 if (r < 0)
526                         goto fail;
527
528                 if (c == 0)
529                         /* End of name */
530                         break;
531                 else if (c <= 63) {
532                         _cleanup_free_ char *t = NULL;
533                         const char *label;
534
535                         /* Literal label */
536                         r = dns_packet_read(p, c, (const void**) &label, NULL);
537                         if (r < 0)
538                                 goto fail;
539
540                         r = dns_label_escape(label, c, &t);
541                         if (r < 0)
542                                 goto fail;
543
544                         if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) {
545                                 r = -ENOMEM;
546                                 goto fail;
547                         }
548
549                         if (!first)
550                                 ret[n++] = '.';
551                         else
552                                 first = false;
553
554                         memcpy(ret + n, t, c);
555                         n += r;
556                         continue;
557                 } else if ((c & 0xc0) == 0xc0) {
558                         uint16_t ptr;
559
560                         /* Pointer */
561                         r = dns_packet_read_uint8(p, &d, NULL);
562                         if (r < 0)
563                                 goto fail;
564
565                         ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d;
566                         if (ptr < DNS_PACKET_HEADER_SIZE || ptr >= saved_rindex) {
567                                 r = -EBADMSG;
568                                 goto fail;
569                         }
570
571                         if (after_rindex == 0)
572                                 after_rindex = p->rindex;
573
574                         p->rindex = ptr;
575                 } else
576                         goto fail;
577         }
578
579         if (!GREEDY_REALLOC(ret, allocated, n + 1)) {
580                 r = -ENOMEM;
581                 goto fail;
582         }
583
584         ret[n] = 0;
585
586         if (after_rindex != 0)
587                 p->rindex= after_rindex;
588
589         *_ret = ret;
590         ret = NULL;
591
592         if (start)
593                 *start = saved_rindex;
594
595         return 0;
596
597 fail:
598         dns_packet_rewind(p, saved_rindex);
599         return r;
600 }
601
602 int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {
603         _cleanup_free_ char *name = NULL;
604         uint16_t class, type;
605         DnsResourceKey *key;
606         size_t saved_rindex;
607         int r;
608
609         assert(p);
610         assert(ret);
611
612         saved_rindex = p->rindex;
613
614         r = dns_packet_read_name(p, &name, NULL);
615         if (r < 0)
616                 goto fail;
617
618         r = dns_packet_read_uint16(p, &type, NULL);
619         if (r < 0)
620                 goto fail;
621
622         r = dns_packet_read_uint16(p, &class, NULL);
623         if (r < 0)
624                 goto fail;
625
626         key = dns_resource_key_new_consume(class, type, name);
627         if (!key) {
628                 r = -ENOMEM;
629                 goto fail;
630         }
631
632         name = NULL;
633         *ret = key;
634
635         if (start)
636                 *start = saved_rindex;
637
638         return 0;
639 fail:
640         dns_packet_rewind(p, saved_rindex);
641         return r;
642 }
643
644 int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {
645         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
646         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
647         size_t saved_rindex, offset;
648         uint16_t rdlength;
649         const void *d;
650         int r;
651
652         assert(p);
653         assert(ret);
654
655         saved_rindex = p->rindex;
656
657         r = dns_packet_read_key(p, &key, NULL);
658         if (r < 0)
659                 goto fail;
660
661         rr = dns_resource_record_new(key);
662         if (!rr) {
663                 r = -ENOMEM;
664                 goto fail;
665         }
666
667         r = dns_packet_read_uint32(p, &rr->ttl, NULL);
668         if (r < 0)
669                 goto fail;
670
671         r = dns_packet_read_uint16(p, &rdlength, NULL);
672         if (r < 0)
673                 goto fail;
674
675         if (p->rindex + rdlength > p->size) {
676                 r = -EBADMSG;
677                 goto fail;
678         }
679
680         offset = p->rindex;
681
682         switch (rr->key->type) {
683
684         case DNS_TYPE_PTR:
685         case DNS_TYPE_NS:
686         case DNS_TYPE_CNAME:
687                 r = dns_packet_read_name(p, &rr->ptr.name, NULL);
688                 break;
689
690         case DNS_TYPE_HINFO:
691                 r = dns_packet_read_string(p, &rr->hinfo.cpu, NULL);
692                 if (r < 0)
693                         goto fail;
694
695                 r = dns_packet_read_string(p, &rr->hinfo.os, NULL);
696                 break;
697
698         case DNS_TYPE_A:
699                 r = dns_packet_read(p, sizeof(struct in_addr), &d, NULL);
700                 if (r < 0)
701                         goto fail;
702
703                 memcpy(&rr->a.in_addr, d, sizeof(struct in_addr));
704                 break;
705
706         case DNS_TYPE_AAAA:
707                 r = dns_packet_read(p, sizeof(struct in6_addr), &d, NULL);
708                 if (r < 0)
709                         goto fail;
710
711                 memcpy(&rr->aaaa.in6_addr, d, sizeof(struct in6_addr));
712                 break;
713
714         case DNS_TYPE_SOA:
715                 r = dns_packet_read_name(p, &rr->soa.mname, NULL);
716                 if (r < 0)
717                         goto fail;
718
719                 r = dns_packet_read_name(p, &rr->soa.rname, NULL);
720                 if (r < 0)
721                         goto fail;
722
723                 r = dns_packet_read_uint32(p, &rr->soa.serial, NULL);
724                 if (r < 0)
725                         goto fail;
726
727                 r = dns_packet_read_uint32(p, &rr->soa.refresh, NULL);
728                 if (r < 0)
729                         goto fail;
730
731                 r = dns_packet_read_uint32(p, &rr->soa.retry, NULL);
732                 if (r < 0)
733                         goto fail;
734
735                 r = dns_packet_read_uint32(p, &rr->soa.expire, NULL);
736                 if (r < 0)
737                         goto fail;
738
739                 r = dns_packet_read_uint32(p, &rr->soa.minimum, NULL);
740                 break;
741
742         default:
743                 r = dns_packet_read(p, rdlength, &d, NULL);
744                 if (r < 0)
745                         goto fail;
746
747                 rr->generic.data = memdup(d, rdlength);
748                 if (!rr->generic.data) {
749                         r = -ENOMEM;
750                         goto fail;
751                 }
752
753                 rr->generic.size = rdlength;
754                 break;
755         }
756         if (r < 0)
757                 goto fail;
758         if (p->rindex != offset + rdlength) {
759                 r = -EBADMSG;
760                 goto fail;
761         }
762
763         *ret = rr;
764         rr = NULL;
765
766         if (start)
767                 *start = saved_rindex;
768
769         return 0;
770 fail:
771         dns_packet_rewind(p, saved_rindex);
772         return r;
773 }
774
775 int dns_packet_extract(DnsPacket *p) {
776         _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL;
777         _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;
778         size_t saved_rindex;
779         unsigned n, i;
780         int r;
781
782         saved_rindex = p->rindex;
783         dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE);
784
785         n = DNS_PACKET_QDCOUNT(p);
786         if (n > 0) {
787                 question = dns_question_new(n);
788                 if (!question) {
789                         r = -ENOMEM;
790                         goto finish;
791                 }
792
793                 for (i = 0; i < n; i++) {
794                         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
795
796                         r = dns_packet_read_key(p, &key, NULL);
797                         if (r < 0)
798                                 goto finish;
799
800                         r = dns_question_add(question, key);
801                         if (r < 0)
802                                 goto finish;
803                 }
804         }
805
806         n = DNS_PACKET_RRCOUNT(p);
807         if (n > 0) {
808                 answer = dns_answer_new(n);
809                 if (!answer) {
810                         r = -ENOMEM;
811                         goto finish;
812                 }
813
814                 for (i = 0; i < n; i++) {
815                         _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
816
817                         r = dns_packet_read_rr(p, &rr, NULL);
818                         if (r < 0)
819                                 goto finish;
820
821                         r = dns_answer_add(answer, rr);
822                         if (r < 0)
823                                 goto finish;
824                 }
825         }
826
827         p->question = question;
828         question = NULL;
829
830         p->answer = answer;
831         answer = NULL;
832
833         r = 0;
834
835 finish:
836         p->rindex = saved_rindex;
837         return r;
838 }
839
840 static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = {
841         [DNS_RCODE_SUCCESS] = "SUCCESS",
842         [DNS_RCODE_FORMERR] = "FORMERR",
843         [DNS_RCODE_SERVFAIL] = "SERVFAIL",
844         [DNS_RCODE_NXDOMAIN] = "NXDOMAIN",
845         [DNS_RCODE_NOTIMP] = "NOTIMP",
846         [DNS_RCODE_REFUSED] = "REFUSED",
847         [DNS_RCODE_YXDOMAIN] = "YXDOMAIN",
848         [DNS_RCODE_YXRRSET] = "YRRSET",
849         [DNS_RCODE_NXRRSET] = "NXRRSET",
850         [DNS_RCODE_NOTAUTH] = "NOTAUTH",
851         [DNS_RCODE_NOTZONE] = "NOTZONE",
852         [DNS_RCODE_BADVERS] = "BADVERS",
853         [DNS_RCODE_BADKEY] = "BADKEY",
854         [DNS_RCODE_BADTIME] = "BADTIME",
855         [DNS_RCODE_BADMODE] = "BADMODE",
856         [DNS_RCODE_BADNAME] = "BADNAME",
857         [DNS_RCODE_BADALG] = "BADALG",
858         [DNS_RCODE_BADTRUNC] = "BADTRUNC",
859 };
860 DEFINE_STRING_TABLE_LOOKUP(dns_rcode, int);
861
862 static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {
863         [DNS_PROTOCOL_DNS] = "dns",
864         [DNS_PROTOCOL_MDNS] = "mdns",
865         [DNS_PROTOCOL_LLMNR] = "llmnr",
866 };
867 DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol);