2 /* Copyright 2020 by <danny.sonnenschein@platynum.ch>
4 * Permission to use, copy, modify, and distribute this
5 * software and its documentation for any purpose and without
6 * fee is hereby granted, provided that the above copyright
7 * notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting
9 * documentation, and that the name of M.I.T. not be used in
10 * advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.
12 * M.I.T. makes no representations about the suitability of
13 * this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
17 #include "ares_setup.h"
19 #ifdef HAVE_NETINET_IN_H
20 # include <netinet/in.h>
25 #ifdef HAVE_ARPA_INET_H
26 # include <arpa/inet.h>
29 #include "ares_nameser.h"
37 #include "ares_data.h"
38 #include "ares_private.h"
41 ares_parse_caa_reply (const unsigned char *abuf, int alen,
42 struct ares_caa_reply **caa_out)
44 unsigned int qdcount, ancount, i;
45 const unsigned char *aptr;
46 const unsigned char *strptr;
47 int status, rr_type, rr_class, rr_len;
49 char *hostname = NULL, *rr_name = NULL;
50 struct ares_caa_reply *caa_head = NULL;
51 struct ares_caa_reply *caa_last = NULL;
52 struct ares_caa_reply *caa_curr;
54 /* Set *caa_out to NULL for all failure cases. */
57 /* Give up if abuf doesn't have room for a header. */
61 /* Fetch the question and answer count from the header. */
62 qdcount = DNS_HEADER_QDCOUNT (abuf);
63 ancount = DNS_HEADER_ANCOUNT (abuf);
69 /* Expand the name from the question, and skip past the question. */
70 aptr = abuf + HFIXEDSZ;
71 status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
72 if (status != ARES_SUCCESS)
75 if (aptr + len + QFIXEDSZ > abuf + alen)
80 aptr += len + QFIXEDSZ;
82 /* Examine each answer resource record (RR) in turn. */
83 for (i = 0; i < ancount; i++)
85 /* Decode the RR up to the data field. */
86 status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
87 if (status != ARES_SUCCESS)
92 if (aptr + RRFIXEDSZ > abuf + alen)
94 status = ARES_EBADRESP;
97 rr_type = DNS_RR_TYPE (aptr);
98 rr_class = DNS_RR_CLASS (aptr);
99 rr_len = DNS_RR_LEN (aptr);
101 if (aptr + rr_len > abuf + alen)
103 status = ARES_EBADRESP;
107 /* Check if we are really looking at a CAA record */
108 if ((rr_class == C_IN || rr_class == C_CHAOS) && rr_type == T_CAA)
112 /* Allocate storage for this CAA answer appending it to the list */
113 caa_curr = ares_malloc_data(ARES_DATATYPE_CAA_REPLY);
116 status = ARES_ENOMEM;
121 caa_last->next = caa_curr;
130 status = ARES_EBADRESP;
133 caa_curr->critical = (int)*strptr++;
134 caa_curr->plength = (int)*strptr++;
135 if (caa_curr->plength <= 0 || (int)caa_curr->plength >= rr_len - 2)
137 status = ARES_EBADRESP;
140 caa_curr->property = ares_malloc (caa_curr->plength + 1/* Including null byte */);
141 if (caa_curr->property == NULL)
143 status = ARES_ENOMEM;
146 memcpy ((char *) caa_curr->property, strptr, caa_curr->plength);
147 /* Make sure we NULL-terminate */
148 caa_curr->property[caa_curr->plength] = 0;
149 strptr += caa_curr->plength;
151 caa_curr->length = rr_len - caa_curr->plength - 2;
152 if (caa_curr->length <= 0)
154 status = ARES_EBADRESP;
157 caa_curr->value = ares_malloc (caa_curr->length + 1/* Including null byte */);
158 if (caa_curr->value == NULL)
160 status = ARES_ENOMEM;
163 memcpy ((char *) caa_curr->value, strptr, caa_curr->length);
164 /* Make sure we NULL-terminate */
165 caa_curr->value[caa_curr->length] = 0;
168 /* Propagate any failures */
169 if (status != ARES_SUCCESS)
174 /* Don't lose memory in the next iteration */
178 /* Move on to the next record */
183 ares_free (hostname);
187 /* clean up on error */
188 if (status != ARES_SUCCESS)
191 ares_free_data (caa_head);
195 /* everything looks fine, return the data */