1 /* $OpenBSD: unpack_dns.c,v 1.1 2018/01/06 07:57:53 sunil Exp $ */
4 * Copyright (c) 2011-2014 Eric Faurot <eric@faurot.net>
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.
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.
19 #include <arpa/inet.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);
33 unpack_init(struct unpack *unpack, const char *buf, size_t len)
42 unpack_header(struct unpack *p, struct dns_header *h)
44 if (unpack_data(p, h, HFIXEDSZ) == -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);
57 unpack_query(struct unpack *p, struct dns_query *q)
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);
67 unpack_rr(struct unpack *p, struct dns_rr *rr)
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);
81 if (p->len - p->offset < rdlen) {
86 save_offset = p->offset;
88 switch (rr->rr_type) {
91 unpack_dname(p, rr->rr.cname.cname, sizeof(rr->rr.cname.cname));
95 unpack_u16(p, &rr->rr.mx.preference);
96 unpack_dname(p, rr->rr.mx.exchange, sizeof(rr->rr.mx.exchange));
100 unpack_dname(p, rr->rr.ns.nsname, sizeof(rr->rr.ns.nsname));
104 unpack_dname(p, rr->rr.ptr.ptrname, sizeof(rr->rr.ptr.ptrname));
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);
118 if (rr->rr_class != C_IN)
120 unpack_inaddr(p, &rr->rr.in_a.addr);
124 if (rr->rr_class != C_IN)
126 unpack_in6addr(p, &rr->rr.in_aaaa.addr6);
130 rr->rr.other.rdata = p->buf + p->offset;
131 rr->rr.other.rdlen = rdlen;
138 /* make sure that the advertised rdlen is really ok */
139 if (p->offset - save_offset != rdlen)
142 return (p->err) ? (-1) : (0);
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;
156 end = start = offset;
158 for (; (n = data[offset]); ) {
159 if ((n & 0xc0) == 0xc0) {
160 if (offset + 2 > len)
162 ptr = 256 * (n & ~0xc0) + data[offset + 1];
165 if (end < offset + 2)
167 offset = start = ptr;
170 if (offset + n + 1 > len)
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);
185 if (end < offset + 1)
188 if (dst != NULL && max != 0)
196 print_dname(const char *_dname, char *buf, size_t max)
198 const unsigned char *dname = _dname;
202 if (_dname[0] == 0) {
203 (void)strlcpy(buf, ".", max);
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;
226 unpack_data(struct unpack *p, void *data, size_t len)
231 if (p->len - p->offset < len) {
232 p->err = "too short";
236 memmove(data, p->buf + p->offset, len);
243 unpack_u16(struct unpack *p, uint16_t *u16)
245 if (unpack_data(p, u16, 2) == -1)
254 unpack_u32(struct unpack *p, uint32_t *u32)
256 if (unpack_data(p, u32, 4) == -1)
265 unpack_inaddr(struct unpack *p, struct in_addr *a)
267 return (unpack_data(p, a, 4));
271 unpack_in6addr(struct unpack *p, struct in6_addr *a6)
273 return (unpack_data(p, a6, 16));
277 unpack_dname(struct unpack *p, char *dst, size_t max)
284 e = dname_expand(p->buf, p->len, p->offset, &p->offset, dst, max);
286 p->err = "bad domain name";
289 if (e < 0 || e > MAXDNAME) {
290 p->err = "domain name too long";