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