blob: de0c902b860649f03d49bbc698d49f388c4f5882 [file] [log] [blame]
Elliott Hughesa93fb052018-12-12 14:22:48 -08001/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
Elliott Hughes34dd5f42021-08-10 13:01:18 -07008 * Copyright (C) 2018 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
Elliott Hughesa93fb052018-12-12 14:22:48 -08009 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
Elliott Hughes34dd5f42021-08-10 13:01:18 -070012 * are also available at https://curl.se/docs/copyright.html.
Elliott Hughesa93fb052018-12-12 14:22:48 -080013 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
Haibo Huang34ab3462019-05-22 00:50:27 -070025#ifndef CURL_DISABLE_DOH
26
Elliott Hughesa93fb052018-12-12 14:22:48 -080027#include "urldata.h"
28#include "curl_addrinfo.h"
29#include "doh.h"
30
Elliott Hughesa93fb052018-12-12 14:22:48 -080031#include "sendf.h"
32#include "multiif.h"
33#include "url.h"
34#include "share.h"
35#include "curl_base64.h"
36#include "connect.h"
Haibo Huang21926d52019-01-08 14:27:10 -080037#include "strdup.h"
Haibo Huangca2a8022020-07-10 20:17:42 -070038#include "dynbuf.h"
Elliott Hughesa93fb052018-12-12 14:22:48 -080039/* The last 3 #include files should be in this order */
40#include "curl_printf.h"
41#include "curl_memory.h"
42#include "memdebug.h"
43
44#define DNS_CLASS_IN 0x01
Elliott Hughesa93fb052018-12-12 14:22:48 -080045
46#ifndef CURL_DISABLE_VERBOSE_STRINGS
47static const char * const errors[]={
48 "",
49 "Bad label",
50 "Out of range",
51 "Label loop",
52 "Too small",
53 "Out of memory",
54 "RDATA length",
55 "Malformat",
56 "Bad RCODE",
57 "Unexpected TYPE",
58 "Unexpected CLASS",
59 "No content",
Haibo Huangb5a52b92020-10-28 22:18:23 -070060 "Bad ID",
61 "Name too long"
Elliott Hughesa93fb052018-12-12 14:22:48 -080062};
63
64static const char *doh_strerror(DOHcode code)
65{
Haibo Huangb5a52b92020-10-28 22:18:23 -070066 if((code >= DOH_OK) && (code <= DOH_DNS_NAME_TOO_LONG))
Elliott Hughesa93fb052018-12-12 14:22:48 -080067 return errors[code];
68 return "bad error code";
69}
70#endif
71
72#ifdef DEBUGBUILD
73#define UNITTEST
74#else
75#define UNITTEST static
76#endif
77
Haibo Huang31944072019-11-06 02:28:57 -080078/* @unittest 1655
79 */
Elliott Hughesa93fb052018-12-12 14:22:48 -080080UNITTEST DOHcode doh_encode(const char *host,
81 DNStype dnstype,
82 unsigned char *dnsp, /* buffer */
83 size_t len, /* buffer size */
84 size_t *olen) /* output length */
85{
Haibo Huang31944072019-11-06 02:28:57 -080086 const size_t hostlen = strlen(host);
Elliott Hughesa93fb052018-12-12 14:22:48 -080087 unsigned char *orig = dnsp;
88 const char *hostp = host;
89
Haibo Huangb51266f2020-03-04 02:22:48 -080090 /* The expected output length is 16 bytes more than the length of
91 * the QNAME-encoding of the host name.
92 *
93 * A valid DNS name may not contain a zero-length label, except at
94 * the end. For this reason, a name beginning with a dot, or
95 * containing a sequence of two or more consecutive dots, is invalid
96 * and cannot be encoded as a QNAME.
97 *
98 * If the host name ends with a trailing dot, the corresponding
99 * QNAME-encoding is one byte longer than the host name. If (as is
100 * also valid) the hostname is shortened by the omission of the
101 * trailing dot, then its QNAME-encoding will be two bytes longer
102 * than the host name.
103 *
104 * Each [ label, dot ] pair is encoded as [ length, label ],
105 * preserving overall length. A final [ label ] without a dot is
106 * also encoded as [ length, label ], increasing overall length
107 * by one. The encoding is completed by appending a zero byte,
108 * representing the zero-length root label, again increasing
109 * the overall length by one.
Haibo Huang31944072019-11-06 02:28:57 -0800110 */
Haibo Huangb51266f2020-03-04 02:22:48 -0800111
112 size_t expected_len;
113 DEBUGASSERT(hostlen);
114 expected_len = 12 + 1 + hostlen + 4;
115 if(host[hostlen-1]!='.')
116 expected_len++;
117
118 if(expected_len > (256 + 16)) /* RFCs 1034, 1035 */
119 return DOH_DNS_NAME_TOO_LONG;
Haibo Huang31944072019-11-06 02:28:57 -0800120
121 if(len < expected_len)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800122 return DOH_TOO_SMALL_BUFFER;
123
124 *dnsp++ = 0; /* 16 bit id */
125 *dnsp++ = 0;
126 *dnsp++ = 0x01; /* |QR| Opcode |AA|TC|RD| Set the RD bit */
127 *dnsp++ = '\0'; /* |RA| Z | RCODE | */
128 *dnsp++ = '\0';
129 *dnsp++ = 1; /* QDCOUNT (number of entries in the question section) */
130 *dnsp++ = '\0';
131 *dnsp++ = '\0'; /* ANCOUNT */
132 *dnsp++ = '\0';
133 *dnsp++ = '\0'; /* NSCOUNT */
134 *dnsp++ = '\0';
135 *dnsp++ = '\0'; /* ARCOUNT */
136
Haibo Huangb51266f2020-03-04 02:22:48 -0800137 /* encode each label and store it in the QNAME */
138 while(*hostp) {
Elliott Hughesa93fb052018-12-12 14:22:48 -0800139 size_t labellen;
Haibo Huangb51266f2020-03-04 02:22:48 -0800140 char *dot = strchr(hostp, '.');
141 if(dot)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800142 labellen = dot - hostp;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800143 else
144 labellen = strlen(hostp);
Haibo Huangb51266f2020-03-04 02:22:48 -0800145 if((labellen > 63) || (!labellen)) {
146 /* label is too long or too short, error out */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800147 *olen = 0;
148 return DOH_DNS_BAD_LABEL;
149 }
Haibo Huangb51266f2020-03-04 02:22:48 -0800150 /* label is non-empty, process it */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800151 *dnsp++ = (unsigned char)labellen;
152 memcpy(dnsp, hostp, labellen);
153 dnsp += labellen;
Haibo Huangb51266f2020-03-04 02:22:48 -0800154 hostp += labellen;
155 /* advance past dot, but only if there is one */
156 if(dot)
157 hostp++;
158 } /* next label */
159
160 *dnsp++ = 0; /* append zero-length label for root */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800161
Haibo Huang31944072019-11-06 02:28:57 -0800162 /* There are assigned TYPE codes beyond 255: use range [1..65535] */
163 *dnsp++ = (unsigned char)(255 & (dnstype>>8)); /* upper 8 bit TYPE */
164 *dnsp++ = (unsigned char)(255 & dnstype); /* lower 8 bit TYPE */
165
Elliott Hughesa93fb052018-12-12 14:22:48 -0800166 *dnsp++ = '\0'; /* upper 8 bit CLASS */
167 *dnsp++ = DNS_CLASS_IN; /* IN - "the Internet" */
168
169 *olen = dnsp - orig;
Haibo Huang31944072019-11-06 02:28:57 -0800170
Haibo Huangb51266f2020-03-04 02:22:48 -0800171 /* verify that our estimation of length is valid, since
172 * this has led to buffer overflows in this function */
Haibo Huang31944072019-11-06 02:28:57 -0800173 DEBUGASSERT(*olen == expected_len);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800174 return DOH_OK;
175}
176
177static size_t
Haibo Huang24c77a12020-04-29 13:49:57 -0700178doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800179{
180 size_t realsize = size * nmemb;
Haibo Huangca2a8022020-07-10 20:17:42 -0700181 struct dynbuf *mem = (struct dynbuf *)userp;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800182
Haibo Huangca2a8022020-07-10 20:17:42 -0700183 if(Curl_dyn_addn(mem, contents, realsize))
Elliott Hughesa93fb052018-12-12 14:22:48 -0800184 return 0;
185
Elliott Hughesa93fb052018-12-12 14:22:48 -0800186 return realsize;
187}
188
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700189/* called from multi.c when this DoH transfer is complete */
190static int doh_done(struct Curl_easy *doh, CURLcode result)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800191{
192 struct Curl_easy *data = doh->set.dohfor;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700193 struct dohdata *dohp = data->req.doh;
194 /* so one of the DoH request done for the 'data' transfer is now complete! */
195 dohp->pending--;
196 infof(data, "a DoH request is completed, %u to go", dohp->pending);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800197 if(result)
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700198 infof(data, "DoH request %s", curl_easy_strerror(result));
Elliott Hughesa93fb052018-12-12 14:22:48 -0800199
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700200 if(!dohp->pending) {
201 /* DoH completed */
202 curl_slist_free_all(dohp->headers);
203 dohp->headers = NULL;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800204 Curl_expire(data, 0, EXPIRE_RUN_NOW);
205 }
206 return 0;
207}
208
Haibo Huang65021c72019-03-27 15:37:23 -0700209#define ERROR_CHECK_SETOPT(x,y) \
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700210do { \
211 result = curl_easy_setopt(doh, x, y); \
212 if(result && \
213 result != CURLE_NOT_BUILT_IN && \
214 result != CURLE_UNKNOWN_OPTION) \
215 goto error; \
Haibo Huangb51266f2020-03-04 02:22:48 -0800216} while(0)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800217
218static CURLcode dohprobe(struct Curl_easy *data,
219 struct dnsprobe *p, DNStype dnstype,
220 const char *host,
221 const char *url, CURLM *multi,
222 struct curl_slist *headers)
223{
224 struct Curl_easy *doh = NULL;
225 char *nurl = NULL;
226 CURLcode result = CURLE_OK;
227 timediff_t timeout_ms;
228 DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
229 &p->dohlen);
230 if(d) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700231 failf(data, "Failed to encode DoH packet [%d]", d);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800232 return CURLE_OUT_OF_MEMORY;
233 }
234
235 p->dnstype = dnstype;
Haibo Huangca2a8022020-07-10 20:17:42 -0700236 Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800237
238 /* Note: this is code for sending the DoH request with GET but there's still
239 no logic that actually enables this. We should either add that ability or
240 yank out the GET code. Discuss! */
241 if(data->set.doh_get) {
242 char *b64;
243 size_t b64len;
244 result = Curl_base64url_encode(data, (char *)p->dohbuffer, p->dohlen,
245 &b64, &b64len);
246 if(result)
247 goto error;
248 nurl = aprintf("%s?dns=%s", url, b64);
249 free(b64);
250 if(!nurl) {
251 result = CURLE_OUT_OF_MEMORY;
252 goto error;
253 }
254 url = nurl;
255 }
256
257 timeout_ms = Curl_timeleft(data, NULL, TRUE);
Haibo Huang31944072019-11-06 02:28:57 -0800258 if(timeout_ms <= 0) {
259 result = CURLE_OPERATION_TIMEDOUT;
260 goto error;
261 }
Elliott Hughesa93fb052018-12-12 14:22:48 -0800262 /* Curl_open() is the internal version of curl_easy_init() */
263 result = Curl_open(&doh);
264 if(!result) {
265 /* pass in the struct pointer via a local variable to please coverity and
266 the gcc typecheck helpers */
Haibo Huangca2a8022020-07-10 20:17:42 -0700267 struct dynbuf *resp = &p->serverdoh;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800268 ERROR_CHECK_SETOPT(CURLOPT_URL, url);
269 ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
270 ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
271 if(!data->set.doh_get) {
272 ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
273 ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
274 }
275 ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
Haibo Huang21926d52019-01-08 14:27:10 -0800276#ifdef USE_NGHTTP2
Elliott Hughesa93fb052018-12-12 14:22:48 -0800277 ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
Haibo Huang21926d52019-01-08 14:27:10 -0800278#endif
Elliott Hughesa93fb052018-12-12 14:22:48 -0800279#ifndef CURLDEBUG
280 /* enforce HTTPS if not debug */
281 ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
Haibo Huang31944072019-11-06 02:28:57 -0800282#else
283 /* in debug mode, also allow http */
284 ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800285#endif
286 ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700287 ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
288 if(data->set.err && data->set.err != stderr)
289 ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
Haibo Huang65021c72019-03-27 15:37:23 -0700290 if(data->set.verbose)
291 ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
292 if(data->set.no_signal)
293 ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
294
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700295 ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
296 data->set.doh_verifyhost ? 2L : 0L);
297 ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
298 data->set.doh_verifypeer ? 1L : 0L);
299 ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
300 data->set.doh_verifystatus ? 1L : 0L);
301
Haibo Huang65021c72019-03-27 15:37:23 -0700302 /* Inherit *some* SSL options from the user's transfer. This is a
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700303 best-guess as to which options are needed for compatibility. #3661
304
305 Note DoH does not inherit the user's proxy server so proxy SSL settings
306 have no effect and are not inherited. If that changes then two new
307 options should be added to check doh proxy insecure separately,
308 CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
309 */
Haibo Huang65021c72019-03-27 15:37:23 -0700310 if(data->set.ssl.falsestart)
311 ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700312 if(data->set.str[STRING_SSL_CAFILE]) {
Haibo Huang65021c72019-03-27 15:37:23 -0700313 ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700314 data->set.str[STRING_SSL_CAFILE]);
Haibo Huang65021c72019-03-27 15:37:23 -0700315 }
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700316 if(data->set.blobs[BLOB_CAINFO]) {
317 ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
318 data->set.blobs[BLOB_CAINFO]);
319 }
320 if(data->set.str[STRING_SSL_CAPATH]) {
Haibo Huang65021c72019-03-27 15:37:23 -0700321 ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700322 data->set.str[STRING_SSL_CAPATH]);
Haibo Huang65021c72019-03-27 15:37:23 -0700323 }
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700324 if(data->set.str[STRING_SSL_CRLFILE]) {
Haibo Huang65021c72019-03-27 15:37:23 -0700325 ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700326 data->set.str[STRING_SSL_CRLFILE]);
Haibo Huang65021c72019-03-27 15:37:23 -0700327 }
Haibo Huang65021c72019-03-27 15:37:23 -0700328 if(data->set.ssl.certinfo)
329 ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
330 if(data->set.str[STRING_SSL_RANDOM_FILE]) {
331 ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700332 data->set.str[STRING_SSL_RANDOM_FILE]);
Haibo Huang65021c72019-03-27 15:37:23 -0700333 }
334 if(data->set.str[STRING_SSL_EGDSOCKET]) {
335 ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700336 data->set.str[STRING_SSL_EGDSOCKET]);
Haibo Huang65021c72019-03-27 15:37:23 -0700337 }
Haibo Huang65021c72019-03-27 15:37:23 -0700338 if(data->set.ssl.fsslctx)
339 ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
340 if(data->set.ssl.fsslctxp)
341 ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
Haibo Huangb5a52b92020-10-28 22:18:23 -0700342 if(data->set.str[STRING_SSL_EC_CURVES]) {
343 ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700344 data->set.str[STRING_SSL_EC_CURVES]);
Haibo Huangb5a52b92020-10-28 22:18:23 -0700345 }
Haibo Huang65021c72019-03-27 15:37:23 -0700346
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700347 {
348 long mask =
349 (data->set.ssl.enable_beast ?
350 CURLSSLOPT_ALLOW_BEAST : 0) |
351 (data->set.ssl.no_revoke ?
352 CURLSSLOPT_NO_REVOKE : 0) |
353 (data->set.ssl.no_partialchain ?
354 CURLSSLOPT_NO_PARTIALCHAIN : 0) |
355 (data->set.ssl.revoke_best_effort ?
356 CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
357 (data->set.ssl.native_ca_store ?
358 CURLSSLOPT_NATIVE_CA : 0) |
359 (data->set.ssl.auto_client_cert ?
360 CURLSSLOPT_AUTO_CLIENT_CERT : 0);
361
362 (void)curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
363 }
364
365 doh->set.fmultidone = doh_done;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800366 doh->set.dohfor = data; /* identify for which transfer this is done */
367 p->easy = doh;
368
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700369 /* DoH private_data must be null because the user must have a way to
370 distinguish their transfer's handle from DoH handles in user
371 callbacks (ie SSL CTX callback). */
372 DEBUGASSERT(!doh->set.private_data);
373
Elliott Hughesa93fb052018-12-12 14:22:48 -0800374 if(curl_multi_add_handle(multi, doh))
375 goto error;
376 }
377 else
378 goto error;
379 free(nurl);
380 return CURLE_OK;
381
382 error:
383 free(nurl);
Haibo Huang31944072019-11-06 02:28:57 -0800384 Curl_close(&doh);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800385 return result;
386}
387
388/*
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700389 * Curl_doh() resolves a name using DoH. It resolves a name and returns a
Elliott Hughesa93fb052018-12-12 14:22:48 -0800390 * 'Curl_addrinfo *' with the address information.
391 */
392
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700393struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
Haibo Huangca2a8022020-07-10 20:17:42 -0700394 const char *hostname,
395 int port,
396 int *waitp)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800397{
Elliott Hughesa93fb052018-12-12 14:22:48 -0800398 CURLcode result = CURLE_OK;
Haibo Huangb51266f2020-03-04 02:22:48 -0800399 int slot;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700400 struct dohdata *dohp;
401 struct connectdata *conn = data->conn;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800402 *waitp = TRUE; /* this never returns synchronously */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800403 (void)hostname;
404 (void)port;
405
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700406 DEBUGASSERT(!data->req.doh);
407 DEBUGASSERT(conn);
408
Elliott Hughesa93fb052018-12-12 14:22:48 -0800409 /* start clean, consider allocating this struct on demand */
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700410 dohp = data->req.doh = calloc(sizeof(struct dohdata), 1);
411 if(!dohp)
412 return NULL;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800413
Haibo Huangca2a8022020-07-10 20:17:42 -0700414 conn->bits.doh = TRUE;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700415 dohp->host = hostname;
416 dohp->port = port;
417 dohp->headers =
Elliott Hughesa93fb052018-12-12 14:22:48 -0800418 curl_slist_append(NULL,
419 "Content-Type: application/dns-message");
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700420 if(!dohp->headers)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800421 goto error;
422
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700423 /* create IPv4 DoH request */
424 result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
425 DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
426 data->multi, dohp->headers);
427 if(result)
428 goto error;
429 dohp->pending++;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800430
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700431 if(Curl_ipv6works(data)) {
432 /* create IPv6 DoH request */
433 result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
Haibo Huangb51266f2020-03-04 02:22:48 -0800434 DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700435 data->multi, dohp->headers);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800436 if(result)
437 goto error;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700438 dohp->pending++;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800439 }
440 return NULL;
441
442 error:
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700443 curl_slist_free_all(dohp->headers);
444 data->req.doh->headers = NULL;
Haibo Huangb51266f2020-03-04 02:22:48 -0800445 for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700446 Curl_close(&dohp->probe[slot].easy);
Haibo Huangb51266f2020-03-04 02:22:48 -0800447 }
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700448 Curl_safefree(data->req.doh);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800449 return NULL;
450}
451
Haibo Huang24c77a12020-04-29 13:49:57 -0700452static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
Elliott Hughesa93fb052018-12-12 14:22:48 -0800453 unsigned int *indexp)
454{
455 unsigned char length;
456 do {
457 if(dohlen < (*indexp + 1))
458 return DOH_DNS_OUT_OF_RANGE;
459 length = doh[*indexp];
460 if((length & 0xc0) == 0xc0) {
461 /* name pointer, advance over it and be done */
462 if(dohlen < (*indexp + 2))
463 return DOH_DNS_OUT_OF_RANGE;
464 *indexp += 2;
465 break;
466 }
467 if(length & 0xc0)
468 return DOH_DNS_BAD_LABEL;
469 if(dohlen < (*indexp + 1 + length))
470 return DOH_DNS_OUT_OF_RANGE;
471 *indexp += 1 + length;
472 } while(length);
473 return DOH_OK;
474}
475
Haibo Huang24c77a12020-04-29 13:49:57 -0700476static unsigned short get16bit(const unsigned char *doh, int index)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800477{
478 return (unsigned short)((doh[index] << 8) | doh[index + 1]);
479}
480
Haibo Huang24c77a12020-04-29 13:49:57 -0700481static unsigned int get32bit(const unsigned char *doh, int index)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800482{
Haibo Huang31944072019-11-06 02:28:57 -0800483 /* make clang and gcc optimize this to bswap by incrementing
484 the pointer first. */
485 doh += index;
486
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700487 /* avoid undefined behavior by casting to unsigned before shifting
Haibo Huang31944072019-11-06 02:28:57 -0800488 24 bits, possibly into the sign bit. codegen is same, but
489 ub sanitizer won't be upset */
490 return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
Elliott Hughesa93fb052018-12-12 14:22:48 -0800491}
492
Haibo Huang24c77a12020-04-29 13:49:57 -0700493static DOHcode store_a(const unsigned char *doh, int index, struct dohentry *d)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800494{
495 /* silently ignore addresses over the limit */
496 if(d->numaddr < DOH_MAX_ADDR) {
497 struct dohaddr *a = &d->addr[d->numaddr];
498 a->type = DNS_TYPE_A;
499 memcpy(&a->ip.v4, &doh[index], 4);
500 d->numaddr++;
501 }
502 return DOH_OK;
503}
504
Haibo Huang24c77a12020-04-29 13:49:57 -0700505static DOHcode store_aaaa(const unsigned char *doh,
506 int index,
507 struct dohentry *d)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800508{
509 /* silently ignore addresses over the limit */
510 if(d->numaddr < DOH_MAX_ADDR) {
511 struct dohaddr *a = &d->addr[d->numaddr];
512 a->type = DNS_TYPE_AAAA;
513 memcpy(&a->ip.v6, &doh[index], 16);
514 d->numaddr++;
515 }
516 return DOH_OK;
517}
518
Haibo Huang24c77a12020-04-29 13:49:57 -0700519static DOHcode store_cname(const unsigned char *doh,
Elliott Hughesa93fb052018-12-12 14:22:48 -0800520 size_t dohlen,
521 unsigned int index,
522 struct dohentry *d)
523{
Haibo Huangca2a8022020-07-10 20:17:42 -0700524 struct dynbuf *c;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800525 unsigned int loop = 128; /* a valid DNS name can never loop this much */
526 unsigned char length;
527
528 if(d->numcname == DOH_MAX_CNAME)
529 return DOH_OK; /* skip! */
530
531 c = &d->cname[d->numcname++];
532 do {
533 if(index >= dohlen)
534 return DOH_DNS_OUT_OF_RANGE;
535 length = doh[index];
536 if((length & 0xc0) == 0xc0) {
537 int newpos;
538 /* name pointer, get the new offset (14 bits) */
539 if((index + 1) >= dohlen)
540 return DOH_DNS_OUT_OF_RANGE;
541
Haibo Huangb51266f2020-03-04 02:22:48 -0800542 /* move to the new index */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800543 newpos = (length & 0x3f) << 8 | doh[index + 1];
544 index = newpos;
545 continue;
546 }
547 else if(length & 0xc0)
548 return DOH_DNS_BAD_LABEL; /* bad input */
549 else
550 index++;
551
552 if(length) {
Haibo Huangca2a8022020-07-10 20:17:42 -0700553 if(Curl_dyn_len(c)) {
554 if(Curl_dyn_add(c, "."))
555 return DOH_OUT_OF_MEM;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800556 }
557 if((index + length) > dohlen)
558 return DOH_DNS_BAD_LABEL;
559
Haibo Huangca2a8022020-07-10 20:17:42 -0700560 if(Curl_dyn_addn(c, &doh[index], length))
561 return DOH_OUT_OF_MEM;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800562 index += length;
563 }
564 } while(length && --loop);
565
566 if(!loop)
567 return DOH_DNS_LABEL_LOOP;
568 return DOH_OK;
569}
570
Haibo Huang24c77a12020-04-29 13:49:57 -0700571static DOHcode rdata(const unsigned char *doh,
Elliott Hughesa93fb052018-12-12 14:22:48 -0800572 size_t dohlen,
573 unsigned short rdlength,
574 unsigned short type,
575 int index,
576 struct dohentry *d)
577{
578 /* RDATA
579 - A (TYPE 1): 4 bytes
580 - AAAA (TYPE 28): 16 bytes
581 - NS (TYPE 2): N bytes */
582 DOHcode rc;
583
584 switch(type) {
585 case DNS_TYPE_A:
586 if(rdlength != 4)
587 return DOH_DNS_RDATA_LEN;
588 rc = store_a(doh, index, d);
589 if(rc)
590 return rc;
591 break;
592 case DNS_TYPE_AAAA:
593 if(rdlength != 16)
594 return DOH_DNS_RDATA_LEN;
595 rc = store_aaaa(doh, index, d);
596 if(rc)
597 return rc;
598 break;
599 case DNS_TYPE_CNAME:
600 rc = store_cname(doh, dohlen, index, d);
601 if(rc)
602 return rc;
603 break;
Haibo Huangb51266f2020-03-04 02:22:48 -0800604 case DNS_TYPE_DNAME:
605 /* explicit for clarity; just skip; rely on synthesized CNAME */
606 break;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800607 default:
608 /* unsupported type, just skip it */
609 break;
610 }
611 return DOH_OK;
612}
613
Haibo Huangca2a8022020-07-10 20:17:42 -0700614UNITTEST void de_init(struct dohentry *de)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800615{
Haibo Huangca2a8022020-07-10 20:17:42 -0700616 int i;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800617 memset(de, 0, sizeof(*de));
618 de->ttl = INT_MAX;
Haibo Huangca2a8022020-07-10 20:17:42 -0700619 for(i = 0; i < DOH_MAX_CNAME; i++)
620 Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800621}
622
623
Haibo Huang24c77a12020-04-29 13:49:57 -0700624UNITTEST DOHcode doh_decode(const unsigned char *doh,
Elliott Hughesa93fb052018-12-12 14:22:48 -0800625 size_t dohlen,
626 DNStype dnstype,
627 struct dohentry *d)
628{
629 unsigned char rcode;
630 unsigned short qdcount;
631 unsigned short ancount;
632 unsigned short type = 0;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800633 unsigned short rdlength;
634 unsigned short nscount;
635 unsigned short arcount;
636 unsigned int index = 12;
637 DOHcode rc;
638
639 if(dohlen < 12)
640 return DOH_TOO_SMALL_BUFFER; /* too small */
Haibo Huang21926d52019-01-08 14:27:10 -0800641 if(!doh || doh[0] || doh[1])
Elliott Hughesa93fb052018-12-12 14:22:48 -0800642 return DOH_DNS_BAD_ID; /* bad ID */
643 rcode = doh[3] & 0x0f;
644 if(rcode)
645 return DOH_DNS_BAD_RCODE; /* bad rcode */
646
647 qdcount = get16bit(doh, 4);
648 while(qdcount) {
649 rc = skipqname(doh, dohlen, &index);
650 if(rc)
651 return rc; /* bad qname */
652 if(dohlen < (index + 4))
653 return DOH_DNS_OUT_OF_RANGE;
654 index += 4; /* skip question's type and class */
655 qdcount--;
656 }
657
658 ancount = get16bit(doh, 6);
659 while(ancount) {
Haibo Huang34ab3462019-05-22 00:50:27 -0700660 unsigned short class;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800661 unsigned int ttl;
662
663 rc = skipqname(doh, dohlen, &index);
664 if(rc)
665 return rc; /* bad qname */
666
667 if(dohlen < (index + 2))
668 return DOH_DNS_OUT_OF_RANGE;
669
670 type = get16bit(doh, index);
Haibo Huangb51266f2020-03-04 02:22:48 -0800671 if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */
672 && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */
673 && (type != dnstype))
674 /* Not the same type as was asked for nor CNAME nor DNAME */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800675 return DOH_DNS_UNEXPECTED_TYPE;
676 index += 2;
677
678 if(dohlen < (index + 2))
679 return DOH_DNS_OUT_OF_RANGE;
680 class = get16bit(doh, index);
681 if(DNS_CLASS_IN != class)
682 return DOH_DNS_UNEXPECTED_CLASS; /* unsupported */
683 index += 2;
684
685 if(dohlen < (index + 4))
686 return DOH_DNS_OUT_OF_RANGE;
687
688 ttl = get32bit(doh, index);
689 if(ttl < d->ttl)
690 d->ttl = ttl;
691 index += 4;
692
693 if(dohlen < (index + 2))
694 return DOH_DNS_OUT_OF_RANGE;
695
696 rdlength = get16bit(doh, index);
697 index += 2;
698 if(dohlen < (index + rdlength))
699 return DOH_DNS_OUT_OF_RANGE;
700
701 rc = rdata(doh, dohlen, rdlength, type, index, d);
702 if(rc)
703 return rc; /* bad rdata */
704 index += rdlength;
705 ancount--;
706 }
707
708 nscount = get16bit(doh, 8);
709 while(nscount) {
710 rc = skipqname(doh, dohlen, &index);
711 if(rc)
712 return rc; /* bad qname */
713
714 if(dohlen < (index + 8))
715 return DOH_DNS_OUT_OF_RANGE;
716
717 index += 2 + 2 + 4; /* type, class and ttl */
718
719 if(dohlen < (index + 2))
720 return DOH_DNS_OUT_OF_RANGE;
721
722 rdlength = get16bit(doh, index);
723 index += 2;
724 if(dohlen < (index + rdlength))
725 return DOH_DNS_OUT_OF_RANGE;
726 index += rdlength;
727 nscount--;
728 }
729
730 arcount = get16bit(doh, 10);
731 while(arcount) {
732 rc = skipqname(doh, dohlen, &index);
733 if(rc)
734 return rc; /* bad qname */
735
736 if(dohlen < (index + 8))
737 return DOH_DNS_OUT_OF_RANGE;
738
739 index += 2 + 2 + 4; /* type, class and ttl */
740
741 if(dohlen < (index + 2))
742 return DOH_DNS_OUT_OF_RANGE;
743
744 rdlength = get16bit(doh, index);
745 index += 2;
746 if(dohlen < (index + rdlength))
747 return DOH_DNS_OUT_OF_RANGE;
748 index += rdlength;
749 arcount--;
750 }
751
752 if(index != dohlen)
753 return DOH_DNS_MALFORMAT; /* something is wrong */
754
755 if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr)
756 /* nothing stored! */
757 return DOH_NO_CONTENT;
758
759 return DOH_OK; /* ok */
760}
761
762#ifndef CURL_DISABLE_VERBOSE_STRINGS
763static void showdoh(struct Curl_easy *data,
Haibo Huang24c77a12020-04-29 13:49:57 -0700764 const struct dohentry *d)
Elliott Hughesa93fb052018-12-12 14:22:48 -0800765{
766 int i;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700767 infof(data, "TTL: %u seconds", d->ttl);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800768 for(i = 0; i < d->numaddr; i++) {
Haibo Huang24c77a12020-04-29 13:49:57 -0700769 const struct dohaddr *a = &d->addr[i];
Elliott Hughesa93fb052018-12-12 14:22:48 -0800770 if(a->type == DNS_TYPE_A) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700771 infof(data, "DoH A: %u.%u.%u.%u",
Elliott Hughesa93fb052018-12-12 14:22:48 -0800772 a->ip.v4[0], a->ip.v4[1],
773 a->ip.v4[2], a->ip.v4[3]);
774 }
775 else if(a->type == DNS_TYPE_AAAA) {
776 int j;
777 char buffer[128];
778 char *ptr;
779 size_t len;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700780 msnprintf(buffer, 128, "DoH AAAA: ");
Elliott Hughesa93fb052018-12-12 14:22:48 -0800781 ptr = &buffer[10];
782 len = 118;
783 for(j = 0; j < 16; j += 2) {
784 size_t l;
Haibo Huang21926d52019-01-08 14:27:10 -0800785 msnprintf(ptr, len, "%s%02x%02x", j?":":"", d->addr[i].ip.v6[j],
786 d->addr[i].ip.v6[j + 1]);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800787 l = strlen(ptr);
788 len -= l;
789 ptr += l;
790 }
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700791 infof(data, "%s", buffer);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800792 }
793 }
794 for(i = 0; i < d->numcname; i++) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700795 infof(data, "CNAME: %s", Curl_dyn_ptr(&d->cname[i]));
Elliott Hughesa93fb052018-12-12 14:22:48 -0800796 }
797}
798#else
799#define showdoh(x,y)
800#endif
801
802/*
803 * doh2ai()
804 *
805 * This function returns a pointer to the first element of a newly allocated
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700806 * Curl_addrinfo struct linked list filled with the data from a set of DoH
Elliott Hughesa93fb052018-12-12 14:22:48 -0800807 * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
808 * a IPv6 stack, but usable also for IPv4, all hosts and environments.
809 *
810 * The memory allocated by this function *MUST* be free'd later on calling
811 * Curl_freeaddrinfo(). For each successful call to this function there
812 * must be an associated call later to Curl_freeaddrinfo().
813 */
814
Haibo Huangca2a8022020-07-10 20:17:42 -0700815static struct Curl_addrinfo *
Elliott Hughesa93fb052018-12-12 14:22:48 -0800816doh2ai(const struct dohentry *de, const char *hostname, int port)
817{
Haibo Huangca2a8022020-07-10 20:17:42 -0700818 struct Curl_addrinfo *ai;
819 struct Curl_addrinfo *prevai = NULL;
820 struct Curl_addrinfo *firstai = NULL;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800821 struct sockaddr_in *addr;
822#ifdef ENABLE_IPV6
823 struct sockaddr_in6 *addr6;
824#endif
825 CURLcode result = CURLE_OK;
826 int i;
Haibo Huangca2a8022020-07-10 20:17:42 -0700827 size_t hostlen = strlen(hostname) + 1; /* include zero terminator */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800828
829 if(!de)
830 /* no input == no output! */
831 return NULL;
832
833 for(i = 0; i < de->numaddr; i++) {
834 size_t ss_size;
835 CURL_SA_FAMILY_T addrtype;
836 if(de->addr[i].type == DNS_TYPE_AAAA) {
837#ifndef ENABLE_IPV6
838 /* we can't handle IPv6 addresses */
839 continue;
840#else
841 ss_size = sizeof(struct sockaddr_in6);
842 addrtype = AF_INET6;
843#endif
844 }
845 else {
846 ss_size = sizeof(struct sockaddr_in);
847 addrtype = AF_INET;
848 }
849
Haibo Huangca2a8022020-07-10 20:17:42 -0700850 ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800851 if(!ai) {
852 result = CURLE_OUT_OF_MEMORY;
853 break;
854 }
Haibo Huangca2a8022020-07-10 20:17:42 -0700855 ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
856 ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size);
857 memcpy(ai->ai_canonname, hostname, hostlen);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800858
859 if(!firstai)
860 /* store the pointer we want to return from this function */
861 firstai = ai;
862
863 if(prevai)
864 /* make the previous entry point to this */
865 prevai->ai_next = ai;
866
867 ai->ai_family = addrtype;
868
869 /* we return all names as STREAM, so when using this address for TFTP
870 the type must be ignored and conn->socktype be used instead! */
871 ai->ai_socktype = SOCK_STREAM;
872
873 ai->ai_addrlen = (curl_socklen_t)ss_size;
874
875 /* leave the rest of the struct filled with zero */
876
877 switch(ai->ai_family) {
878 case AF_INET:
879 addr = (void *)ai->ai_addr; /* storage area for this info */
880 DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
881 memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
Haibo Huangc3c04f42020-08-19 13:00:07 -0700882 addr->sin_family = addrtype;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800883 addr->sin_port = htons((unsigned short)port);
884 break;
885
886#ifdef ENABLE_IPV6
887 case AF_INET6:
888 addr6 = (void *)ai->ai_addr; /* storage area for this info */
889 DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
890 memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
Haibo Huangc3c04f42020-08-19 13:00:07 -0700891 addr6->sin6_family = addrtype;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800892 addr6->sin6_port = htons((unsigned short)port);
893 break;
894#endif
895 }
896
897 prevai = ai;
898 }
899
900 if(result) {
901 Curl_freeaddrinfo(firstai);
902 firstai = NULL;
903 }
904
905 return firstai;
906}
907
908#ifndef CURL_DISABLE_VERBOSE_STRINGS
909static const char *type2name(DNStype dnstype)
910{
911 return (dnstype == DNS_TYPE_A)?"A":"AAAA";
912}
913#endif
914
915UNITTEST void de_cleanup(struct dohentry *d)
916{
917 int i = 0;
918 for(i = 0; i < d->numcname; i++) {
Haibo Huangca2a8022020-07-10 20:17:42 -0700919 Curl_dyn_free(&d->cname[i]);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800920 }
921}
922
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700923CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
Elliott Hughesa93fb052018-12-12 14:22:48 -0800924 struct Curl_dns_entry **dnsp)
925{
Haibo Huangb51266f2020-03-04 02:22:48 -0800926 CURLcode result;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700927 struct dohdata *dohp = data->req.doh;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800928 *dnsp = NULL; /* defaults to no response */
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700929 if(!dohp)
930 return CURLE_OUT_OF_MEMORY;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800931
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700932 if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
933 !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
934 failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
935 return data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
Elliott Hughesa93fb052018-12-12 14:22:48 -0800936 CURLE_COULDNT_RESOLVE_HOST;
937 }
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700938 else if(!dohp->pending) {
Haibo Huangca2a8022020-07-10 20:17:42 -0700939 DOHcode rc[DOH_PROBE_SLOTS] = {
940 DOH_OK, DOH_OK
941 };
Elliott Hughesa93fb052018-12-12 14:22:48 -0800942 struct dohentry de;
Haibo Huangb51266f2020-03-04 02:22:48 -0800943 int slot;
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700944 /* remove DoH handles from multi handle and close them */
Haibo Huangb51266f2020-03-04 02:22:48 -0800945 for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700946 curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
947 Curl_close(&dohp->probe[slot].easy);
Haibo Huangb51266f2020-03-04 02:22:48 -0800948 }
Elliott Hughesa93fb052018-12-12 14:22:48 -0800949 /* parse the responses, create the struct and return it! */
Haibo Huangca2a8022020-07-10 20:17:42 -0700950 de_init(&de);
Haibo Huangb51266f2020-03-04 02:22:48 -0800951 for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700952 struct dnsprobe *p = &dohp->probe[slot];
Haibo Huangca2a8022020-07-10 20:17:42 -0700953 if(!p->dnstype)
954 continue;
955 rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
956 Curl_dyn_len(&p->serverdoh),
957 p->dnstype,
Haibo Huangb51266f2020-03-04 02:22:48 -0800958 &de);
Haibo Huangca2a8022020-07-10 20:17:42 -0700959 Curl_dyn_free(&p->serverdoh);
Haibo Huangb51266f2020-03-04 02:22:48 -0800960 if(rc[slot]) {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700961 infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]),
962 type2name(p->dnstype), dohp->host);
Haibo Huangb51266f2020-03-04 02:22:48 -0800963 }
964 } /* next slot */
965
966 result = CURLE_COULDNT_RESOLVE_HOST; /* until we know better */
967 if(!rc[DOH_PROBE_SLOT_IPADDR_V4] || !rc[DOH_PROBE_SLOT_IPADDR_V6]) {
968 /* we have an address, of one kind or other */
Haibo Huang34ab3462019-05-22 00:50:27 -0700969 struct Curl_dns_entry *dns;
970 struct Curl_addrinfo *ai;
971
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700972 infof(data, "DoH Host name: %s", dohp->host);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800973 showdoh(data, &de);
974
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700975 ai = doh2ai(&de, dohp->host, dohp->port);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800976 if(!ai) {
977 de_cleanup(&de);
978 return CURLE_OUT_OF_MEMORY;
979 }
980
981 if(data->share)
982 Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
983
984 /* we got a response, store it in the cache */
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700985 dns = Curl_cache_addr(data, ai, dohp->host, dohp->port);
Elliott Hughesa93fb052018-12-12 14:22:48 -0800986
987 if(data->share)
988 Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
989
Haibo Huangb51266f2020-03-04 02:22:48 -0800990 if(!dns) {
Elliott Hughesa93fb052018-12-12 14:22:48 -0800991 /* returned failure, bail out nicely */
992 Curl_freeaddrinfo(ai);
Haibo Huangb51266f2020-03-04 02:22:48 -0800993 }
Elliott Hughesa93fb052018-12-12 14:22:48 -0800994 else {
Elliott Hughes34dd5f42021-08-10 13:01:18 -0700995 data->state.async.dns = dns;
Elliott Hughesa93fb052018-12-12 14:22:48 -0800996 *dnsp = dns;
Haibo Huangb51266f2020-03-04 02:22:48 -0800997 result = CURLE_OK; /* address resolution OK */
Elliott Hughesa93fb052018-12-12 14:22:48 -0800998 }
Haibo Huangb51266f2020-03-04 02:22:48 -0800999 } /* address processing done */
1000
1001 /* Now process any build-specific attributes retrieved from DNS */
1002
1003 /* All done */
Elliott Hughesa93fb052018-12-12 14:22:48 -08001004 de_cleanup(&de);
Elliott Hughes34dd5f42021-08-10 13:01:18 -07001005 Curl_safefree(data->req.doh);
Haibo Huangb51266f2020-03-04 02:22:48 -08001006 return result;
Elliott Hughesa93fb052018-12-12 14:22:48 -08001007
Elliott Hughes34dd5f42021-08-10 13:01:18 -07001008 } /* !dohp->pending */
Elliott Hughesa93fb052018-12-12 14:22:48 -08001009
Elliott Hughes34dd5f42021-08-10 13:01:18 -07001010 /* else wait for pending DoH transactions to complete */
Elliott Hughesa93fb052018-12-12 14:22:48 -08001011 return CURLE_OK;
1012}
Haibo Huang34ab3462019-05-22 00:50:27 -07001013
1014#endif /* CURL_DISABLE_DOH */