• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* MIT License
2  *
3  * Copyright (c) 2023 Brad House
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  *
24  * SPDX-License-Identifier: MIT
25  */
26 
27 #include "ares_setup.h"
28 #include "ares.h"
29 #include "ares_data.h"
30 #include "ares_private.h"
31 
ares__parse_txt_reply(const unsigned char * abuf,size_t alen,ares_bool_t ex,void ** txt_out)32 static int ares__parse_txt_reply(const unsigned char *abuf, size_t alen,
33                                  ares_bool_t ex, void **txt_out)
34 {
35   ares_status_t        status;
36   struct ares_txt_ext *txt_head = NULL;
37   struct ares_txt_ext *txt_last = NULL;
38   struct ares_txt_ext *txt_curr;
39   ares_dns_record_t   *dnsrec = NULL;
40   size_t               i;
41 
42   *txt_out = NULL;
43 
44   status = ares_dns_parse(abuf, alen, 0, &dnsrec);
45   if (status != ARES_SUCCESS) {
46     goto done;
47   }
48 
49   if (ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER) == 0) {
50     status = ARES_ENODATA;
51     goto done;
52   }
53 
54   for (i = 0; i < ares_dns_record_rr_cnt(dnsrec, ARES_SECTION_ANSWER); i++) {
55     const ares_dns_rr_t *rr =
56       ares_dns_record_rr_get(dnsrec, ARES_SECTION_ANSWER, i);
57     const unsigned char *ptr;
58     size_t               ptr_len;
59 
60     if (rr == NULL) {
61       /* Shouldn't be possible */
62       status = ARES_EBADRESP;
63       goto done;
64     }
65 
66     /* XXX: Why Chaos? */
67     if ((ares_dns_rr_get_class(rr) != ARES_CLASS_IN &&
68          ares_dns_rr_get_class(rr) != ARES_CLASS_CHAOS) ||
69         ares_dns_rr_get_type(rr) != ARES_REC_TYPE_TXT) {
70       continue;
71     }
72 
73     /* Allocate storage for this TXT answer appending it to the list */
74     txt_curr =
75       ares_malloc_data(ex ? ARES_DATATYPE_TXT_EXT : ARES_DATATYPE_TXT_REPLY);
76     if (txt_curr == NULL) {
77       status = ARES_ENOMEM;
78       goto done;
79     }
80 
81     /* Link in the record */
82     if (txt_last) {
83       txt_last->next = txt_curr;
84     } else {
85       txt_head = txt_curr;
86     }
87     txt_last = txt_curr;
88 
89     /* These days, records are joined, always tag as start */
90     if (ex) {
91       txt_curr->record_start = 1;
92     }
93 
94     ptr = ares_dns_rr_get_bin(rr, ARES_RR_TXT_DATA, &ptr_len);
95 
96     txt_curr->txt = ares_malloc(ptr_len + 1);
97     if (txt_curr->txt == NULL) {
98       status = ARES_ENOMEM;
99       goto done;
100     }
101     memcpy(txt_curr->txt, ptr, ptr_len);
102     txt_curr->txt[ptr_len] = 0;
103     txt_curr->length       = ptr_len;
104   }
105 
106 done:
107   /* clean up on error */
108   if (status != ARES_SUCCESS) {
109     if (txt_head) {
110       ares_free_data(txt_head);
111     }
112   } else {
113     /* everything looks fine, return the data */
114     *txt_out = txt_head;
115   }
116   ares_dns_record_destroy(dnsrec);
117   return (int)status;
118 }
119 
ares_parse_txt_reply(const unsigned char * abuf,int alen,struct ares_txt_reply ** txt_out)120 int ares_parse_txt_reply(const unsigned char *abuf, int alen,
121                          struct ares_txt_reply **txt_out)
122 {
123   if (alen < 0) {
124     return ARES_EBADRESP;
125   }
126   return ares__parse_txt_reply(abuf, (size_t)alen, ARES_FALSE,
127                                (void **)txt_out);
128 }
129 
ares_parse_txt_reply_ext(const unsigned char * abuf,int alen,struct ares_txt_ext ** txt_out)130 int ares_parse_txt_reply_ext(const unsigned char *abuf, int alen,
131                              struct ares_txt_ext **txt_out)
132 {
133   if (alen < 0) {
134     return ARES_EBADRESP;
135   }
136   return ares__parse_txt_reply(abuf, (size_t)alen, ARES_TRUE, (void **)txt_out);
137 }
138