xref: /aosp_15_r20/external/curl/lib/doh.c (revision 6236dae45794135f37c4eb022389c904c8b0090d)
1*6236dae4SAndroid Build Coastguard Worker /***************************************************************************
2*6236dae4SAndroid Build Coastguard Worker  *                                  _   _ ____  _
3*6236dae4SAndroid Build Coastguard Worker  *  Project                     ___| | | |  _ \| |
4*6236dae4SAndroid Build Coastguard Worker  *                             / __| | | | |_) | |
5*6236dae4SAndroid Build Coastguard Worker  *                            | (__| |_| |  _ <| |___
6*6236dae4SAndroid Build Coastguard Worker  *                             \___|\___/|_| \_\_____|
7*6236dae4SAndroid Build Coastguard Worker  *
8*6236dae4SAndroid Build Coastguard Worker  * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9*6236dae4SAndroid Build Coastguard Worker  *
10*6236dae4SAndroid Build Coastguard Worker  * This software is licensed as described in the file COPYING, which
11*6236dae4SAndroid Build Coastguard Worker  * you should have received as part of this distribution. The terms
12*6236dae4SAndroid Build Coastguard Worker  * are also available at https://curl.se/docs/copyright.html.
13*6236dae4SAndroid Build Coastguard Worker  *
14*6236dae4SAndroid Build Coastguard Worker  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15*6236dae4SAndroid Build Coastguard Worker  * copies of the Software, and permit persons to whom the Software is
16*6236dae4SAndroid Build Coastguard Worker  * furnished to do so, under the terms of the COPYING file.
17*6236dae4SAndroid Build Coastguard Worker  *
18*6236dae4SAndroid Build Coastguard Worker  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19*6236dae4SAndroid Build Coastguard Worker  * KIND, either express or implied.
20*6236dae4SAndroid Build Coastguard Worker  *
21*6236dae4SAndroid Build Coastguard Worker  * SPDX-License-Identifier: curl
22*6236dae4SAndroid Build Coastguard Worker  *
23*6236dae4SAndroid Build Coastguard Worker  ***************************************************************************/
24*6236dae4SAndroid Build Coastguard Worker 
25*6236dae4SAndroid Build Coastguard Worker #include "curl_setup.h"
26*6236dae4SAndroid Build Coastguard Worker 
27*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_DOH
28*6236dae4SAndroid Build Coastguard Worker 
29*6236dae4SAndroid Build Coastguard Worker #include "urldata.h"
30*6236dae4SAndroid Build Coastguard Worker #include "curl_addrinfo.h"
31*6236dae4SAndroid Build Coastguard Worker #include "doh.h"
32*6236dae4SAndroid Build Coastguard Worker 
33*6236dae4SAndroid Build Coastguard Worker #include "sendf.h"
34*6236dae4SAndroid Build Coastguard Worker #include "multiif.h"
35*6236dae4SAndroid Build Coastguard Worker #include "url.h"
36*6236dae4SAndroid Build Coastguard Worker #include "share.h"
37*6236dae4SAndroid Build Coastguard Worker #include "curl_base64.h"
38*6236dae4SAndroid Build Coastguard Worker #include "connect.h"
39*6236dae4SAndroid Build Coastguard Worker #include "strdup.h"
40*6236dae4SAndroid Build Coastguard Worker #include "dynbuf.h"
41*6236dae4SAndroid Build Coastguard Worker /* The last 3 #include files should be in this order */
42*6236dae4SAndroid Build Coastguard Worker #include "curl_printf.h"
43*6236dae4SAndroid Build Coastguard Worker #include "curl_memory.h"
44*6236dae4SAndroid Build Coastguard Worker #include "memdebug.h"
45*6236dae4SAndroid Build Coastguard Worker #include "escape.h"
46*6236dae4SAndroid Build Coastguard Worker 
47*6236dae4SAndroid Build Coastguard Worker #define DNS_CLASS_IN 0x01
48*6236dae4SAndroid Build Coastguard Worker 
49*6236dae4SAndroid Build Coastguard Worker /* doh_print_buf truncates if the hex string will be more than this */
50*6236dae4SAndroid Build Coastguard Worker #define LOCAL_PB_HEXMAX 400
51*6236dae4SAndroid Build Coastguard Worker 
52*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
53*6236dae4SAndroid Build Coastguard Worker static const char * const errors[]={
54*6236dae4SAndroid Build Coastguard Worker   "",
55*6236dae4SAndroid Build Coastguard Worker   "Bad label",
56*6236dae4SAndroid Build Coastguard Worker   "Out of range",
57*6236dae4SAndroid Build Coastguard Worker   "Label loop",
58*6236dae4SAndroid Build Coastguard Worker   "Too small",
59*6236dae4SAndroid Build Coastguard Worker   "Out of memory",
60*6236dae4SAndroid Build Coastguard Worker   "RDATA length",
61*6236dae4SAndroid Build Coastguard Worker   "Malformat",
62*6236dae4SAndroid Build Coastguard Worker   "Bad RCODE",
63*6236dae4SAndroid Build Coastguard Worker   "Unexpected TYPE",
64*6236dae4SAndroid Build Coastguard Worker   "Unexpected CLASS",
65*6236dae4SAndroid Build Coastguard Worker   "No content",
66*6236dae4SAndroid Build Coastguard Worker   "Bad ID",
67*6236dae4SAndroid Build Coastguard Worker   "Name too long"
68*6236dae4SAndroid Build Coastguard Worker };
69*6236dae4SAndroid Build Coastguard Worker 
doh_strerror(DOHcode code)70*6236dae4SAndroid Build Coastguard Worker static const char *doh_strerror(DOHcode code)
71*6236dae4SAndroid Build Coastguard Worker {
72*6236dae4SAndroid Build Coastguard Worker   if((code >= DOH_OK) && (code <= DOH_DNS_NAME_TOO_LONG))
73*6236dae4SAndroid Build Coastguard Worker     return errors[code];
74*6236dae4SAndroid Build Coastguard Worker   return "bad error code";
75*6236dae4SAndroid Build Coastguard Worker }
76*6236dae4SAndroid Build Coastguard Worker 
77*6236dae4SAndroid Build Coastguard Worker struct curl_trc_feat Curl_doh_trc = {
78*6236dae4SAndroid Build Coastguard Worker   "DoH",
79*6236dae4SAndroid Build Coastguard Worker   CURL_LOG_LVL_NONE,
80*6236dae4SAndroid Build Coastguard Worker };
81*6236dae4SAndroid Build Coastguard Worker #endif /* !CURL_DISABLE_VERBOSE_STRINGS */
82*6236dae4SAndroid Build Coastguard Worker 
83*6236dae4SAndroid Build Coastguard Worker /* @unittest 1655
84*6236dae4SAndroid Build Coastguard Worker  */
doh_req_encode(const char * host,DNStype dnstype,unsigned char * dnsp,size_t len,size_t * olen)85*6236dae4SAndroid Build Coastguard Worker UNITTEST DOHcode doh_req_encode(const char *host,
86*6236dae4SAndroid Build Coastguard Worker                                 DNStype dnstype,
87*6236dae4SAndroid Build Coastguard Worker                                 unsigned char *dnsp, /* buffer */
88*6236dae4SAndroid Build Coastguard Worker                                 size_t len,  /* buffer size */
89*6236dae4SAndroid Build Coastguard Worker                                 size_t *olen) /* output length */
90*6236dae4SAndroid Build Coastguard Worker {
91*6236dae4SAndroid Build Coastguard Worker   const size_t hostlen = strlen(host);
92*6236dae4SAndroid Build Coastguard Worker   unsigned char *orig = dnsp;
93*6236dae4SAndroid Build Coastguard Worker   const char *hostp = host;
94*6236dae4SAndroid Build Coastguard Worker 
95*6236dae4SAndroid Build Coastguard Worker   /* The expected output length is 16 bytes more than the length of
96*6236dae4SAndroid Build Coastguard Worker    * the QNAME-encoding of the hostname.
97*6236dae4SAndroid Build Coastguard Worker    *
98*6236dae4SAndroid Build Coastguard Worker    * A valid DNS name may not contain a zero-length label, except at
99*6236dae4SAndroid Build Coastguard Worker    * the end. For this reason, a name beginning with a dot, or
100*6236dae4SAndroid Build Coastguard Worker    * containing a sequence of two or more consecutive dots, is invalid
101*6236dae4SAndroid Build Coastguard Worker    * and cannot be encoded as a QNAME.
102*6236dae4SAndroid Build Coastguard Worker    *
103*6236dae4SAndroid Build Coastguard Worker    * If the hostname ends with a trailing dot, the corresponding
104*6236dae4SAndroid Build Coastguard Worker    * QNAME-encoding is one byte longer than the hostname. If (as is
105*6236dae4SAndroid Build Coastguard Worker    * also valid) the hostname is shortened by the omission of the
106*6236dae4SAndroid Build Coastguard Worker    * trailing dot, then its QNAME-encoding will be two bytes longer
107*6236dae4SAndroid Build Coastguard Worker    * than the hostname.
108*6236dae4SAndroid Build Coastguard Worker    *
109*6236dae4SAndroid Build Coastguard Worker    * Each [ label, dot ] pair is encoded as [ length, label ],
110*6236dae4SAndroid Build Coastguard Worker    * preserving overall length. A final [ label ] without a dot is
111*6236dae4SAndroid Build Coastguard Worker    * also encoded as [ length, label ], increasing overall length
112*6236dae4SAndroid Build Coastguard Worker    * by one. The encoding is completed by appending a zero byte,
113*6236dae4SAndroid Build Coastguard Worker    * representing the zero-length root label, again increasing
114*6236dae4SAndroid Build Coastguard Worker    * the overall length by one.
115*6236dae4SAndroid Build Coastguard Worker    */
116*6236dae4SAndroid Build Coastguard Worker 
117*6236dae4SAndroid Build Coastguard Worker   size_t expected_len;
118*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(hostlen);
119*6236dae4SAndroid Build Coastguard Worker   expected_len = 12 + 1 + hostlen + 4;
120*6236dae4SAndroid Build Coastguard Worker   if(host[hostlen-1]!='.')
121*6236dae4SAndroid Build Coastguard Worker     expected_len++;
122*6236dae4SAndroid Build Coastguard Worker 
123*6236dae4SAndroid Build Coastguard Worker   if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */
124*6236dae4SAndroid Build Coastguard Worker     return DOH_DNS_NAME_TOO_LONG;
125*6236dae4SAndroid Build Coastguard Worker 
126*6236dae4SAndroid Build Coastguard Worker   if(len < expected_len)
127*6236dae4SAndroid Build Coastguard Worker     return DOH_TOO_SMALL_BUFFER;
128*6236dae4SAndroid Build Coastguard Worker 
129*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = 0; /* 16 bit id */
130*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = 0;
131*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = 0x01; /* |QR|   Opcode  |AA|TC|RD| Set the RD bit */
132*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0'; /* |RA|   Z    |   RCODE   |                */
133*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0';
134*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = 1;    /* QDCOUNT (number of entries in the question section) */
135*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0';
136*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0'; /* ANCOUNT */
137*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0';
138*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0'; /* NSCOUNT */
139*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0';
140*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0'; /* ARCOUNT */
141*6236dae4SAndroid Build Coastguard Worker 
142*6236dae4SAndroid Build Coastguard Worker   /* encode each label and store it in the QNAME */
143*6236dae4SAndroid Build Coastguard Worker   while(*hostp) {
144*6236dae4SAndroid Build Coastguard Worker     size_t labellen;
145*6236dae4SAndroid Build Coastguard Worker     char *dot = strchr(hostp, '.');
146*6236dae4SAndroid Build Coastguard Worker     if(dot)
147*6236dae4SAndroid Build Coastguard Worker       labellen = dot - hostp;
148*6236dae4SAndroid Build Coastguard Worker     else
149*6236dae4SAndroid Build Coastguard Worker       labellen = strlen(hostp);
150*6236dae4SAndroid Build Coastguard Worker     if((labellen > 63) || (!labellen)) {
151*6236dae4SAndroid Build Coastguard Worker       /* label is too long or too short, error out */
152*6236dae4SAndroid Build Coastguard Worker       *olen = 0;
153*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_BAD_LABEL;
154*6236dae4SAndroid Build Coastguard Worker     }
155*6236dae4SAndroid Build Coastguard Worker     /* label is non-empty, process it */
156*6236dae4SAndroid Build Coastguard Worker     *dnsp++ = (unsigned char)labellen;
157*6236dae4SAndroid Build Coastguard Worker     memcpy(dnsp, hostp, labellen);
158*6236dae4SAndroid Build Coastguard Worker     dnsp += labellen;
159*6236dae4SAndroid Build Coastguard Worker     hostp += labellen;
160*6236dae4SAndroid Build Coastguard Worker     /* advance past dot, but only if there is one */
161*6236dae4SAndroid Build Coastguard Worker     if(dot)
162*6236dae4SAndroid Build Coastguard Worker       hostp++;
163*6236dae4SAndroid Build Coastguard Worker   } /* next label */
164*6236dae4SAndroid Build Coastguard Worker 
165*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = 0; /* append zero-length label for root */
166*6236dae4SAndroid Build Coastguard Worker 
167*6236dae4SAndroid Build Coastguard Worker   /* There are assigned TYPE codes beyond 255: use range [1..65535]  */
168*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = (unsigned char)(255 & (dnstype >> 8)); /* upper 8 bit TYPE */
169*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = (unsigned char)(255 & dnstype);      /* lower 8 bit TYPE */
170*6236dae4SAndroid Build Coastguard Worker 
171*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = '\0'; /* upper 8 bit CLASS */
172*6236dae4SAndroid Build Coastguard Worker   *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
173*6236dae4SAndroid Build Coastguard Worker 
174*6236dae4SAndroid Build Coastguard Worker   *olen = dnsp - orig;
175*6236dae4SAndroid Build Coastguard Worker 
176*6236dae4SAndroid Build Coastguard Worker   /* verify that our estimation of length is valid, since
177*6236dae4SAndroid Build Coastguard Worker    * this has led to buffer overflows in this function */
178*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(*olen == expected_len);
179*6236dae4SAndroid Build Coastguard Worker   return DOH_OK;
180*6236dae4SAndroid Build Coastguard Worker }
181*6236dae4SAndroid Build Coastguard Worker 
182*6236dae4SAndroid Build Coastguard Worker static size_t
doh_write_cb(char * contents,size_t size,size_t nmemb,void * userp)183*6236dae4SAndroid Build Coastguard Worker doh_write_cb(char *contents, size_t size, size_t nmemb, void *userp)
184*6236dae4SAndroid Build Coastguard Worker {
185*6236dae4SAndroid Build Coastguard Worker   size_t realsize = size * nmemb;
186*6236dae4SAndroid Build Coastguard Worker   struct dynbuf *mem = (struct dynbuf *)userp;
187*6236dae4SAndroid Build Coastguard Worker 
188*6236dae4SAndroid Build Coastguard Worker   if(Curl_dyn_addn(mem, contents, realsize))
189*6236dae4SAndroid Build Coastguard Worker     return 0;
190*6236dae4SAndroid Build Coastguard Worker 
191*6236dae4SAndroid Build Coastguard Worker   return realsize;
192*6236dae4SAndroid Build Coastguard Worker }
193*6236dae4SAndroid Build Coastguard Worker 
194*6236dae4SAndroid Build Coastguard Worker #if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
doh_print_buf(struct Curl_easy * data,const char * prefix,unsigned char * buf,size_t len)195*6236dae4SAndroid Build Coastguard Worker static void doh_print_buf(struct Curl_easy *data,
196*6236dae4SAndroid Build Coastguard Worker                           const char *prefix,
197*6236dae4SAndroid Build Coastguard Worker                           unsigned char *buf, size_t len)
198*6236dae4SAndroid Build Coastguard Worker {
199*6236dae4SAndroid Build Coastguard Worker   unsigned char hexstr[LOCAL_PB_HEXMAX];
200*6236dae4SAndroid Build Coastguard Worker   size_t hlen = LOCAL_PB_HEXMAX;
201*6236dae4SAndroid Build Coastguard Worker   bool truncated = FALSE;
202*6236dae4SAndroid Build Coastguard Worker 
203*6236dae4SAndroid Build Coastguard Worker   if(len > (LOCAL_PB_HEXMAX / 2))
204*6236dae4SAndroid Build Coastguard Worker     truncated = TRUE;
205*6236dae4SAndroid Build Coastguard Worker   Curl_hexencode(buf, len, hexstr, hlen);
206*6236dae4SAndroid Build Coastguard Worker   if(!truncated)
207*6236dae4SAndroid Build Coastguard Worker     infof(data, "%s: len=%d, val=%s", prefix, (int)len, hexstr);
208*6236dae4SAndroid Build Coastguard Worker   else
209*6236dae4SAndroid Build Coastguard Worker     infof(data, "%s: len=%d (truncated)val=%s", prefix, (int)len, hexstr);
210*6236dae4SAndroid Build Coastguard Worker   return;
211*6236dae4SAndroid Build Coastguard Worker }
212*6236dae4SAndroid Build Coastguard Worker #endif
213*6236dae4SAndroid Build Coastguard Worker 
214*6236dae4SAndroid Build Coastguard Worker /* called from multi.c when this DoH transfer is complete */
doh_done(struct Curl_easy * doh,CURLcode result)215*6236dae4SAndroid Build Coastguard Worker static int doh_done(struct Curl_easy *doh, CURLcode result)
216*6236dae4SAndroid Build Coastguard Worker {
217*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *data; /* the transfer that asked for the DoH probe */
218*6236dae4SAndroid Build Coastguard Worker 
219*6236dae4SAndroid Build Coastguard Worker   data = Curl_multi_get_handle(doh->multi, doh->set.dohfor_mid);
220*6236dae4SAndroid Build Coastguard Worker   if(!data) {
221*6236dae4SAndroid Build Coastguard Worker     DEBUGF(infof(doh, "doh_done: xfer for mid=%" FMT_OFF_T
222*6236dae4SAndroid Build Coastguard Worker                  " not found", doh->set.dohfor_mid));
223*6236dae4SAndroid Build Coastguard Worker     DEBUGASSERT(0);
224*6236dae4SAndroid Build Coastguard Worker   }
225*6236dae4SAndroid Build Coastguard Worker   else {
226*6236dae4SAndroid Build Coastguard Worker     struct doh_probes *dohp = data->req.doh;
227*6236dae4SAndroid Build Coastguard Worker     /* one of the DoH request done for the 'data' transfer is now complete! */
228*6236dae4SAndroid Build Coastguard Worker     dohp->pending--;
229*6236dae4SAndroid Build Coastguard Worker     infof(doh, "a DoH request is completed, %u to go", dohp->pending);
230*6236dae4SAndroid Build Coastguard Worker     if(result)
231*6236dae4SAndroid Build Coastguard Worker       infof(doh, "DoH request %s", curl_easy_strerror(result));
232*6236dae4SAndroid Build Coastguard Worker 
233*6236dae4SAndroid Build Coastguard Worker     if(!dohp->pending) {
234*6236dae4SAndroid Build Coastguard Worker       /* DoH completed, run the transfer picking up the results */
235*6236dae4SAndroid Build Coastguard Worker       Curl_expire(data, 0, EXPIRE_RUN_NOW);
236*6236dae4SAndroid Build Coastguard Worker     }
237*6236dae4SAndroid Build Coastguard Worker   }
238*6236dae4SAndroid Build Coastguard Worker   return 0;
239*6236dae4SAndroid Build Coastguard Worker }
240*6236dae4SAndroid Build Coastguard Worker 
241*6236dae4SAndroid Build Coastguard Worker #define ERROR_CHECK_SETOPT(x,y)                         \
242*6236dae4SAndroid Build Coastguard Worker   do {                                                  \
243*6236dae4SAndroid Build Coastguard Worker     result = curl_easy_setopt((CURL *)doh, x, y);       \
244*6236dae4SAndroid Build Coastguard Worker     if(result &&                                        \
245*6236dae4SAndroid Build Coastguard Worker        result != CURLE_NOT_BUILT_IN &&                  \
246*6236dae4SAndroid Build Coastguard Worker        result != CURLE_UNKNOWN_OPTION)                  \
247*6236dae4SAndroid Build Coastguard Worker       goto error;                                       \
248*6236dae4SAndroid Build Coastguard Worker   } while(0)
249*6236dae4SAndroid Build Coastguard Worker 
doh_run_probe(struct Curl_easy * data,struct doh_probe * p,DNStype dnstype,const char * host,const char * url,CURLM * multi,struct curl_slist * headers)250*6236dae4SAndroid Build Coastguard Worker static CURLcode doh_run_probe(struct Curl_easy *data,
251*6236dae4SAndroid Build Coastguard Worker                               struct doh_probe *p, DNStype dnstype,
252*6236dae4SAndroid Build Coastguard Worker                               const char *host,
253*6236dae4SAndroid Build Coastguard Worker                               const char *url, CURLM *multi,
254*6236dae4SAndroid Build Coastguard Worker                               struct curl_slist *headers)
255*6236dae4SAndroid Build Coastguard Worker {
256*6236dae4SAndroid Build Coastguard Worker   struct Curl_easy *doh = NULL;
257*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
258*6236dae4SAndroid Build Coastguard Worker   timediff_t timeout_ms;
259*6236dae4SAndroid Build Coastguard Worker   DOHcode d = doh_req_encode(host, dnstype, p->req_body, sizeof(p->req_body),
260*6236dae4SAndroid Build Coastguard Worker                              &p->req_body_len);
261*6236dae4SAndroid Build Coastguard Worker   if(d) {
262*6236dae4SAndroid Build Coastguard Worker     failf(data, "Failed to encode DoH packet [%d]", d);
263*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
264*6236dae4SAndroid Build Coastguard Worker   }
265*6236dae4SAndroid Build Coastguard Worker 
266*6236dae4SAndroid Build Coastguard Worker   p->dnstype = dnstype;
267*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&p->resp_body, DYN_DOH_RESPONSE);
268*6236dae4SAndroid Build Coastguard Worker 
269*6236dae4SAndroid Build Coastguard Worker   timeout_ms = Curl_timeleft(data, NULL, TRUE);
270*6236dae4SAndroid Build Coastguard Worker   if(timeout_ms <= 0) {
271*6236dae4SAndroid Build Coastguard Worker     result = CURLE_OPERATION_TIMEDOUT;
272*6236dae4SAndroid Build Coastguard Worker     goto error;
273*6236dae4SAndroid Build Coastguard Worker   }
274*6236dae4SAndroid Build Coastguard Worker   /* Curl_open() is the internal version of curl_easy_init() */
275*6236dae4SAndroid Build Coastguard Worker   result = Curl_open(&doh);
276*6236dae4SAndroid Build Coastguard Worker   if(result)
277*6236dae4SAndroid Build Coastguard Worker     goto error;
278*6236dae4SAndroid Build Coastguard Worker 
279*6236dae4SAndroid Build Coastguard Worker   /* pass in the struct pointer via a local variable to please coverity and
280*6236dae4SAndroid Build Coastguard Worker      the gcc typecheck helpers */
281*6236dae4SAndroid Build Coastguard Worker   doh->state.internal = TRUE;
282*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
283*6236dae4SAndroid Build Coastguard Worker   doh->state.feat = &Curl_doh_trc;
284*6236dae4SAndroid Build Coastguard Worker #endif
285*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_URL, url);
286*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_DEFAULT_PROTOCOL, "https");
287*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
288*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, &p->resp_body);
289*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->req_body);
290*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->req_body_len);
291*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
292*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTP2
293*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
294*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
295*6236dae4SAndroid Build Coastguard Worker #endif
296*6236dae4SAndroid Build Coastguard Worker #ifndef DEBUGBUILD
297*6236dae4SAndroid Build Coastguard Worker   /* enforce HTTPS if not debug */
298*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
299*6236dae4SAndroid Build Coastguard Worker #else
300*6236dae4SAndroid Build Coastguard Worker   /* in debug mode, also allow http */
301*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
302*6236dae4SAndroid Build Coastguard Worker #endif
303*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
304*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_SHARE, (CURLSH *)data->share);
305*6236dae4SAndroid Build Coastguard Worker   if(data->set.err && data->set.err != stderr)
306*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
307*6236dae4SAndroid Build Coastguard Worker   if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc))
308*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
309*6236dae4SAndroid Build Coastguard Worker   if(data->set.no_signal)
310*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
311*6236dae4SAndroid Build Coastguard Worker 
312*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
313*6236dae4SAndroid Build Coastguard Worker     data->set.doh_verifyhost ? 2L : 0L);
314*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
315*6236dae4SAndroid Build Coastguard Worker     data->set.doh_verifypeer ? 1L : 0L);
316*6236dae4SAndroid Build Coastguard Worker   ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
317*6236dae4SAndroid Build Coastguard Worker     data->set.doh_verifystatus ? 1L : 0L);
318*6236dae4SAndroid Build Coastguard Worker 
319*6236dae4SAndroid Build Coastguard Worker   /* Inherit *some* SSL options from the user's transfer. This is a
320*6236dae4SAndroid Build Coastguard Worker      best-guess as to which options are needed for compatibility. #3661
321*6236dae4SAndroid Build Coastguard Worker 
322*6236dae4SAndroid Build Coastguard Worker      Note DoH does not inherit the user's proxy server so proxy SSL settings
323*6236dae4SAndroid Build Coastguard Worker      have no effect and are not inherited. If that changes then two new
324*6236dae4SAndroid Build Coastguard Worker      options should be added to check doh proxy insecure separately,
325*6236dae4SAndroid Build Coastguard Worker      CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
326*6236dae4SAndroid Build Coastguard Worker      */
327*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.falsestart)
328*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
329*6236dae4SAndroid Build Coastguard Worker   if(data->set.str[STRING_SSL_CAFILE]) {
330*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
331*6236dae4SAndroid Build Coastguard Worker                        data->set.str[STRING_SSL_CAFILE]);
332*6236dae4SAndroid Build Coastguard Worker   }
333*6236dae4SAndroid Build Coastguard Worker   if(data->set.blobs[BLOB_CAINFO]) {
334*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
335*6236dae4SAndroid Build Coastguard Worker                        data->set.blobs[BLOB_CAINFO]);
336*6236dae4SAndroid Build Coastguard Worker   }
337*6236dae4SAndroid Build Coastguard Worker   if(data->set.str[STRING_SSL_CAPATH]) {
338*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
339*6236dae4SAndroid Build Coastguard Worker                        data->set.str[STRING_SSL_CAPATH]);
340*6236dae4SAndroid Build Coastguard Worker   }
341*6236dae4SAndroid Build Coastguard Worker   if(data->set.str[STRING_SSL_CRLFILE]) {
342*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
343*6236dae4SAndroid Build Coastguard Worker                        data->set.str[STRING_SSL_CRLFILE]);
344*6236dae4SAndroid Build Coastguard Worker   }
345*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.certinfo)
346*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
347*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.fsslctx)
348*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
349*6236dae4SAndroid Build Coastguard Worker   if(data->set.ssl.fsslctxp)
350*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
351*6236dae4SAndroid Build Coastguard Worker   if(data->set.fdebug)
352*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_DEBUGFUNCTION, data->set.fdebug);
353*6236dae4SAndroid Build Coastguard Worker   if(data->set.debugdata)
354*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_DEBUGDATA, data->set.debugdata);
355*6236dae4SAndroid Build Coastguard Worker   if(data->set.str[STRING_SSL_EC_CURVES]) {
356*6236dae4SAndroid Build Coastguard Worker     ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
357*6236dae4SAndroid Build Coastguard Worker                        data->set.str[STRING_SSL_EC_CURVES]);
358*6236dae4SAndroid Build Coastguard Worker   }
359*6236dae4SAndroid Build Coastguard Worker 
360*6236dae4SAndroid Build Coastguard Worker   {
361*6236dae4SAndroid Build Coastguard Worker     long mask =
362*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.enable_beast ?
363*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_ALLOW_BEAST : 0) |
364*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.no_revoke ?
365*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_NO_REVOKE : 0) |
366*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.no_partialchain ?
367*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_NO_PARTIALCHAIN : 0) |
368*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.revoke_best_effort ?
369*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
370*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.native_ca_store ?
371*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_NATIVE_CA : 0) |
372*6236dae4SAndroid Build Coastguard Worker       (data->set.ssl.auto_client_cert ?
373*6236dae4SAndroid Build Coastguard Worker        CURLSSLOPT_AUTO_CLIENT_CERT : 0);
374*6236dae4SAndroid Build Coastguard Worker 
375*6236dae4SAndroid Build Coastguard Worker     (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
376*6236dae4SAndroid Build Coastguard Worker   }
377*6236dae4SAndroid Build Coastguard Worker 
378*6236dae4SAndroid Build Coastguard Worker   doh->set.fmultidone = doh_done;
379*6236dae4SAndroid Build Coastguard Worker   doh->set.dohfor_mid = data->mid; /* for which transfer this is done */
380*6236dae4SAndroid Build Coastguard Worker 
381*6236dae4SAndroid Build Coastguard Worker   /* DoH handles must not inherit private_data. The handles may be passed to
382*6236dae4SAndroid Build Coastguard Worker      the user via callbacks and the user will be able to identify them as
383*6236dae4SAndroid Build Coastguard Worker      internal handles because private data is not set. The user can then set
384*6236dae4SAndroid Build Coastguard Worker      private_data via CURLOPT_PRIVATE if they so choose. */
385*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(!doh->set.private_data);
386*6236dae4SAndroid Build Coastguard Worker 
387*6236dae4SAndroid Build Coastguard Worker   if(curl_multi_add_handle(multi, doh))
388*6236dae4SAndroid Build Coastguard Worker     goto error;
389*6236dae4SAndroid Build Coastguard Worker 
390*6236dae4SAndroid Build Coastguard Worker   p->easy_mid = doh->mid;
391*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
392*6236dae4SAndroid Build Coastguard Worker 
393*6236dae4SAndroid Build Coastguard Worker error:
394*6236dae4SAndroid Build Coastguard Worker   Curl_close(&doh);
395*6236dae4SAndroid Build Coastguard Worker   p->easy_mid = -1;
396*6236dae4SAndroid Build Coastguard Worker   return result;
397*6236dae4SAndroid Build Coastguard Worker }
398*6236dae4SAndroid Build Coastguard Worker 
399*6236dae4SAndroid Build Coastguard Worker /*
400*6236dae4SAndroid Build Coastguard Worker  * Curl_doh() resolves a name using DoH. It resolves a name and returns a
401*6236dae4SAndroid Build Coastguard Worker  * 'Curl_addrinfo *' with the address information.
402*6236dae4SAndroid Build Coastguard Worker  */
403*6236dae4SAndroid Build Coastguard Worker 
Curl_doh(struct Curl_easy * data,const char * hostname,int port,int * waitp)404*6236dae4SAndroid Build Coastguard Worker struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
405*6236dae4SAndroid Build Coastguard Worker                                const char *hostname,
406*6236dae4SAndroid Build Coastguard Worker                                int port,
407*6236dae4SAndroid Build Coastguard Worker                                int *waitp)
408*6236dae4SAndroid Build Coastguard Worker {
409*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
410*6236dae4SAndroid Build Coastguard Worker   struct doh_probes *dohp;
411*6236dae4SAndroid Build Coastguard Worker   struct connectdata *conn = data->conn;
412*6236dae4SAndroid Build Coastguard Worker   size_t i;
413*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
414*6236dae4SAndroid Build Coastguard Worker   /* for now, this is only used when ECH is enabled */
415*6236dae4SAndroid Build Coastguard Worker # ifdef USE_ECH
416*6236dae4SAndroid Build Coastguard Worker   char *qname = NULL;
417*6236dae4SAndroid Build Coastguard Worker # endif
418*6236dae4SAndroid Build Coastguard Worker #endif
419*6236dae4SAndroid Build Coastguard Worker   *waitp = FALSE;
420*6236dae4SAndroid Build Coastguard Worker   (void)hostname;
421*6236dae4SAndroid Build Coastguard Worker   (void)port;
422*6236dae4SAndroid Build Coastguard Worker 
423*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(!data->req.doh);
424*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(conn);
425*6236dae4SAndroid Build Coastguard Worker 
426*6236dae4SAndroid Build Coastguard Worker   /* start clean, consider allocating this struct on demand */
427*6236dae4SAndroid Build Coastguard Worker   dohp = data->req.doh = calloc(1, sizeof(struct doh_probes));
428*6236dae4SAndroid Build Coastguard Worker   if(!dohp)
429*6236dae4SAndroid Build Coastguard Worker     return NULL;
430*6236dae4SAndroid Build Coastguard Worker 
431*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < DOH_SLOT_COUNT; ++i) {
432*6236dae4SAndroid Build Coastguard Worker     dohp->probe[i].easy_mid = -1;
433*6236dae4SAndroid Build Coastguard Worker   }
434*6236dae4SAndroid Build Coastguard Worker 
435*6236dae4SAndroid Build Coastguard Worker   conn->bits.doh = TRUE;
436*6236dae4SAndroid Build Coastguard Worker   dohp->host = hostname;
437*6236dae4SAndroid Build Coastguard Worker   dohp->port = port;
438*6236dae4SAndroid Build Coastguard Worker   dohp->req_hds =
439*6236dae4SAndroid Build Coastguard Worker     curl_slist_append(NULL,
440*6236dae4SAndroid Build Coastguard Worker                       "Content-Type: application/dns-message");
441*6236dae4SAndroid Build Coastguard Worker   if(!dohp->req_hds)
442*6236dae4SAndroid Build Coastguard Worker     goto error;
443*6236dae4SAndroid Build Coastguard Worker 
444*6236dae4SAndroid Build Coastguard Worker   /* create IPv4 DoH request */
445*6236dae4SAndroid Build Coastguard Worker   result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV4],
446*6236dae4SAndroid Build Coastguard Worker                          DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
447*6236dae4SAndroid Build Coastguard Worker                          data->multi, dohp->req_hds);
448*6236dae4SAndroid Build Coastguard Worker   if(result)
449*6236dae4SAndroid Build Coastguard Worker     goto error;
450*6236dae4SAndroid Build Coastguard Worker   dohp->pending++;
451*6236dae4SAndroid Build Coastguard Worker 
452*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
453*6236dae4SAndroid Build Coastguard Worker   if((conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
454*6236dae4SAndroid Build Coastguard Worker     /* create IPv6 DoH request */
455*6236dae4SAndroid Build Coastguard Worker     result = doh_run_probe(data, &dohp->probe[DOH_SLOT_IPV6],
456*6236dae4SAndroid Build Coastguard Worker                            DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
457*6236dae4SAndroid Build Coastguard Worker                            data->multi, dohp->req_hds);
458*6236dae4SAndroid Build Coastguard Worker     if(result)
459*6236dae4SAndroid Build Coastguard Worker       goto error;
460*6236dae4SAndroid Build Coastguard Worker     dohp->pending++;
461*6236dae4SAndroid Build Coastguard Worker   }
462*6236dae4SAndroid Build Coastguard Worker #endif
463*6236dae4SAndroid Build Coastguard Worker 
464*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
465*6236dae4SAndroid Build Coastguard Worker   /*
466*6236dae4SAndroid Build Coastguard Worker    * TODO: Figure out the conditions under which we want to make
467*6236dae4SAndroid Build Coastguard Worker    * a request for an HTTPS RR when we are not doing ECH. For now,
468*6236dae4SAndroid Build Coastguard Worker    * making this request breaks a bunch of DoH tests, e.g. test2100,
469*6236dae4SAndroid Build Coastguard Worker    * where the additional request does not match the pre-cooked data
470*6236dae4SAndroid Build Coastguard Worker    * files, so there is a bit of work attached to making the request
471*6236dae4SAndroid Build Coastguard Worker    * in a non-ECH use-case. For the present, we will only make the
472*6236dae4SAndroid Build Coastguard Worker    * request when ECH is enabled in the build and is being used for
473*6236dae4SAndroid Build Coastguard Worker    * the curl operation.
474*6236dae4SAndroid Build Coastguard Worker    */
475*6236dae4SAndroid Build Coastguard Worker # ifdef USE_ECH
476*6236dae4SAndroid Build Coastguard Worker   if(data->set.tls_ech & CURLECH_ENABLE
477*6236dae4SAndroid Build Coastguard Worker      || data->set.tls_ech & CURLECH_HARD) {
478*6236dae4SAndroid Build Coastguard Worker     if(port == 443)
479*6236dae4SAndroid Build Coastguard Worker       qname = strdup(hostname);
480*6236dae4SAndroid Build Coastguard Worker     else
481*6236dae4SAndroid Build Coastguard Worker       qname = aprintf("_%d._https.%s", port, hostname);
482*6236dae4SAndroid Build Coastguard Worker     if(!qname)
483*6236dae4SAndroid Build Coastguard Worker       goto error;
484*6236dae4SAndroid Build Coastguard Worker     result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
485*6236dae4SAndroid Build Coastguard Worker                            DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
486*6236dae4SAndroid Build Coastguard Worker                            data->multi, dohp->req_hds);
487*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(qname);
488*6236dae4SAndroid Build Coastguard Worker     if(result)
489*6236dae4SAndroid Build Coastguard Worker       goto error;
490*6236dae4SAndroid Build Coastguard Worker     dohp->pending++;
491*6236dae4SAndroid Build Coastguard Worker   }
492*6236dae4SAndroid Build Coastguard Worker # endif
493*6236dae4SAndroid Build Coastguard Worker #endif
494*6236dae4SAndroid Build Coastguard Worker   *waitp = TRUE; /* this never returns synchronously */
495*6236dae4SAndroid Build Coastguard Worker   return NULL;
496*6236dae4SAndroid Build Coastguard Worker 
497*6236dae4SAndroid Build Coastguard Worker error:
498*6236dae4SAndroid Build Coastguard Worker   Curl_doh_cleanup(data);
499*6236dae4SAndroid Build Coastguard Worker   return NULL;
500*6236dae4SAndroid Build Coastguard Worker }
501*6236dae4SAndroid Build Coastguard Worker 
doh_skipqname(const unsigned char * doh,size_t dohlen,unsigned int * indexp)502*6236dae4SAndroid Build Coastguard Worker static DOHcode doh_skipqname(const unsigned char *doh, size_t dohlen,
503*6236dae4SAndroid Build Coastguard Worker                              unsigned int *indexp)
504*6236dae4SAndroid Build Coastguard Worker {
505*6236dae4SAndroid Build Coastguard Worker   unsigned char length;
506*6236dae4SAndroid Build Coastguard Worker   do {
507*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (*indexp + 1))
508*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
509*6236dae4SAndroid Build Coastguard Worker     length = doh[*indexp];
510*6236dae4SAndroid Build Coastguard Worker     if((length & 0xc0) == 0xc0) {
511*6236dae4SAndroid Build Coastguard Worker       /* name pointer, advance over it and be done */
512*6236dae4SAndroid Build Coastguard Worker       if(dohlen < (*indexp + 2))
513*6236dae4SAndroid Build Coastguard Worker         return DOH_DNS_OUT_OF_RANGE;
514*6236dae4SAndroid Build Coastguard Worker       *indexp += 2;
515*6236dae4SAndroid Build Coastguard Worker       break;
516*6236dae4SAndroid Build Coastguard Worker     }
517*6236dae4SAndroid Build Coastguard Worker     if(length & 0xc0)
518*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_BAD_LABEL;
519*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (*indexp + 1 + length))
520*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
521*6236dae4SAndroid Build Coastguard Worker     *indexp += (unsigned int)(1 + length);
522*6236dae4SAndroid Build Coastguard Worker   } while(length);
523*6236dae4SAndroid Build Coastguard Worker   return DOH_OK;
524*6236dae4SAndroid Build Coastguard Worker }
525*6236dae4SAndroid Build Coastguard Worker 
doh_get16bit(const unsigned char * doh,unsigned int index)526*6236dae4SAndroid Build Coastguard Worker static unsigned short doh_get16bit(const unsigned char *doh,
527*6236dae4SAndroid Build Coastguard Worker                                    unsigned int index)
528*6236dae4SAndroid Build Coastguard Worker {
529*6236dae4SAndroid Build Coastguard Worker   return (unsigned short)((doh[index] << 8) | doh[index + 1]);
530*6236dae4SAndroid Build Coastguard Worker }
531*6236dae4SAndroid Build Coastguard Worker 
doh_get32bit(const unsigned char * doh,unsigned int index)532*6236dae4SAndroid Build Coastguard Worker static unsigned int doh_get32bit(const unsigned char *doh, unsigned int index)
533*6236dae4SAndroid Build Coastguard Worker {
534*6236dae4SAndroid Build Coastguard Worker   /* make clang and gcc optimize this to bswap by incrementing
535*6236dae4SAndroid Build Coastguard Worker      the pointer first. */
536*6236dae4SAndroid Build Coastguard Worker   doh += index;
537*6236dae4SAndroid Build Coastguard Worker 
538*6236dae4SAndroid Build Coastguard Worker   /* avoid undefined behavior by casting to unsigned before shifting
539*6236dae4SAndroid Build Coastguard Worker      24 bits, possibly into the sign bit. codegen is same, but
540*6236dae4SAndroid Build Coastguard Worker      ub sanitizer will not be upset */
541*6236dae4SAndroid Build Coastguard Worker   return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
542*6236dae4SAndroid Build Coastguard Worker          ((unsigned)doh[2] << 8) | doh[3];
543*6236dae4SAndroid Build Coastguard Worker }
544*6236dae4SAndroid Build Coastguard Worker 
doh_store_a(const unsigned char * doh,int index,struct dohentry * d)545*6236dae4SAndroid Build Coastguard Worker static void doh_store_a(const unsigned char *doh, int index,
546*6236dae4SAndroid Build Coastguard Worker                         struct dohentry *d)
547*6236dae4SAndroid Build Coastguard Worker {
548*6236dae4SAndroid Build Coastguard Worker   /* silently ignore addresses over the limit */
549*6236dae4SAndroid Build Coastguard Worker   if(d->numaddr < DOH_MAX_ADDR) {
550*6236dae4SAndroid Build Coastguard Worker     struct dohaddr *a = &d->addr[d->numaddr];
551*6236dae4SAndroid Build Coastguard Worker     a->type = DNS_TYPE_A;
552*6236dae4SAndroid Build Coastguard Worker     memcpy(&a->ip.v4, &doh[index], 4);
553*6236dae4SAndroid Build Coastguard Worker     d->numaddr++;
554*6236dae4SAndroid Build Coastguard Worker   }
555*6236dae4SAndroid Build Coastguard Worker }
556*6236dae4SAndroid Build Coastguard Worker 
doh_store_aaaa(const unsigned char * doh,int index,struct dohentry * d)557*6236dae4SAndroid Build Coastguard Worker static void doh_store_aaaa(const unsigned char *doh, int index,
558*6236dae4SAndroid Build Coastguard Worker                               struct dohentry *d)
559*6236dae4SAndroid Build Coastguard Worker {
560*6236dae4SAndroid Build Coastguard Worker   /* silently ignore addresses over the limit */
561*6236dae4SAndroid Build Coastguard Worker   if(d->numaddr < DOH_MAX_ADDR) {
562*6236dae4SAndroid Build Coastguard Worker     struct dohaddr *a = &d->addr[d->numaddr];
563*6236dae4SAndroid Build Coastguard Worker     a->type = DNS_TYPE_AAAA;
564*6236dae4SAndroid Build Coastguard Worker     memcpy(&a->ip.v6, &doh[index], 16);
565*6236dae4SAndroid Build Coastguard Worker     d->numaddr++;
566*6236dae4SAndroid Build Coastguard Worker   }
567*6236dae4SAndroid Build Coastguard Worker }
568*6236dae4SAndroid Build Coastguard Worker 
569*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
doh_store_https(const unsigned char * doh,int index,struct dohentry * d,uint16_t len)570*6236dae4SAndroid Build Coastguard Worker static DOHcode doh_store_https(const unsigned char *doh, int index,
571*6236dae4SAndroid Build Coastguard Worker                                struct dohentry *d, uint16_t len)
572*6236dae4SAndroid Build Coastguard Worker {
573*6236dae4SAndroid Build Coastguard Worker   /* silently ignore RRs over the limit */
574*6236dae4SAndroid Build Coastguard Worker   if(d->numhttps_rrs < DOH_MAX_HTTPS) {
575*6236dae4SAndroid Build Coastguard Worker     struct dohhttps_rr *h = &d->https_rrs[d->numhttps_rrs];
576*6236dae4SAndroid Build Coastguard Worker     h->val = Curl_memdup(&doh[index], len);
577*6236dae4SAndroid Build Coastguard Worker     if(!h->val)
578*6236dae4SAndroid Build Coastguard Worker       return DOH_OUT_OF_MEM;
579*6236dae4SAndroid Build Coastguard Worker     h->len = len;
580*6236dae4SAndroid Build Coastguard Worker     d->numhttps_rrs++;
581*6236dae4SAndroid Build Coastguard Worker   }
582*6236dae4SAndroid Build Coastguard Worker   return DOH_OK;
583*6236dae4SAndroid Build Coastguard Worker }
584*6236dae4SAndroid Build Coastguard Worker #endif
585*6236dae4SAndroid Build Coastguard Worker 
doh_store_cname(const unsigned char * doh,size_t dohlen,unsigned int index,struct dohentry * d)586*6236dae4SAndroid Build Coastguard Worker static DOHcode doh_store_cname(const unsigned char *doh, size_t dohlen,
587*6236dae4SAndroid Build Coastguard Worker                                unsigned int index, struct dohentry *d)
588*6236dae4SAndroid Build Coastguard Worker {
589*6236dae4SAndroid Build Coastguard Worker   struct dynbuf *c;
590*6236dae4SAndroid Build Coastguard Worker   unsigned int loop = 128; /* a valid DNS name can never loop this much */
591*6236dae4SAndroid Build Coastguard Worker   unsigned char length;
592*6236dae4SAndroid Build Coastguard Worker 
593*6236dae4SAndroid Build Coastguard Worker   if(d->numcname == DOH_MAX_CNAME)
594*6236dae4SAndroid Build Coastguard Worker     return DOH_OK; /* skip! */
595*6236dae4SAndroid Build Coastguard Worker 
596*6236dae4SAndroid Build Coastguard Worker   c = &d->cname[d->numcname++];
597*6236dae4SAndroid Build Coastguard Worker   do {
598*6236dae4SAndroid Build Coastguard Worker     if(index >= dohlen)
599*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
600*6236dae4SAndroid Build Coastguard Worker     length = doh[index];
601*6236dae4SAndroid Build Coastguard Worker     if((length & 0xc0) == 0xc0) {
602*6236dae4SAndroid Build Coastguard Worker       int newpos;
603*6236dae4SAndroid Build Coastguard Worker       /* name pointer, get the new offset (14 bits) */
604*6236dae4SAndroid Build Coastguard Worker       if((index + 1) >= dohlen)
605*6236dae4SAndroid Build Coastguard Worker         return DOH_DNS_OUT_OF_RANGE;
606*6236dae4SAndroid Build Coastguard Worker 
607*6236dae4SAndroid Build Coastguard Worker       /* move to the new index */
608*6236dae4SAndroid Build Coastguard Worker       newpos = (length & 0x3f) << 8 | doh[index + 1];
609*6236dae4SAndroid Build Coastguard Worker       index = (unsigned int)newpos;
610*6236dae4SAndroid Build Coastguard Worker       continue;
611*6236dae4SAndroid Build Coastguard Worker     }
612*6236dae4SAndroid Build Coastguard Worker     else if(length & 0xc0)
613*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_BAD_LABEL; /* bad input */
614*6236dae4SAndroid Build Coastguard Worker     else
615*6236dae4SAndroid Build Coastguard Worker       index++;
616*6236dae4SAndroid Build Coastguard Worker 
617*6236dae4SAndroid Build Coastguard Worker     if(length) {
618*6236dae4SAndroid Build Coastguard Worker       if(Curl_dyn_len(c)) {
619*6236dae4SAndroid Build Coastguard Worker         if(Curl_dyn_addn(c, STRCONST(".")))
620*6236dae4SAndroid Build Coastguard Worker           return DOH_OUT_OF_MEM;
621*6236dae4SAndroid Build Coastguard Worker       }
622*6236dae4SAndroid Build Coastguard Worker       if((index + length) > dohlen)
623*6236dae4SAndroid Build Coastguard Worker         return DOH_DNS_BAD_LABEL;
624*6236dae4SAndroid Build Coastguard Worker 
625*6236dae4SAndroid Build Coastguard Worker       if(Curl_dyn_addn(c, &doh[index], length))
626*6236dae4SAndroid Build Coastguard Worker         return DOH_OUT_OF_MEM;
627*6236dae4SAndroid Build Coastguard Worker       index += length;
628*6236dae4SAndroid Build Coastguard Worker     }
629*6236dae4SAndroid Build Coastguard Worker   } while(length && --loop);
630*6236dae4SAndroid Build Coastguard Worker 
631*6236dae4SAndroid Build Coastguard Worker   if(!loop)
632*6236dae4SAndroid Build Coastguard Worker     return DOH_DNS_LABEL_LOOP;
633*6236dae4SAndroid Build Coastguard Worker   return DOH_OK;
634*6236dae4SAndroid Build Coastguard Worker }
635*6236dae4SAndroid Build Coastguard Worker 
doh_rdata(const unsigned char * doh,size_t dohlen,unsigned short rdlength,unsigned short type,int index,struct dohentry * d)636*6236dae4SAndroid Build Coastguard Worker static DOHcode doh_rdata(const unsigned char *doh,
637*6236dae4SAndroid Build Coastguard Worker                          size_t dohlen,
638*6236dae4SAndroid Build Coastguard Worker                          unsigned short rdlength,
639*6236dae4SAndroid Build Coastguard Worker                          unsigned short type,
640*6236dae4SAndroid Build Coastguard Worker                          int index,
641*6236dae4SAndroid Build Coastguard Worker                          struct dohentry *d)
642*6236dae4SAndroid Build Coastguard Worker {
643*6236dae4SAndroid Build Coastguard Worker   /* RDATA
644*6236dae4SAndroid Build Coastguard Worker      - A (TYPE 1):  4 bytes
645*6236dae4SAndroid Build Coastguard Worker      - AAAA (TYPE 28): 16 bytes
646*6236dae4SAndroid Build Coastguard Worker      - NS (TYPE 2): N bytes
647*6236dae4SAndroid Build Coastguard Worker      - HTTPS (TYPE 65): N bytes */
648*6236dae4SAndroid Build Coastguard Worker   DOHcode rc;
649*6236dae4SAndroid Build Coastguard Worker 
650*6236dae4SAndroid Build Coastguard Worker   switch(type) {
651*6236dae4SAndroid Build Coastguard Worker   case DNS_TYPE_A:
652*6236dae4SAndroid Build Coastguard Worker     if(rdlength != 4)
653*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_RDATA_LEN;
654*6236dae4SAndroid Build Coastguard Worker     doh_store_a(doh, index, d);
655*6236dae4SAndroid Build Coastguard Worker     break;
656*6236dae4SAndroid Build Coastguard Worker   case DNS_TYPE_AAAA:
657*6236dae4SAndroid Build Coastguard Worker     if(rdlength != 16)
658*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_RDATA_LEN;
659*6236dae4SAndroid Build Coastguard Worker     doh_store_aaaa(doh, index, d);
660*6236dae4SAndroid Build Coastguard Worker     break;
661*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
662*6236dae4SAndroid Build Coastguard Worker   case DNS_TYPE_HTTPS:
663*6236dae4SAndroid Build Coastguard Worker     rc = doh_store_https(doh, index, d, rdlength);
664*6236dae4SAndroid Build Coastguard Worker     if(rc)
665*6236dae4SAndroid Build Coastguard Worker       return rc;
666*6236dae4SAndroid Build Coastguard Worker     break;
667*6236dae4SAndroid Build Coastguard Worker #endif
668*6236dae4SAndroid Build Coastguard Worker   case DNS_TYPE_CNAME:
669*6236dae4SAndroid Build Coastguard Worker     rc = doh_store_cname(doh, dohlen, (unsigned int)index, d);
670*6236dae4SAndroid Build Coastguard Worker     if(rc)
671*6236dae4SAndroid Build Coastguard Worker       return rc;
672*6236dae4SAndroid Build Coastguard Worker     break;
673*6236dae4SAndroid Build Coastguard Worker   case DNS_TYPE_DNAME:
674*6236dae4SAndroid Build Coastguard Worker     /* explicit for clarity; just skip; rely on synthesized CNAME  */
675*6236dae4SAndroid Build Coastguard Worker     break;
676*6236dae4SAndroid Build Coastguard Worker   default:
677*6236dae4SAndroid Build Coastguard Worker     /* unsupported type, just skip it */
678*6236dae4SAndroid Build Coastguard Worker     break;
679*6236dae4SAndroid Build Coastguard Worker   }
680*6236dae4SAndroid Build Coastguard Worker   return DOH_OK;
681*6236dae4SAndroid Build Coastguard Worker }
682*6236dae4SAndroid Build Coastguard Worker 
de_init(struct dohentry * de)683*6236dae4SAndroid Build Coastguard Worker UNITTEST void de_init(struct dohentry *de)
684*6236dae4SAndroid Build Coastguard Worker {
685*6236dae4SAndroid Build Coastguard Worker   int i;
686*6236dae4SAndroid Build Coastguard Worker   memset(de, 0, sizeof(*de));
687*6236dae4SAndroid Build Coastguard Worker   de->ttl = INT_MAX;
688*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < DOH_MAX_CNAME; i++)
689*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME);
690*6236dae4SAndroid Build Coastguard Worker }
691*6236dae4SAndroid Build Coastguard Worker 
692*6236dae4SAndroid Build Coastguard Worker 
doh_resp_decode(const unsigned char * doh,size_t dohlen,DNStype dnstype,struct dohentry * d)693*6236dae4SAndroid Build Coastguard Worker UNITTEST DOHcode doh_resp_decode(const unsigned char *doh,
694*6236dae4SAndroid Build Coastguard Worker                                  size_t dohlen,
695*6236dae4SAndroid Build Coastguard Worker                                  DNStype dnstype,
696*6236dae4SAndroid Build Coastguard Worker                                  struct dohentry *d)
697*6236dae4SAndroid Build Coastguard Worker {
698*6236dae4SAndroid Build Coastguard Worker   unsigned char rcode;
699*6236dae4SAndroid Build Coastguard Worker   unsigned short qdcount;
700*6236dae4SAndroid Build Coastguard Worker   unsigned short ancount;
701*6236dae4SAndroid Build Coastguard Worker   unsigned short type = 0;
702*6236dae4SAndroid Build Coastguard Worker   unsigned short rdlength;
703*6236dae4SAndroid Build Coastguard Worker   unsigned short nscount;
704*6236dae4SAndroid Build Coastguard Worker   unsigned short arcount;
705*6236dae4SAndroid Build Coastguard Worker   unsigned int index = 12;
706*6236dae4SAndroid Build Coastguard Worker   DOHcode rc;
707*6236dae4SAndroid Build Coastguard Worker 
708*6236dae4SAndroid Build Coastguard Worker   if(dohlen < 12)
709*6236dae4SAndroid Build Coastguard Worker     return DOH_TOO_SMALL_BUFFER; /* too small */
710*6236dae4SAndroid Build Coastguard Worker   if(!doh || doh[0] || doh[1])
711*6236dae4SAndroid Build Coastguard Worker     return DOH_DNS_BAD_ID; /* bad ID */
712*6236dae4SAndroid Build Coastguard Worker   rcode = doh[3] & 0x0f;
713*6236dae4SAndroid Build Coastguard Worker   if(rcode)
714*6236dae4SAndroid Build Coastguard Worker     return DOH_DNS_BAD_RCODE; /* bad rcode */
715*6236dae4SAndroid Build Coastguard Worker 
716*6236dae4SAndroid Build Coastguard Worker   qdcount = doh_get16bit(doh, 4);
717*6236dae4SAndroid Build Coastguard Worker   while(qdcount) {
718*6236dae4SAndroid Build Coastguard Worker     rc = doh_skipqname(doh, dohlen, &index);
719*6236dae4SAndroid Build Coastguard Worker     if(rc)
720*6236dae4SAndroid Build Coastguard Worker       return rc; /* bad qname */
721*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 4))
722*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
723*6236dae4SAndroid Build Coastguard Worker     index += 4; /* skip question's type and class */
724*6236dae4SAndroid Build Coastguard Worker     qdcount--;
725*6236dae4SAndroid Build Coastguard Worker   }
726*6236dae4SAndroid Build Coastguard Worker 
727*6236dae4SAndroid Build Coastguard Worker   ancount = doh_get16bit(doh, 6);
728*6236dae4SAndroid Build Coastguard Worker   while(ancount) {
729*6236dae4SAndroid Build Coastguard Worker     unsigned short class;
730*6236dae4SAndroid Build Coastguard Worker     unsigned int ttl;
731*6236dae4SAndroid Build Coastguard Worker 
732*6236dae4SAndroid Build Coastguard Worker     rc = doh_skipqname(doh, dohlen, &index);
733*6236dae4SAndroid Build Coastguard Worker     if(rc)
734*6236dae4SAndroid Build Coastguard Worker       return rc; /* bad qname */
735*6236dae4SAndroid Build Coastguard Worker 
736*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 2))
737*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
738*6236dae4SAndroid Build Coastguard Worker 
739*6236dae4SAndroid Build Coastguard Worker     type = doh_get16bit(doh, index);
740*6236dae4SAndroid Build Coastguard Worker     if((type != DNS_TYPE_CNAME)    /* may be synthesized from DNAME */
741*6236dae4SAndroid Build Coastguard Worker        && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
742*6236dae4SAndroid Build Coastguard Worker        && (type != dnstype))
743*6236dae4SAndroid Build Coastguard Worker       /* Not the same type as was asked for nor CNAME nor DNAME */
744*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_UNEXPECTED_TYPE;
745*6236dae4SAndroid Build Coastguard Worker     index += 2;
746*6236dae4SAndroid Build Coastguard Worker 
747*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 2))
748*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
749*6236dae4SAndroid Build Coastguard Worker     class = doh_get16bit(doh, index);
750*6236dae4SAndroid Build Coastguard Worker     if(DNS_CLASS_IN != class)
751*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
752*6236dae4SAndroid Build Coastguard Worker     index += 2;
753*6236dae4SAndroid Build Coastguard Worker 
754*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 4))
755*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
756*6236dae4SAndroid Build Coastguard Worker 
757*6236dae4SAndroid Build Coastguard Worker     ttl = doh_get32bit(doh, index);
758*6236dae4SAndroid Build Coastguard Worker     if(ttl < d->ttl)
759*6236dae4SAndroid Build Coastguard Worker       d->ttl = ttl;
760*6236dae4SAndroid Build Coastguard Worker     index += 4;
761*6236dae4SAndroid Build Coastguard Worker 
762*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 2))
763*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
764*6236dae4SAndroid Build Coastguard Worker 
765*6236dae4SAndroid Build Coastguard Worker     rdlength = doh_get16bit(doh, index);
766*6236dae4SAndroid Build Coastguard Worker     index += 2;
767*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + rdlength))
768*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
769*6236dae4SAndroid Build Coastguard Worker 
770*6236dae4SAndroid Build Coastguard Worker     rc = doh_rdata(doh, dohlen, rdlength, type, (int)index, d);
771*6236dae4SAndroid Build Coastguard Worker     if(rc)
772*6236dae4SAndroid Build Coastguard Worker       return rc; /* bad doh_rdata */
773*6236dae4SAndroid Build Coastguard Worker     index += rdlength;
774*6236dae4SAndroid Build Coastguard Worker     ancount--;
775*6236dae4SAndroid Build Coastguard Worker   }
776*6236dae4SAndroid Build Coastguard Worker 
777*6236dae4SAndroid Build Coastguard Worker   nscount = doh_get16bit(doh, 8);
778*6236dae4SAndroid Build Coastguard Worker   while(nscount) {
779*6236dae4SAndroid Build Coastguard Worker     rc = doh_skipqname(doh, dohlen, &index);
780*6236dae4SAndroid Build Coastguard Worker     if(rc)
781*6236dae4SAndroid Build Coastguard Worker       return rc; /* bad qname */
782*6236dae4SAndroid Build Coastguard Worker 
783*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 8))
784*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
785*6236dae4SAndroid Build Coastguard Worker 
786*6236dae4SAndroid Build Coastguard Worker     index += 2 + 2 + 4; /* type, class and ttl */
787*6236dae4SAndroid Build Coastguard Worker 
788*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 2))
789*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
790*6236dae4SAndroid Build Coastguard Worker 
791*6236dae4SAndroid Build Coastguard Worker     rdlength = doh_get16bit(doh, index);
792*6236dae4SAndroid Build Coastguard Worker     index += 2;
793*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + rdlength))
794*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
795*6236dae4SAndroid Build Coastguard Worker     index += rdlength;
796*6236dae4SAndroid Build Coastguard Worker     nscount--;
797*6236dae4SAndroid Build Coastguard Worker   }
798*6236dae4SAndroid Build Coastguard Worker 
799*6236dae4SAndroid Build Coastguard Worker   arcount = doh_get16bit(doh, 10);
800*6236dae4SAndroid Build Coastguard Worker   while(arcount) {
801*6236dae4SAndroid Build Coastguard Worker     rc = doh_skipqname(doh, dohlen, &index);
802*6236dae4SAndroid Build Coastguard Worker     if(rc)
803*6236dae4SAndroid Build Coastguard Worker       return rc; /* bad qname */
804*6236dae4SAndroid Build Coastguard Worker 
805*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 8))
806*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
807*6236dae4SAndroid Build Coastguard Worker 
808*6236dae4SAndroid Build Coastguard Worker     index += 2 + 2 + 4; /* type, class and ttl */
809*6236dae4SAndroid Build Coastguard Worker 
810*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + 2))
811*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
812*6236dae4SAndroid Build Coastguard Worker 
813*6236dae4SAndroid Build Coastguard Worker     rdlength = doh_get16bit(doh, index);
814*6236dae4SAndroid Build Coastguard Worker     index += 2;
815*6236dae4SAndroid Build Coastguard Worker     if(dohlen < (index + rdlength))
816*6236dae4SAndroid Build Coastguard Worker       return DOH_DNS_OUT_OF_RANGE;
817*6236dae4SAndroid Build Coastguard Worker     index += rdlength;
818*6236dae4SAndroid Build Coastguard Worker     arcount--;
819*6236dae4SAndroid Build Coastguard Worker   }
820*6236dae4SAndroid Build Coastguard Worker 
821*6236dae4SAndroid Build Coastguard Worker   if(index != dohlen)
822*6236dae4SAndroid Build Coastguard Worker     return DOH_DNS_MALFORMAT; /* something is wrong */
823*6236dae4SAndroid Build Coastguard Worker 
824*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTTPS
825*6236dae4SAndroid Build Coastguard Worker   if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr && !d->numhttps_rrs)
826*6236dae4SAndroid Build Coastguard Worker #else
827*6236dae4SAndroid Build Coastguard Worker   if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
828*6236dae4SAndroid Build Coastguard Worker #endif
829*6236dae4SAndroid Build Coastguard Worker     /* nothing stored! */
830*6236dae4SAndroid Build Coastguard Worker     return DOH_NO_CONTENT;
831*6236dae4SAndroid Build Coastguard Worker 
832*6236dae4SAndroid Build Coastguard Worker   return DOH_OK; /* ok */
833*6236dae4SAndroid Build Coastguard Worker }
834*6236dae4SAndroid Build Coastguard Worker 
835*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
doh_show(struct Curl_easy * data,const struct dohentry * d)836*6236dae4SAndroid Build Coastguard Worker static void doh_show(struct Curl_easy *data,
837*6236dae4SAndroid Build Coastguard Worker                      const struct dohentry *d)
838*6236dae4SAndroid Build Coastguard Worker {
839*6236dae4SAndroid Build Coastguard Worker   int i;
840*6236dae4SAndroid Build Coastguard Worker   infof(data, "[DoH] TTL: %u seconds", d->ttl);
841*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < d->numaddr; i++) {
842*6236dae4SAndroid Build Coastguard Worker     const struct dohaddr *a = &d->addr[i];
843*6236dae4SAndroid Build Coastguard Worker     if(a->type == DNS_TYPE_A) {
844*6236dae4SAndroid Build Coastguard Worker       infof(data, "[DoH] A: %u.%u.%u.%u",
845*6236dae4SAndroid Build Coastguard Worker             a->ip.v4[0], a->ip.v4[1],
846*6236dae4SAndroid Build Coastguard Worker             a->ip.v4[2], a->ip.v4[3]);
847*6236dae4SAndroid Build Coastguard Worker     }
848*6236dae4SAndroid Build Coastguard Worker     else if(a->type == DNS_TYPE_AAAA) {
849*6236dae4SAndroid Build Coastguard Worker       int j;
850*6236dae4SAndroid Build Coastguard Worker       char buffer[128] = "[DoH] AAAA: ";
851*6236dae4SAndroid Build Coastguard Worker       size_t len = strlen(buffer);
852*6236dae4SAndroid Build Coastguard Worker       char *ptr = &buffer[len];
853*6236dae4SAndroid Build Coastguard Worker       len = sizeof(buffer) - len;
854*6236dae4SAndroid Build Coastguard Worker       for(j = 0; j < 16; j += 2) {
855*6236dae4SAndroid Build Coastguard Worker         size_t l;
856*6236dae4SAndroid Build Coastguard Worker         msnprintf(ptr, len, "%s%02x%02x", j ? ":" : "", d->addr[i].ip.v6[j],
857*6236dae4SAndroid Build Coastguard Worker                   d->addr[i].ip.v6[j + 1]);
858*6236dae4SAndroid Build Coastguard Worker         l = strlen(ptr);
859*6236dae4SAndroid Build Coastguard Worker         len -= l;
860*6236dae4SAndroid Build Coastguard Worker         ptr += l;
861*6236dae4SAndroid Build Coastguard Worker       }
862*6236dae4SAndroid Build Coastguard Worker       infof(data, "%s", buffer);
863*6236dae4SAndroid Build Coastguard Worker     }
864*6236dae4SAndroid Build Coastguard Worker   }
865*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
866*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < d->numhttps_rrs; i++) {
867*6236dae4SAndroid Build Coastguard Worker # ifdef DEBUGBUILD
868*6236dae4SAndroid Build Coastguard Worker     doh_print_buf(data, "DoH HTTPS",
869*6236dae4SAndroid Build Coastguard Worker                   d->https_rrs[i].val, d->https_rrs[i].len);
870*6236dae4SAndroid Build Coastguard Worker # else
871*6236dae4SAndroid Build Coastguard Worker     infof(data, "DoH HTTPS RR: length %d", d->https_rrs[i].len);
872*6236dae4SAndroid Build Coastguard Worker # endif
873*6236dae4SAndroid Build Coastguard Worker   }
874*6236dae4SAndroid Build Coastguard Worker #endif
875*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < d->numcname; i++) {
876*6236dae4SAndroid Build Coastguard Worker     infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
877*6236dae4SAndroid Build Coastguard Worker   }
878*6236dae4SAndroid Build Coastguard Worker }
879*6236dae4SAndroid Build Coastguard Worker #else
880*6236dae4SAndroid Build Coastguard Worker #define doh_show(x,y)
881*6236dae4SAndroid Build Coastguard Worker #endif
882*6236dae4SAndroid Build Coastguard Worker 
883*6236dae4SAndroid Build Coastguard Worker /*
884*6236dae4SAndroid Build Coastguard Worker  * doh2ai()
885*6236dae4SAndroid Build Coastguard Worker  *
886*6236dae4SAndroid Build Coastguard Worker  * This function returns a pointer to the first element of a newly allocated
887*6236dae4SAndroid Build Coastguard Worker  * Curl_addrinfo struct linked list filled with the data from a set of DoH
888*6236dae4SAndroid Build Coastguard Worker  * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
889*6236dae4SAndroid Build Coastguard Worker  * a IPv6 stack, but usable also for IPv4, all hosts and environments.
890*6236dae4SAndroid Build Coastguard Worker  *
891*6236dae4SAndroid Build Coastguard Worker  * The memory allocated by this function *MUST* be free'd later on calling
892*6236dae4SAndroid Build Coastguard Worker  * Curl_freeaddrinfo(). For each successful call to this function there
893*6236dae4SAndroid Build Coastguard Worker  * must be an associated call later to Curl_freeaddrinfo().
894*6236dae4SAndroid Build Coastguard Worker  */
895*6236dae4SAndroid Build Coastguard Worker 
doh2ai(const struct dohentry * de,const char * hostname,int port,struct Curl_addrinfo ** aip)896*6236dae4SAndroid Build Coastguard Worker static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
897*6236dae4SAndroid Build Coastguard Worker                        int port, struct Curl_addrinfo **aip)
898*6236dae4SAndroid Build Coastguard Worker {
899*6236dae4SAndroid Build Coastguard Worker   struct Curl_addrinfo *ai;
900*6236dae4SAndroid Build Coastguard Worker   struct Curl_addrinfo *prevai = NULL;
901*6236dae4SAndroid Build Coastguard Worker   struct Curl_addrinfo *firstai = NULL;
902*6236dae4SAndroid Build Coastguard Worker   struct sockaddr_in *addr;
903*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
904*6236dae4SAndroid Build Coastguard Worker   struct sockaddr_in6 *addr6;
905*6236dae4SAndroid Build Coastguard Worker #endif
906*6236dae4SAndroid Build Coastguard Worker   CURLcode result = CURLE_OK;
907*6236dae4SAndroid Build Coastguard Worker   int i;
908*6236dae4SAndroid Build Coastguard Worker   size_t hostlen = strlen(hostname) + 1; /* include null-terminator */
909*6236dae4SAndroid Build Coastguard Worker 
910*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(de);
911*6236dae4SAndroid Build Coastguard Worker 
912*6236dae4SAndroid Build Coastguard Worker   if(!de->numaddr)
913*6236dae4SAndroid Build Coastguard Worker     return CURLE_COULDNT_RESOLVE_HOST;
914*6236dae4SAndroid Build Coastguard Worker 
915*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < de->numaddr; i++) {
916*6236dae4SAndroid Build Coastguard Worker     size_t ss_size;
917*6236dae4SAndroid Build Coastguard Worker     CURL_SA_FAMILY_T addrtype;
918*6236dae4SAndroid Build Coastguard Worker     if(de->addr[i].type == DNS_TYPE_AAAA) {
919*6236dae4SAndroid Build Coastguard Worker #ifndef USE_IPV6
920*6236dae4SAndroid Build Coastguard Worker       /* we cannot handle IPv6 addresses */
921*6236dae4SAndroid Build Coastguard Worker       continue;
922*6236dae4SAndroid Build Coastguard Worker #else
923*6236dae4SAndroid Build Coastguard Worker       ss_size = sizeof(struct sockaddr_in6);
924*6236dae4SAndroid Build Coastguard Worker       addrtype = AF_INET6;
925*6236dae4SAndroid Build Coastguard Worker #endif
926*6236dae4SAndroid Build Coastguard Worker     }
927*6236dae4SAndroid Build Coastguard Worker     else {
928*6236dae4SAndroid Build Coastguard Worker       ss_size = sizeof(struct sockaddr_in);
929*6236dae4SAndroid Build Coastguard Worker       addrtype = AF_INET;
930*6236dae4SAndroid Build Coastguard Worker     }
931*6236dae4SAndroid Build Coastguard Worker 
932*6236dae4SAndroid Build Coastguard Worker     ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen);
933*6236dae4SAndroid Build Coastguard Worker     if(!ai) {
934*6236dae4SAndroid Build Coastguard Worker       result = CURLE_OUT_OF_MEMORY;
935*6236dae4SAndroid Build Coastguard Worker       break;
936*6236dae4SAndroid Build Coastguard Worker     }
937*6236dae4SAndroid Build Coastguard Worker     ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
938*6236dae4SAndroid Build Coastguard Worker     ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size);
939*6236dae4SAndroid Build Coastguard Worker     memcpy(ai->ai_canonname, hostname, hostlen);
940*6236dae4SAndroid Build Coastguard Worker 
941*6236dae4SAndroid Build Coastguard Worker     if(!firstai)
942*6236dae4SAndroid Build Coastguard Worker       /* store the pointer we want to return from this function */
943*6236dae4SAndroid Build Coastguard Worker       firstai = ai;
944*6236dae4SAndroid Build Coastguard Worker 
945*6236dae4SAndroid Build Coastguard Worker     if(prevai)
946*6236dae4SAndroid Build Coastguard Worker       /* make the previous entry point to this */
947*6236dae4SAndroid Build Coastguard Worker       prevai->ai_next = ai;
948*6236dae4SAndroid Build Coastguard Worker 
949*6236dae4SAndroid Build Coastguard Worker     ai->ai_family = addrtype;
950*6236dae4SAndroid Build Coastguard Worker 
951*6236dae4SAndroid Build Coastguard Worker     /* we return all names as STREAM, so when using this address for TFTP
952*6236dae4SAndroid Build Coastguard Worker        the type must be ignored and conn->socktype be used instead! */
953*6236dae4SAndroid Build Coastguard Worker     ai->ai_socktype = SOCK_STREAM;
954*6236dae4SAndroid Build Coastguard Worker 
955*6236dae4SAndroid Build Coastguard Worker     ai->ai_addrlen = (curl_socklen_t)ss_size;
956*6236dae4SAndroid Build Coastguard Worker 
957*6236dae4SAndroid Build Coastguard Worker     /* leave the rest of the struct filled with zero */
958*6236dae4SAndroid Build Coastguard Worker 
959*6236dae4SAndroid Build Coastguard Worker     switch(ai->ai_family) {
960*6236dae4SAndroid Build Coastguard Worker     case AF_INET:
961*6236dae4SAndroid Build Coastguard Worker       addr = (void *)ai->ai_addr; /* storage area for this info */
962*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
963*6236dae4SAndroid Build Coastguard Worker       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
964*6236dae4SAndroid Build Coastguard Worker #ifdef __MINGW32__
965*6236dae4SAndroid Build Coastguard Worker       addr->sin_family = (short)addrtype;
966*6236dae4SAndroid Build Coastguard Worker #else
967*6236dae4SAndroid Build Coastguard Worker       addr->sin_family = addrtype;
968*6236dae4SAndroid Build Coastguard Worker #endif
969*6236dae4SAndroid Build Coastguard Worker       addr->sin_port = htons((unsigned short)port);
970*6236dae4SAndroid Build Coastguard Worker       break;
971*6236dae4SAndroid Build Coastguard Worker 
972*6236dae4SAndroid Build Coastguard Worker #ifdef USE_IPV6
973*6236dae4SAndroid Build Coastguard Worker     case AF_INET6:
974*6236dae4SAndroid Build Coastguard Worker       addr6 = (void *)ai->ai_addr; /* storage area for this info */
975*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
976*6236dae4SAndroid Build Coastguard Worker       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
977*6236dae4SAndroid Build Coastguard Worker #ifdef __MINGW32__
978*6236dae4SAndroid Build Coastguard Worker       addr6->sin6_family = (short)addrtype;
979*6236dae4SAndroid Build Coastguard Worker #else
980*6236dae4SAndroid Build Coastguard Worker       addr6->sin6_family = addrtype;
981*6236dae4SAndroid Build Coastguard Worker #endif
982*6236dae4SAndroid Build Coastguard Worker       addr6->sin6_port = htons((unsigned short)port);
983*6236dae4SAndroid Build Coastguard Worker       break;
984*6236dae4SAndroid Build Coastguard Worker #endif
985*6236dae4SAndroid Build Coastguard Worker     }
986*6236dae4SAndroid Build Coastguard Worker 
987*6236dae4SAndroid Build Coastguard Worker     prevai = ai;
988*6236dae4SAndroid Build Coastguard Worker   }
989*6236dae4SAndroid Build Coastguard Worker 
990*6236dae4SAndroid Build Coastguard Worker   if(result) {
991*6236dae4SAndroid Build Coastguard Worker     Curl_freeaddrinfo(firstai);
992*6236dae4SAndroid Build Coastguard Worker     firstai = NULL;
993*6236dae4SAndroid Build Coastguard Worker   }
994*6236dae4SAndroid Build Coastguard Worker   *aip = firstai;
995*6236dae4SAndroid Build Coastguard Worker 
996*6236dae4SAndroid Build Coastguard Worker   return result;
997*6236dae4SAndroid Build Coastguard Worker }
998*6236dae4SAndroid Build Coastguard Worker 
999*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
doh_type2name(DNStype dnstype)1000*6236dae4SAndroid Build Coastguard Worker static const char *doh_type2name(DNStype dnstype)
1001*6236dae4SAndroid Build Coastguard Worker {
1002*6236dae4SAndroid Build Coastguard Worker   switch(dnstype) {
1003*6236dae4SAndroid Build Coastguard Worker     case DNS_TYPE_A:
1004*6236dae4SAndroid Build Coastguard Worker       return "A";
1005*6236dae4SAndroid Build Coastguard Worker     case DNS_TYPE_AAAA:
1006*6236dae4SAndroid Build Coastguard Worker       return "AAAA";
1007*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
1008*6236dae4SAndroid Build Coastguard Worker     case DNS_TYPE_HTTPS:
1009*6236dae4SAndroid Build Coastguard Worker       return "HTTPS";
1010*6236dae4SAndroid Build Coastguard Worker #endif
1011*6236dae4SAndroid Build Coastguard Worker     default:
1012*6236dae4SAndroid Build Coastguard Worker        return "unknown";
1013*6236dae4SAndroid Build Coastguard Worker   }
1014*6236dae4SAndroid Build Coastguard Worker }
1015*6236dae4SAndroid Build Coastguard Worker #endif
1016*6236dae4SAndroid Build Coastguard Worker 
de_cleanup(struct dohentry * d)1017*6236dae4SAndroid Build Coastguard Worker UNITTEST void de_cleanup(struct dohentry *d)
1018*6236dae4SAndroid Build Coastguard Worker {
1019*6236dae4SAndroid Build Coastguard Worker   int i = 0;
1020*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < d->numcname; i++) {
1021*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_free(&d->cname[i]);
1022*6236dae4SAndroid Build Coastguard Worker   }
1023*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
1024*6236dae4SAndroid Build Coastguard Worker   for(i = 0; i < d->numhttps_rrs; i++)
1025*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(d->https_rrs[i].val);
1026*6236dae4SAndroid Build Coastguard Worker #endif
1027*6236dae4SAndroid Build Coastguard Worker }
1028*6236dae4SAndroid Build Coastguard Worker 
1029*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
1030*6236dae4SAndroid Build Coastguard Worker 
1031*6236dae4SAndroid Build Coastguard Worker /*
1032*6236dae4SAndroid Build Coastguard Worker  * @brief decode the DNS name in a binary RRData
1033*6236dae4SAndroid Build Coastguard Worker  * @param buf points to the buffer (in/out)
1034*6236dae4SAndroid Build Coastguard Worker  * @param remaining points to the remaining buffer length (in/out)
1035*6236dae4SAndroid Build Coastguard Worker  * @param dnsname returns the string form name on success
1036*6236dae4SAndroid Build Coastguard Worker  * @return is 1 for success, error otherwise
1037*6236dae4SAndroid Build Coastguard Worker  *
1038*6236dae4SAndroid Build Coastguard Worker  * The encoding here is defined in
1039*6236dae4SAndroid Build Coastguard Worker  * https://tools.ietf.org/html/rfc1035#section-3.1
1040*6236dae4SAndroid Build Coastguard Worker  *
1041*6236dae4SAndroid Build Coastguard Worker  * The input buffer pointer will be modified so it points to
1042*6236dae4SAndroid Build Coastguard Worker  * just after the end of the DNS name encoding on output. (And
1043*6236dae4SAndroid Build Coastguard Worker  * that is why it is an "unsigned char **" :-)
1044*6236dae4SAndroid Build Coastguard Worker  */
doh_decode_rdata_name(unsigned char ** buf,size_t * remaining,char ** dnsname)1045*6236dae4SAndroid Build Coastguard Worker static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
1046*6236dae4SAndroid Build Coastguard Worker                                       char **dnsname)
1047*6236dae4SAndroid Build Coastguard Worker {
1048*6236dae4SAndroid Build Coastguard Worker   unsigned char *cp = NULL;
1049*6236dae4SAndroid Build Coastguard Worker   int rem = 0;
1050*6236dae4SAndroid Build Coastguard Worker   unsigned char clen = 0; /* chunk len */
1051*6236dae4SAndroid Build Coastguard Worker   struct dynbuf thename;
1052*6236dae4SAndroid Build Coastguard Worker 
1053*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(buf && remaining && dnsname);
1054*6236dae4SAndroid Build Coastguard Worker   if(!buf || !remaining || !dnsname)
1055*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1056*6236dae4SAndroid Build Coastguard Worker   rem = (int)*remaining;
1057*6236dae4SAndroid Build Coastguard Worker   if(rem <= 0) {
1058*6236dae4SAndroid Build Coastguard Worker     Curl_dyn_free(&thename);
1059*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1060*6236dae4SAndroid Build Coastguard Worker   }
1061*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&thename, CURL_MAXLEN_host_name);
1062*6236dae4SAndroid Build Coastguard Worker   cp = *buf;
1063*6236dae4SAndroid Build Coastguard Worker   clen = *cp++;
1064*6236dae4SAndroid Build Coastguard Worker   if(clen == 0) {
1065*6236dae4SAndroid Build Coastguard Worker     /* special case - return "." as name */
1066*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_addn(&thename, ".", 1))
1067*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
1068*6236dae4SAndroid Build Coastguard Worker   }
1069*6236dae4SAndroid Build Coastguard Worker   while(clen) {
1070*6236dae4SAndroid Build Coastguard Worker     if(clen >= rem) {
1071*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_free(&thename);
1072*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
1073*6236dae4SAndroid Build Coastguard Worker     }
1074*6236dae4SAndroid Build Coastguard Worker     if(Curl_dyn_addn(&thename, cp, clen) ||
1075*6236dae4SAndroid Build Coastguard Worker        Curl_dyn_addn(&thename, ".", 1))
1076*6236dae4SAndroid Build Coastguard Worker       return CURLE_TOO_LARGE;
1077*6236dae4SAndroid Build Coastguard Worker 
1078*6236dae4SAndroid Build Coastguard Worker     cp += clen;
1079*6236dae4SAndroid Build Coastguard Worker     rem -= (clen + 1);
1080*6236dae4SAndroid Build Coastguard Worker     if(rem <= 0) {
1081*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_free(&thename);
1082*6236dae4SAndroid Build Coastguard Worker       return CURLE_OUT_OF_MEMORY;
1083*6236dae4SAndroid Build Coastguard Worker     }
1084*6236dae4SAndroid Build Coastguard Worker     clen = *cp++;
1085*6236dae4SAndroid Build Coastguard Worker   }
1086*6236dae4SAndroid Build Coastguard Worker   *buf = cp;
1087*6236dae4SAndroid Build Coastguard Worker   *remaining = rem - 1;
1088*6236dae4SAndroid Build Coastguard Worker   *dnsname = Curl_dyn_ptr(&thename);
1089*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1090*6236dae4SAndroid Build Coastguard Worker }
1091*6236dae4SAndroid Build Coastguard Worker 
doh_decode_rdata_alpn(unsigned char * rrval,size_t len,char ** alpns)1092*6236dae4SAndroid Build Coastguard Worker static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
1093*6236dae4SAndroid Build Coastguard Worker                                       char **alpns)
1094*6236dae4SAndroid Build Coastguard Worker {
1095*6236dae4SAndroid Build Coastguard Worker   /*
1096*6236dae4SAndroid Build Coastguard Worker    * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
1097*6236dae4SAndroid Build Coastguard Worker    * encoding is catenated list of strings each preceded by a one
1098*6236dae4SAndroid Build Coastguard Worker    * octet length
1099*6236dae4SAndroid Build Coastguard Worker    * output is comma-sep list of the strings
1100*6236dae4SAndroid Build Coastguard Worker    * implementations may or may not handle quoting of comma within
1101*6236dae4SAndroid Build Coastguard Worker    * string values, so we might see a comma within the wire format
1102*6236dae4SAndroid Build Coastguard Worker    * version of a string, in which case we will precede that by a
1103*6236dae4SAndroid Build Coastguard Worker    * backslash - same goes for a backslash character, and of course
1104*6236dae4SAndroid Build Coastguard Worker    * we need to use two backslashes in strings when we mean one;-)
1105*6236dae4SAndroid Build Coastguard Worker    */
1106*6236dae4SAndroid Build Coastguard Worker   int remaining = (int) len;
1107*6236dae4SAndroid Build Coastguard Worker   char *oval;
1108*6236dae4SAndroid Build Coastguard Worker   size_t i;
1109*6236dae4SAndroid Build Coastguard Worker   unsigned char *cp = rrval;
1110*6236dae4SAndroid Build Coastguard Worker   struct dynbuf dval;
1111*6236dae4SAndroid Build Coastguard Worker 
1112*6236dae4SAndroid Build Coastguard Worker   if(!alpns)
1113*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1114*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
1115*6236dae4SAndroid Build Coastguard Worker   remaining = (int)len;
1116*6236dae4SAndroid Build Coastguard Worker   cp = rrval;
1117*6236dae4SAndroid Build Coastguard Worker   while(remaining > 0) {
1118*6236dae4SAndroid Build Coastguard Worker     size_t tlen = (size_t) *cp++;
1119*6236dae4SAndroid Build Coastguard Worker 
1120*6236dae4SAndroid Build Coastguard Worker     /* if not 1st time, add comma */
1121*6236dae4SAndroid Build Coastguard Worker     if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
1122*6236dae4SAndroid Build Coastguard Worker       goto err;
1123*6236dae4SAndroid Build Coastguard Worker     remaining--;
1124*6236dae4SAndroid Build Coastguard Worker     if(tlen > (size_t)remaining)
1125*6236dae4SAndroid Build Coastguard Worker       goto err;
1126*6236dae4SAndroid Build Coastguard Worker     /* add escape char if needed, clunky but easier to read */
1127*6236dae4SAndroid Build Coastguard Worker     for(i = 0; i != tlen; i++) {
1128*6236dae4SAndroid Build Coastguard Worker       if('\\' == *cp || ',' == *cp) {
1129*6236dae4SAndroid Build Coastguard Worker         if(Curl_dyn_addn(&dval, "\\", 1))
1130*6236dae4SAndroid Build Coastguard Worker           goto err;
1131*6236dae4SAndroid Build Coastguard Worker       }
1132*6236dae4SAndroid Build Coastguard Worker       if(Curl_dyn_addn(&dval, cp++, 1))
1133*6236dae4SAndroid Build Coastguard Worker         goto err;
1134*6236dae4SAndroid Build Coastguard Worker     }
1135*6236dae4SAndroid Build Coastguard Worker     remaining -= (int)tlen;
1136*6236dae4SAndroid Build Coastguard Worker   }
1137*6236dae4SAndroid Build Coastguard Worker   /* this string is always null terminated */
1138*6236dae4SAndroid Build Coastguard Worker   oval = Curl_dyn_ptr(&dval);
1139*6236dae4SAndroid Build Coastguard Worker   if(!oval)
1140*6236dae4SAndroid Build Coastguard Worker     goto err;
1141*6236dae4SAndroid Build Coastguard Worker   *alpns = oval;
1142*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1143*6236dae4SAndroid Build Coastguard Worker err:
1144*6236dae4SAndroid Build Coastguard Worker   Curl_dyn_free(&dval);
1145*6236dae4SAndroid Build Coastguard Worker   return CURLE_BAD_CONTENT_ENCODING;
1146*6236dae4SAndroid Build Coastguard Worker }
1147*6236dae4SAndroid Build Coastguard Worker 
1148*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
doh_test_alpn_escapes(void)1149*6236dae4SAndroid Build Coastguard Worker static CURLcode doh_test_alpn_escapes(void)
1150*6236dae4SAndroid Build Coastguard Worker {
1151*6236dae4SAndroid Build Coastguard Worker   /* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
1152*6236dae4SAndroid Build Coastguard Worker   static unsigned char example[] = {
1153*6236dae4SAndroid Build Coastguard Worker     0x08,                                           /* length 8 */
1154*6236dae4SAndroid Build Coastguard Worker     0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
1155*6236dae4SAndroid Build Coastguard Worker     0x02,                                           /* length 2 */
1156*6236dae4SAndroid Build Coastguard Worker     0x68, 0x32                                      /* value "h2" */
1157*6236dae4SAndroid Build Coastguard Worker   };
1158*6236dae4SAndroid Build Coastguard Worker   size_t example_len = sizeof(example);
1159*6236dae4SAndroid Build Coastguard Worker   char *aval = NULL;
1160*6236dae4SAndroid Build Coastguard Worker   static const char *expected = "f\\\\oo\\,bar,h2";
1161*6236dae4SAndroid Build Coastguard Worker 
1162*6236dae4SAndroid Build Coastguard Worker   if(doh_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
1163*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
1164*6236dae4SAndroid Build Coastguard Worker   if(strlen(aval) != strlen(expected))
1165*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
1166*6236dae4SAndroid Build Coastguard Worker   if(memcmp(aval, expected, strlen(aval)))
1167*6236dae4SAndroid Build Coastguard Worker     return CURLE_BAD_CONTENT_ENCODING;
1168*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1169*6236dae4SAndroid Build Coastguard Worker }
1170*6236dae4SAndroid Build Coastguard Worker #endif
1171*6236dae4SAndroid Build Coastguard Worker 
doh_resp_decode_httpsrr(unsigned char * rrval,size_t len,struct Curl_https_rrinfo ** hrr)1172*6236dae4SAndroid Build Coastguard Worker static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
1173*6236dae4SAndroid Build Coastguard Worker                                         struct Curl_https_rrinfo **hrr)
1174*6236dae4SAndroid Build Coastguard Worker {
1175*6236dae4SAndroid Build Coastguard Worker   size_t remaining = len;
1176*6236dae4SAndroid Build Coastguard Worker   unsigned char *cp = rrval;
1177*6236dae4SAndroid Build Coastguard Worker   uint16_t pcode = 0, plen = 0;
1178*6236dae4SAndroid Build Coastguard Worker   struct Curl_https_rrinfo *lhrr = NULL;
1179*6236dae4SAndroid Build Coastguard Worker   char *dnsname = NULL;
1180*6236dae4SAndroid Build Coastguard Worker 
1181*6236dae4SAndroid Build Coastguard Worker #ifdef DEBUGBUILD
1182*6236dae4SAndroid Build Coastguard Worker   /* a few tests of escaping, should not be here but ok for now */
1183*6236dae4SAndroid Build Coastguard Worker   if(doh_test_alpn_escapes() != CURLE_OK)
1184*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1185*6236dae4SAndroid Build Coastguard Worker #endif
1186*6236dae4SAndroid Build Coastguard Worker   lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
1187*6236dae4SAndroid Build Coastguard Worker   if(!lhrr)
1188*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1189*6236dae4SAndroid Build Coastguard Worker   lhrr->val = Curl_memdup(rrval, len);
1190*6236dae4SAndroid Build Coastguard Worker   if(!lhrr->val)
1191*6236dae4SAndroid Build Coastguard Worker     goto err;
1192*6236dae4SAndroid Build Coastguard Worker   lhrr->len = len;
1193*6236dae4SAndroid Build Coastguard Worker   if(remaining <= 2)
1194*6236dae4SAndroid Build Coastguard Worker     goto err;
1195*6236dae4SAndroid Build Coastguard Worker   lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
1196*6236dae4SAndroid Build Coastguard Worker   cp += 2;
1197*6236dae4SAndroid Build Coastguard Worker   remaining -= (uint16_t)2;
1198*6236dae4SAndroid Build Coastguard Worker   if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
1199*6236dae4SAndroid Build Coastguard Worker     goto err;
1200*6236dae4SAndroid Build Coastguard Worker   lhrr->target = dnsname;
1201*6236dae4SAndroid Build Coastguard Worker   while(remaining >= 4) {
1202*6236dae4SAndroid Build Coastguard Worker     pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
1203*6236dae4SAndroid Build Coastguard Worker     cp += 2;
1204*6236dae4SAndroid Build Coastguard Worker     plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
1205*6236dae4SAndroid Build Coastguard Worker     cp += 2;
1206*6236dae4SAndroid Build Coastguard Worker     remaining -= 4;
1207*6236dae4SAndroid Build Coastguard Worker     if(pcode == HTTPS_RR_CODE_ALPN) {
1208*6236dae4SAndroid Build Coastguard Worker       if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
1209*6236dae4SAndroid Build Coastguard Worker         goto err;
1210*6236dae4SAndroid Build Coastguard Worker     }
1211*6236dae4SAndroid Build Coastguard Worker     if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
1212*6236dae4SAndroid Build Coastguard Worker       lhrr->no_def_alpn = TRUE;
1213*6236dae4SAndroid Build Coastguard Worker     else if(pcode == HTTPS_RR_CODE_IPV4) {
1214*6236dae4SAndroid Build Coastguard Worker       if(!plen)
1215*6236dae4SAndroid Build Coastguard Worker         goto err;
1216*6236dae4SAndroid Build Coastguard Worker       lhrr->ipv4hints = Curl_memdup(cp, plen);
1217*6236dae4SAndroid Build Coastguard Worker       if(!lhrr->ipv4hints)
1218*6236dae4SAndroid Build Coastguard Worker         goto err;
1219*6236dae4SAndroid Build Coastguard Worker       lhrr->ipv4hints_len = (size_t)plen;
1220*6236dae4SAndroid Build Coastguard Worker     }
1221*6236dae4SAndroid Build Coastguard Worker     else if(pcode == HTTPS_RR_CODE_ECH) {
1222*6236dae4SAndroid Build Coastguard Worker       if(!plen)
1223*6236dae4SAndroid Build Coastguard Worker         goto err;
1224*6236dae4SAndroid Build Coastguard Worker       lhrr->echconfiglist = Curl_memdup(cp, plen);
1225*6236dae4SAndroid Build Coastguard Worker       if(!lhrr->echconfiglist)
1226*6236dae4SAndroid Build Coastguard Worker         goto err;
1227*6236dae4SAndroid Build Coastguard Worker       lhrr->echconfiglist_len = (size_t)plen;
1228*6236dae4SAndroid Build Coastguard Worker     }
1229*6236dae4SAndroid Build Coastguard Worker     else if(pcode == HTTPS_RR_CODE_IPV6) {
1230*6236dae4SAndroid Build Coastguard Worker       if(!plen)
1231*6236dae4SAndroid Build Coastguard Worker         goto err;
1232*6236dae4SAndroid Build Coastguard Worker       lhrr->ipv6hints = Curl_memdup(cp, plen);
1233*6236dae4SAndroid Build Coastguard Worker       if(!lhrr->ipv6hints)
1234*6236dae4SAndroid Build Coastguard Worker         goto err;
1235*6236dae4SAndroid Build Coastguard Worker       lhrr->ipv6hints_len = (size_t)plen;
1236*6236dae4SAndroid Build Coastguard Worker     }
1237*6236dae4SAndroid Build Coastguard Worker     if(plen > 0 && plen <= remaining) {
1238*6236dae4SAndroid Build Coastguard Worker       cp += plen;
1239*6236dae4SAndroid Build Coastguard Worker       remaining -= plen;
1240*6236dae4SAndroid Build Coastguard Worker     }
1241*6236dae4SAndroid Build Coastguard Worker   }
1242*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(!remaining);
1243*6236dae4SAndroid Build Coastguard Worker   *hrr = lhrr;
1244*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1245*6236dae4SAndroid Build Coastguard Worker err:
1246*6236dae4SAndroid Build Coastguard Worker   if(lhrr) {
1247*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(lhrr->target);
1248*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(lhrr->echconfiglist);
1249*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(lhrr->val);
1250*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(lhrr->alpns);
1251*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(lhrr);
1252*6236dae4SAndroid Build Coastguard Worker   }
1253*6236dae4SAndroid Build Coastguard Worker   return CURLE_OUT_OF_MEMORY;
1254*6236dae4SAndroid Build Coastguard Worker }
1255*6236dae4SAndroid Build Coastguard Worker 
1256*6236dae4SAndroid Build Coastguard Worker # ifdef DEBUGBUILD
doh_print_httpsrr(struct Curl_easy * data,struct Curl_https_rrinfo * hrr)1257*6236dae4SAndroid Build Coastguard Worker static void doh_print_httpsrr(struct Curl_easy *data,
1258*6236dae4SAndroid Build Coastguard Worker                               struct Curl_https_rrinfo *hrr)
1259*6236dae4SAndroid Build Coastguard Worker {
1260*6236dae4SAndroid Build Coastguard Worker   DEBUGASSERT(hrr);
1261*6236dae4SAndroid Build Coastguard Worker   infof(data, "HTTPS RR: priority %d, target: %s",
1262*6236dae4SAndroid Build Coastguard Worker         hrr->priority, hrr->target);
1263*6236dae4SAndroid Build Coastguard Worker   if(hrr->alpns)
1264*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: alpns %s", hrr->alpns);
1265*6236dae4SAndroid Build Coastguard Worker   else
1266*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no alpns");
1267*6236dae4SAndroid Build Coastguard Worker   if(hrr->no_def_alpn)
1268*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no_def_alpn set");
1269*6236dae4SAndroid Build Coastguard Worker   else
1270*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no_def_alpn not set");
1271*6236dae4SAndroid Build Coastguard Worker   if(hrr->ipv4hints) {
1272*6236dae4SAndroid Build Coastguard Worker     doh_print_buf(data, "HTTPS RR: ipv4hints",
1273*6236dae4SAndroid Build Coastguard Worker                   hrr->ipv4hints, hrr->ipv4hints_len);
1274*6236dae4SAndroid Build Coastguard Worker   }
1275*6236dae4SAndroid Build Coastguard Worker   else
1276*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no ipv4hints");
1277*6236dae4SAndroid Build Coastguard Worker   if(hrr->echconfiglist) {
1278*6236dae4SAndroid Build Coastguard Worker     doh_print_buf(data, "HTTPS RR: ECHConfigList",
1279*6236dae4SAndroid Build Coastguard Worker                   hrr->echconfiglist, hrr->echconfiglist_len);
1280*6236dae4SAndroid Build Coastguard Worker   }
1281*6236dae4SAndroid Build Coastguard Worker   else
1282*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no ECHConfigList");
1283*6236dae4SAndroid Build Coastguard Worker   if(hrr->ipv6hints) {
1284*6236dae4SAndroid Build Coastguard Worker     doh_print_buf(data, "HTTPS RR: ipv6hint",
1285*6236dae4SAndroid Build Coastguard Worker                   hrr->ipv6hints, hrr->ipv6hints_len);
1286*6236dae4SAndroid Build Coastguard Worker   }
1287*6236dae4SAndroid Build Coastguard Worker   else
1288*6236dae4SAndroid Build Coastguard Worker     infof(data, "HTTPS RR: no ipv6hints");
1289*6236dae4SAndroid Build Coastguard Worker   return;
1290*6236dae4SAndroid Build Coastguard Worker }
1291*6236dae4SAndroid Build Coastguard Worker # endif
1292*6236dae4SAndroid Build Coastguard Worker #endif
1293*6236dae4SAndroid Build Coastguard Worker 
Curl_doh_is_resolved(struct Curl_easy * data,struct Curl_dns_entry ** dnsp)1294*6236dae4SAndroid Build Coastguard Worker CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
1295*6236dae4SAndroid Build Coastguard Worker                               struct Curl_dns_entry **dnsp)
1296*6236dae4SAndroid Build Coastguard Worker {
1297*6236dae4SAndroid Build Coastguard Worker   CURLcode result;
1298*6236dae4SAndroid Build Coastguard Worker   struct doh_probes *dohp = data->req.doh;
1299*6236dae4SAndroid Build Coastguard Worker   *dnsp = NULL; /* defaults to no response */
1300*6236dae4SAndroid Build Coastguard Worker   if(!dohp)
1301*6236dae4SAndroid Build Coastguard Worker     return CURLE_OUT_OF_MEMORY;
1302*6236dae4SAndroid Build Coastguard Worker 
1303*6236dae4SAndroid Build Coastguard Worker   if(dohp->probe[DOH_SLOT_IPV4].easy_mid < 0 &&
1304*6236dae4SAndroid Build Coastguard Worker      dohp->probe[DOH_SLOT_IPV6].easy_mid < 0) {
1305*6236dae4SAndroid Build Coastguard Worker     failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
1306*6236dae4SAndroid Build Coastguard Worker     return CONN_IS_PROXIED(data->conn) ? CURLE_COULDNT_RESOLVE_PROXY :
1307*6236dae4SAndroid Build Coastguard Worker       CURLE_COULDNT_RESOLVE_HOST;
1308*6236dae4SAndroid Build Coastguard Worker   }
1309*6236dae4SAndroid Build Coastguard Worker   else if(!dohp->pending) {
1310*6236dae4SAndroid Build Coastguard Worker     DOHcode rc[DOH_SLOT_COUNT];
1311*6236dae4SAndroid Build Coastguard Worker     struct dohentry de;
1312*6236dae4SAndroid Build Coastguard Worker     int slot;
1313*6236dae4SAndroid Build Coastguard Worker 
1314*6236dae4SAndroid Build Coastguard Worker     memset(rc, 0, sizeof(rc));
1315*6236dae4SAndroid Build Coastguard Worker     /* remove DoH handles from multi handle and close them */
1316*6236dae4SAndroid Build Coastguard Worker     Curl_doh_close(data);
1317*6236dae4SAndroid Build Coastguard Worker     /* parse the responses, create the struct and return it! */
1318*6236dae4SAndroid Build Coastguard Worker     de_init(&de);
1319*6236dae4SAndroid Build Coastguard Worker     for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
1320*6236dae4SAndroid Build Coastguard Worker       struct doh_probe *p = &dohp->probe[slot];
1321*6236dae4SAndroid Build Coastguard Worker       if(!p->dnstype)
1322*6236dae4SAndroid Build Coastguard Worker         continue;
1323*6236dae4SAndroid Build Coastguard Worker       rc[slot] = doh_resp_decode(Curl_dyn_uptr(&p->resp_body),
1324*6236dae4SAndroid Build Coastguard Worker                                  Curl_dyn_len(&p->resp_body),
1325*6236dae4SAndroid Build Coastguard Worker                                  p->dnstype, &de);
1326*6236dae4SAndroid Build Coastguard Worker       Curl_dyn_free(&p->resp_body);
1327*6236dae4SAndroid Build Coastguard Worker #ifndef CURL_DISABLE_VERBOSE_STRINGS
1328*6236dae4SAndroid Build Coastguard Worker       if(rc[slot]) {
1329*6236dae4SAndroid Build Coastguard Worker         infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
1330*6236dae4SAndroid Build Coastguard Worker               doh_type2name(p->dnstype), dohp->host);
1331*6236dae4SAndroid Build Coastguard Worker       }
1332*6236dae4SAndroid Build Coastguard Worker #endif
1333*6236dae4SAndroid Build Coastguard Worker     } /* next slot */
1334*6236dae4SAndroid Build Coastguard Worker 
1335*6236dae4SAndroid Build Coastguard Worker     result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
1336*6236dae4SAndroid Build Coastguard Worker     if(!rc[DOH_SLOT_IPV4] || !rc[DOH_SLOT_IPV6]) {
1337*6236dae4SAndroid Build Coastguard Worker       /* we have an address, of one kind or other */
1338*6236dae4SAndroid Build Coastguard Worker       struct Curl_dns_entry *dns;
1339*6236dae4SAndroid Build Coastguard Worker       struct Curl_addrinfo *ai;
1340*6236dae4SAndroid Build Coastguard Worker 
1341*6236dae4SAndroid Build Coastguard Worker 
1342*6236dae4SAndroid Build Coastguard Worker       if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
1343*6236dae4SAndroid Build Coastguard Worker         infof(data, "[DoH] hostname: %s", dohp->host);
1344*6236dae4SAndroid Build Coastguard Worker         doh_show(data, &de);
1345*6236dae4SAndroid Build Coastguard Worker       }
1346*6236dae4SAndroid Build Coastguard Worker 
1347*6236dae4SAndroid Build Coastguard Worker       result = doh2ai(&de, dohp->host, dohp->port, &ai);
1348*6236dae4SAndroid Build Coastguard Worker       if(result) {
1349*6236dae4SAndroid Build Coastguard Worker         de_cleanup(&de);
1350*6236dae4SAndroid Build Coastguard Worker         return result;
1351*6236dae4SAndroid Build Coastguard Worker       }
1352*6236dae4SAndroid Build Coastguard Worker 
1353*6236dae4SAndroid Build Coastguard Worker       if(data->share)
1354*6236dae4SAndroid Build Coastguard Worker         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
1355*6236dae4SAndroid Build Coastguard Worker 
1356*6236dae4SAndroid Build Coastguard Worker       /* we got a response, store it in the cache */
1357*6236dae4SAndroid Build Coastguard Worker       dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port, FALSE);
1358*6236dae4SAndroid Build Coastguard Worker 
1359*6236dae4SAndroid Build Coastguard Worker       if(data->share)
1360*6236dae4SAndroid Build Coastguard Worker         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
1361*6236dae4SAndroid Build Coastguard Worker 
1362*6236dae4SAndroid Build Coastguard Worker       if(!dns) {
1363*6236dae4SAndroid Build Coastguard Worker         /* returned failure, bail out nicely */
1364*6236dae4SAndroid Build Coastguard Worker         Curl_freeaddrinfo(ai);
1365*6236dae4SAndroid Build Coastguard Worker       }
1366*6236dae4SAndroid Build Coastguard Worker       else {
1367*6236dae4SAndroid Build Coastguard Worker         data->state.async.dns = dns;
1368*6236dae4SAndroid Build Coastguard Worker         *dnsp = dns;
1369*6236dae4SAndroid Build Coastguard Worker         result = CURLE_OK;      /* address resolution OK */
1370*6236dae4SAndroid Build Coastguard Worker       }
1371*6236dae4SAndroid Build Coastguard Worker     } /* address processing done */
1372*6236dae4SAndroid Build Coastguard Worker 
1373*6236dae4SAndroid Build Coastguard Worker     /* Now process any build-specific attributes retrieved from DNS */
1374*6236dae4SAndroid Build Coastguard Worker #ifdef USE_HTTPSRR
1375*6236dae4SAndroid Build Coastguard Worker     if(de.numhttps_rrs > 0 && result == CURLE_OK && *dnsp) {
1376*6236dae4SAndroid Build Coastguard Worker       struct Curl_https_rrinfo *hrr = NULL;
1377*6236dae4SAndroid Build Coastguard Worker       result = doh_resp_decode_httpsrr(de.https_rrs->val, de.https_rrs->len,
1378*6236dae4SAndroid Build Coastguard Worker                                        &hrr);
1379*6236dae4SAndroid Build Coastguard Worker       if(result) {
1380*6236dae4SAndroid Build Coastguard Worker         infof(data, "Failed to decode HTTPS RR");
1381*6236dae4SAndroid Build Coastguard Worker         return result;
1382*6236dae4SAndroid Build Coastguard Worker       }
1383*6236dae4SAndroid Build Coastguard Worker       infof(data, "Some HTTPS RR to process");
1384*6236dae4SAndroid Build Coastguard Worker # ifdef DEBUGBUILD
1385*6236dae4SAndroid Build Coastguard Worker       doh_print_httpsrr(data, hrr);
1386*6236dae4SAndroid Build Coastguard Worker # endif
1387*6236dae4SAndroid Build Coastguard Worker       (*dnsp)->hinfo = hrr;
1388*6236dae4SAndroid Build Coastguard Worker     }
1389*6236dae4SAndroid Build Coastguard Worker #endif
1390*6236dae4SAndroid Build Coastguard Worker 
1391*6236dae4SAndroid Build Coastguard Worker     /* All done */
1392*6236dae4SAndroid Build Coastguard Worker     de_cleanup(&de);
1393*6236dae4SAndroid Build Coastguard Worker     Curl_doh_cleanup(data);
1394*6236dae4SAndroid Build Coastguard Worker     return result;
1395*6236dae4SAndroid Build Coastguard Worker 
1396*6236dae4SAndroid Build Coastguard Worker   } /* !dohp->pending */
1397*6236dae4SAndroid Build Coastguard Worker 
1398*6236dae4SAndroid Build Coastguard Worker   /* else wait for pending DoH transactions to complete */
1399*6236dae4SAndroid Build Coastguard Worker   return CURLE_OK;
1400*6236dae4SAndroid Build Coastguard Worker }
1401*6236dae4SAndroid Build Coastguard Worker 
Curl_doh_close(struct Curl_easy * data)1402*6236dae4SAndroid Build Coastguard Worker void Curl_doh_close(struct Curl_easy *data)
1403*6236dae4SAndroid Build Coastguard Worker {
1404*6236dae4SAndroid Build Coastguard Worker   struct doh_probes *doh = data->req.doh;
1405*6236dae4SAndroid Build Coastguard Worker   if(doh && data->multi) {
1406*6236dae4SAndroid Build Coastguard Worker     struct Curl_easy *probe_data;
1407*6236dae4SAndroid Build Coastguard Worker     curl_off_t mid;
1408*6236dae4SAndroid Build Coastguard Worker     size_t slot;
1409*6236dae4SAndroid Build Coastguard Worker     for(slot = 0; slot < DOH_SLOT_COUNT; slot++) {
1410*6236dae4SAndroid Build Coastguard Worker       mid = doh->probe[slot].easy_mid;
1411*6236dae4SAndroid Build Coastguard Worker       if(mid < 0)
1412*6236dae4SAndroid Build Coastguard Worker         continue;
1413*6236dae4SAndroid Build Coastguard Worker       doh->probe[slot].easy_mid = -1;
1414*6236dae4SAndroid Build Coastguard Worker       /* should have been called before data is removed from multi handle */
1415*6236dae4SAndroid Build Coastguard Worker       DEBUGASSERT(data->multi);
1416*6236dae4SAndroid Build Coastguard Worker       probe_data = data->multi ? Curl_multi_get_handle(data->multi, mid) :
1417*6236dae4SAndroid Build Coastguard Worker         NULL;
1418*6236dae4SAndroid Build Coastguard Worker       if(!probe_data) {
1419*6236dae4SAndroid Build Coastguard Worker         DEBUGF(infof(data, "Curl_doh_close: xfer for mid=%"
1420*6236dae4SAndroid Build Coastguard Worker                      FMT_OFF_T " not found!",
1421*6236dae4SAndroid Build Coastguard Worker                      doh->probe[slot].easy_mid));
1422*6236dae4SAndroid Build Coastguard Worker         continue;
1423*6236dae4SAndroid Build Coastguard Worker       }
1424*6236dae4SAndroid Build Coastguard Worker       /* data->multi might already be reset at this time */
1425*6236dae4SAndroid Build Coastguard Worker       curl_multi_remove_handle(data->multi, probe_data);
1426*6236dae4SAndroid Build Coastguard Worker       Curl_close(&probe_data);
1427*6236dae4SAndroid Build Coastguard Worker     }
1428*6236dae4SAndroid Build Coastguard Worker   }
1429*6236dae4SAndroid Build Coastguard Worker }
1430*6236dae4SAndroid Build Coastguard Worker 
Curl_doh_cleanup(struct Curl_easy * data)1431*6236dae4SAndroid Build Coastguard Worker void Curl_doh_cleanup(struct Curl_easy *data)
1432*6236dae4SAndroid Build Coastguard Worker {
1433*6236dae4SAndroid Build Coastguard Worker   struct doh_probes *doh = data->req.doh;
1434*6236dae4SAndroid Build Coastguard Worker   if(doh) {
1435*6236dae4SAndroid Build Coastguard Worker     Curl_doh_close(data);
1436*6236dae4SAndroid Build Coastguard Worker     curl_slist_free_all(doh->req_hds);
1437*6236dae4SAndroid Build Coastguard Worker     data->req.doh->req_hds = NULL;
1438*6236dae4SAndroid Build Coastguard Worker     Curl_safefree(data->req.doh);
1439*6236dae4SAndroid Build Coastguard Worker   }
1440*6236dae4SAndroid Build Coastguard Worker }
1441*6236dae4SAndroid Build Coastguard Worker 
1442*6236dae4SAndroid Build Coastguard Worker #endif /* CURL_DISABLE_DOH */
1443