Blob


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