1 f1509490 2022-03-20 martijn /* $OpenBSD: unpack_dns.c,v 1.1 2018/01/06 07:57:53 sunil Exp $ */
4 f1509490 2022-03-20 martijn * Copyright (c) 2011-2014 Eric Faurot <eric@faurot.net>
6 f1509490 2022-03-20 martijn * Permission to use, copy, modify, and distribute this software for any
7 f1509490 2022-03-20 martijn * purpose with or without fee is hereby granted, provided that the above
8 f1509490 2022-03-20 martijn * copyright notice and this permission notice appear in all copies.
10 f1509490 2022-03-20 martijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 f1509490 2022-03-20 martijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 f1509490 2022-03-20 martijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 f1509490 2022-03-20 martijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 f1509490 2022-03-20 martijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 f1509490 2022-03-20 martijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 f1509490 2022-03-20 martijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 f1509490 2022-03-20 martijn #include <arpa/inet.h>
21 f1509490 2022-03-20 martijn #include <string.h>
23 f1509490 2022-03-20 martijn #include "unpack_dns.h"
25 f1509490 2022-03-20 martijn static int unpack_data(struct unpack *, void *, size_t);
26 f1509490 2022-03-20 martijn static int unpack_u16(struct unpack *, uint16_t *);
27 f1509490 2022-03-20 martijn static int unpack_u32(struct unpack *, uint32_t *);
28 f1509490 2022-03-20 martijn static int unpack_inaddr(struct unpack *, struct in_addr *);
29 f1509490 2022-03-20 martijn static int unpack_in6addr(struct unpack *, struct in6_addr *);
30 f1509490 2022-03-20 martijn static int unpack_dname(struct unpack *, char *, size_t);
33 f1509490 2022-03-20 martijn unpack_init(struct unpack *unpack, const char *buf, size_t len)
35 f1509490 2022-03-20 martijn unpack->buf = buf;
36 f1509490 2022-03-20 martijn unpack->len = len;
37 f1509490 2022-03-20 martijn unpack->offset = 0;
38 f1509490 2022-03-20 martijn unpack->err = NULL;
42 f1509490 2022-03-20 martijn unpack_header(struct unpack *p, struct dns_header *h)
44 f1509490 2022-03-20 martijn if (unpack_data(p, h, HFIXEDSZ) == -1)
45 f1509490 2022-03-20 martijn return (-1);
47 f1509490 2022-03-20 martijn h->flags = ntohs(h->flags);
48 f1509490 2022-03-20 martijn h->qdcount = ntohs(h->qdcount);
49 f1509490 2022-03-20 martijn h->ancount = ntohs(h->ancount);
50 f1509490 2022-03-20 martijn h->nscount = ntohs(h->nscount);
51 f1509490 2022-03-20 martijn h->arcount = ntohs(h->arcount);
53 f1509490 2022-03-20 martijn return (0);
57 f1509490 2022-03-20 martijn unpack_query(struct unpack *p, struct dns_query *q)
59 f1509490 2022-03-20 martijn unpack_dname(p, q->q_dname, sizeof(q->q_dname));
60 f1509490 2022-03-20 martijn unpack_u16(p, &q->q_type);
61 f1509490 2022-03-20 martijn unpack_u16(p, &q->q_class);
63 f1509490 2022-03-20 martijn return (p->err) ? (-1) : (0);
67 f1509490 2022-03-20 martijn unpack_rr(struct unpack *p, struct dns_rr *rr)
69 f1509490 2022-03-20 martijn uint16_t rdlen;
70 f1509490 2022-03-20 martijn size_t save_offset;
72 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr_dname, sizeof(rr->rr_dname));
73 f1509490 2022-03-20 martijn unpack_u16(p, &rr->rr_type);
74 f1509490 2022-03-20 martijn unpack_u16(p, &rr->rr_class);
75 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr_ttl);
76 f1509490 2022-03-20 martijn unpack_u16(p, &rdlen);
78 f1509490 2022-03-20 martijn if (p->err)
79 f1509490 2022-03-20 martijn return (-1);
81 f1509490 2022-03-20 martijn if (p->len - p->offset < rdlen) {
82 f1509490 2022-03-20 martijn p->err = "too short";
83 f1509490 2022-03-20 martijn return (-1);
86 f1509490 2022-03-20 martijn save_offset = p->offset;
88 f1509490 2022-03-20 martijn switch (rr->rr_type) {
90 f1509490 2022-03-20 martijn case T_CNAME:
91 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
94 f1509490 2022-03-20 martijn case T_MX:
95 f1509490 2022-03-20 martijn unpack_u16(p, &rr->rr.mx.preference);
96 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
99 f1509490 2022-03-20 martijn case T_NS:
100 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
103 f1509490 2022-03-20 martijn case T_PTR:
104 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
107 f1509490 2022-03-20 martijn case T_SOA:
108 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.soa.mname, sizeof(rr->rr.soa.mname));
109 f1509490 2022-03-20 martijn unpack_dname(p, rr->rr.soa.rname, sizeof(rr->rr.soa.rname));
110 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr.soa.serial);
111 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr.soa.refresh);
112 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr.soa.retry);
113 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr.soa.expire);
114 f1509490 2022-03-20 martijn unpack_u32(p, &rr->rr.soa.minimum);
117 f1509490 2022-03-20 martijn case T_A:
118 f1509490 2022-03-20 martijn if (rr->rr_class != C_IN)
119 f1509490 2022-03-20 martijn goto other;
120 f1509490 2022-03-20 martijn unpack_inaddr(p, &rr->rr.in_a.addr);
123 f1509490 2022-03-20 martijn case T_AAAA:
124 f1509490 2022-03-20 martijn if (rr->rr_class != C_IN)
125 f1509490 2022-03-20 martijn goto other;
126 f1509490 2022-03-20 martijn unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
128 f1509490 2022-03-20 martijn default:
130 f1509490 2022-03-20 martijn rr->rr.other.rdata = p->buf + p->offset;
131 f1509490 2022-03-20 martijn rr->rr.other.rdlen = rdlen;
132 f1509490 2022-03-20 martijn p->offset += rdlen;
135 f1509490 2022-03-20 martijn if (p->err)
136 f1509490 2022-03-20 martijn return (-1);
138 f1509490 2022-03-20 martijn /* make sure that the advertised rdlen is really ok */
139 f1509490 2022-03-20 martijn if (p->offset - save_offset != rdlen)
140 f1509490 2022-03-20 martijn p->err = "bad dlen";
142 f1509490 2022-03-20 martijn return (p->err) ? (-1) : (0);
146 f1509490 2022-03-20 martijn dname_expand(const unsigned char *data, size_t len, size_t offset,
147 f1509490 2022-03-20 martijn size_t *newoffset, char *dst, size_t max)
149 f1509490 2022-03-20 martijn size_t n, count, end, ptr, start;
150 f1509490 2022-03-20 martijn ssize_t res;
152 f1509490 2022-03-20 martijn if (offset >= len)
153 f1509490 2022-03-20 martijn return (-1);
155 f1509490 2022-03-20 martijn res = 0;
156 f1509490 2022-03-20 martijn end = start = offset;
158 f1509490 2022-03-20 martijn for (; (n = data[offset]); ) {
159 f1509490 2022-03-20 martijn if ((n & 0xc0) == 0xc0) {
160 f1509490 2022-03-20 martijn if (offset + 2 > len)
161 f1509490 2022-03-20 martijn return (-1);
162 f1509490 2022-03-20 martijn ptr = 256 * (n & ~0xc0) + data[offset + 1];
163 f1509490 2022-03-20 martijn if (ptr >= start)
164 f1509490 2022-03-20 martijn return (-1);
165 f1509490 2022-03-20 martijn if (end < offset + 2)
166 f1509490 2022-03-20 martijn end = offset + 2;
167 f1509490 2022-03-20 martijn offset = start = ptr;
168 f1509490 2022-03-20 martijn continue;
170 f1509490 2022-03-20 martijn if (offset + n + 1 > len)
171 f1509490 2022-03-20 martijn return (-1);
173 f1509490 2022-03-20 martijn /* copy n + at offset+1 */
174 f1509490 2022-03-20 martijn if (dst != NULL && max != 0) {
175 f1509490 2022-03-20 martijn count = (max < n + 1) ? (max) : (n + 1);
176 f1509490 2022-03-20 martijn memmove(dst, data + offset, count);
177 f1509490 2022-03-20 martijn dst += count;
178 f1509490 2022-03-20 martijn max -= count;
180 f1509490 2022-03-20 martijn res += n + 1;
181 f1509490 2022-03-20 martijn offset += n + 1;
182 f1509490 2022-03-20 martijn if (end < offset)
183 f1509490 2022-03-20 martijn end = offset;
185 f1509490 2022-03-20 martijn if (end < offset + 1)
186 f1509490 2022-03-20 martijn end = offset + 1;
188 f1509490 2022-03-20 martijn if (dst != NULL && max != 0)
189 f1509490 2022-03-20 martijn dst[0] = 0;
190 f1509490 2022-03-20 martijn if (newoffset)
191 f1509490 2022-03-20 martijn *newoffset = end;
192 f1509490 2022-03-20 martijn return (res + 1);
196 f1509490 2022-03-20 martijn print_dname(const char *_dname, char *buf, size_t max)
198 f1509490 2022-03-20 martijn const unsigned char *dname = _dname;
199 f1509490 2022-03-20 martijn char *res;
200 f1509490 2022-03-20 martijn size_t left, count;
202 f1509490 2022-03-20 martijn if (_dname[0] == 0) {
203 f1509490 2022-03-20 martijn (void)strlcpy(buf, ".", max);
204 f1509490 2022-03-20 martijn return buf;
207 f1509490 2022-03-20 martijn res = buf;
208 f1509490 2022-03-20 martijn left = max - 1;
209 f1509490 2022-03-20 martijn for (; dname[0] && left;) {
210 f1509490 2022-03-20 martijn count = (dname[0] < (left - 1)) ? dname[0] : (left - 1);
211 f1509490 2022-03-20 martijn memmove(buf, dname + 1, count);
212 f1509490 2022-03-20 martijn dname += dname[0] + 1;
213 f1509490 2022-03-20 martijn left -= count;
214 f1509490 2022-03-20 martijn buf += count;
215 f1509490 2022-03-20 martijn if (left) {
216 f1509490 2022-03-20 martijn left -= 1;
217 f1509490 2022-03-20 martijn *buf++ = '.';
220 f1509490 2022-03-20 martijn buf[0] = 0;
222 f1509490 2022-03-20 martijn return (res);
225 f1509490 2022-03-20 martijn static int
226 f1509490 2022-03-20 martijn unpack_data(struct unpack *p, void *data, size_t len)
228 f1509490 2022-03-20 martijn if (p->err)
229 f1509490 2022-03-20 martijn return (-1);
231 f1509490 2022-03-20 martijn if (p->len - p->offset < len) {
232 f1509490 2022-03-20 martijn p->err = "too short";
233 f1509490 2022-03-20 martijn return (-1);
236 f1509490 2022-03-20 martijn memmove(data, p->buf + p->offset, len);
237 f1509490 2022-03-20 martijn p->offset += len;
239 f1509490 2022-03-20 martijn return (0);
242 f1509490 2022-03-20 martijn static int
243 f1509490 2022-03-20 martijn unpack_u16(struct unpack *p, uint16_t *u16)
245 f1509490 2022-03-20 martijn if (unpack_data(p, u16, 2) == -1)
246 f1509490 2022-03-20 martijn return (-1);
248 f1509490 2022-03-20 martijn *u16 = ntohs(*u16);
250 f1509490 2022-03-20 martijn return (0);
253 f1509490 2022-03-20 martijn static int
254 f1509490 2022-03-20 martijn unpack_u32(struct unpack *p, uint32_t *u32)
256 f1509490 2022-03-20 martijn if (unpack_data(p, u32, 4) == -1)
257 f1509490 2022-03-20 martijn return (-1);
259 f1509490 2022-03-20 martijn *u32 = ntohl(*u32);
261 f1509490 2022-03-20 martijn return (0);
264 f1509490 2022-03-20 martijn static int
265 f1509490 2022-03-20 martijn unpack_inaddr(struct unpack *p, struct in_addr *a)
267 f1509490 2022-03-20 martijn return (unpack_data(p, a, 4));
270 f1509490 2022-03-20 martijn static int
271 f1509490 2022-03-20 martijn unpack_in6addr(struct unpack *p, struct in6_addr *a6)
273 f1509490 2022-03-20 martijn return (unpack_data(p, a6, 16));
276 f1509490 2022-03-20 martijn static int
277 f1509490 2022-03-20 martijn unpack_dname(struct unpack *p, char *dst, size_t max)
279 f1509490 2022-03-20 martijn ssize_t e;
281 f1509490 2022-03-20 martijn if (p->err)
282 f1509490 2022-03-20 martijn return (-1);
284 f1509490 2022-03-20 martijn e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
285 f1509490 2022-03-20 martijn if (e == -1) {
286 f1509490 2022-03-20 martijn p->err = "bad domain name";
287 f1509490 2022-03-20 martijn return (-1);
289 f1509490 2022-03-20 martijn if (e < 0 || e > MAXDNAME) {
290 f1509490 2022-03-20 martijn p->err = "domain name too long";
291 f1509490 2022-03-20 martijn return (-1);
294 f1509490 2022-03-20 martijn return (0);