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