1 /**
2  * Parse a DNS resource record contained in a DNS message.
3  *
4  * \param[in] sec section the RR is contained in
5  * \param[in] p the DNS message that contains the resource record
6  * \param[in] eop pointer to end of buffer containing message
7  * \param[in] data pointer to start of resource record
8  * \param[out] rrsz number of wire bytes read from message
9  * \param[out] rr parsed resource record
10  */
11 
12 wdns_res
_wdns_parse_message_rr(unsigned sec,const uint8_t * p,const uint8_t * eop,const uint8_t * data,size_t * rrsz,wdns_rr_t * rr)13 _wdns_parse_message_rr(unsigned sec, const uint8_t *p, const uint8_t *eop, const uint8_t *data,
14 		       size_t *rrsz, wdns_rr_t *rr)
15 {
16 	const uint8_t *src = data;
17 	size_t len;
18 	uint16_t rdlen;
19 	uint8_t domain_name[WDNS_MAXLEN_NAME];
20 	wdns_res res;
21 
22 	/* uncompress name */
23 	res = wdns_unpack_name(p, eop, src, domain_name, &len);
24 	if (res != wdns_res_success)
25 		return (res);
26 
27 	/* copy name */
28 	rr->name.len = len;
29 	rr->name.data = my_malloc(len);
30 	memcpy(rr->name.data, domain_name, len);
31 
32 	/* skip name */
33 	wdns_skip_name(&src, eop);
34 
35 	/* if this is a question RR, then we need 4 more bytes, rrtype (2) + rrclass (2). */
36 	/* if this is a response RR, then we need 10 more bytes, rrtype (2) + rrclass (2) +
37 	 * rrttl (4) + rdlen (2). */
38 	if (src + 4 > eop || (sec != WDNS_MSG_SEC_QUESTION && src + 10 > eop)) {
39 		res = wdns_res_parse_error;
40 		goto err;
41 	}
42 
43 	/* rrtype */
44 	WDNS_BUF_GET16(rr->rrtype, src);
45 
46 	/* rrclass */
47 	WDNS_BUF_GET16(rr->rrclass, src);
48 
49 	/* finished parsing if this is a question RR */
50 	if (sec == WDNS_MSG_SEC_QUESTION) {
51 		rr->rrttl = 0;
52 		rr->rdata = NULL;
53 		*rrsz = (src - data);
54 		return (wdns_res_success);
55 	}
56 
57 	/* rrttl */
58 	WDNS_BUF_GET32(rr->rrttl, src);
59 
60 	/* rdlen */
61 	WDNS_BUF_GET16(rdlen, src);
62 
63 	/* rdlen overflow check */
64 	if (src + rdlen > eop) {
65 		res = wdns_res_overflow;
66 		goto err;
67 	}
68 
69 	/* parse and copy the rdata */
70 	res = _wdns_parse_rdata(rr, p, eop, src, rdlen);
71 	if (res != wdns_res_success)
72 		goto err;
73 
74 	/* calculate the number of wire bytes that were read from the message */
75 	*rrsz = (src - data) + rdlen;
76 
77 	return (wdns_res_success);
78 
79 err:
80 	my_free(rr->name.data);
81 	return (res);
82 }
83