• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2020 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "private-lib-core.h"
26 #include "private-lib-async-dns.h"
27 
28 static const uint32_t botable[] = { 500, 1000, 1250, 5000
29 				/* in case everything just dog slow */ };
30 static const lws_retry_bo_t retry_policy = {
31 	botable, LWS_ARRAY_SIZE(botable), LWS_ARRAY_SIZE(botable),
32 	/* don't conceal after the last table entry */ 0, 0, 20 };
33 
34 void
lws_adns_q_destroy(lws_adns_q_t * q)35 lws_adns_q_destroy(lws_adns_q_t *q)
36 {
37 	lws_dll2_remove(&q->sul.list);
38 	lws_dll2_remove(&q->list);
39 	lws_free(q);
40 }
41 
42 lws_adns_q_t *
lws_adns_get_query(lws_async_dns_t * dns,adns_query_type_t qtype,lws_dll2_owner_t * owner,uint16_t tid,const char * name)43 lws_adns_get_query(lws_async_dns_t *dns, adns_query_type_t qtype,
44 		   lws_dll2_owner_t *owner, uint16_t tid, const char *name)
45 {
46 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
47 				   lws_dll2_get_head(owner)) {
48 		lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
49 
50 		if (!name && (tid & 0xfffe) == (q->tid & 0xfffe))
51 			return q;
52 
53 		if (name && q->qtype == ((tid & 1) ? LWS_ADNS_RECORD_AAAA :
54 						     LWS_ADNS_RECORD_A) &&
55 		    !strcasecmp(name, (const char *)&q[1])) {
56 			if (owner == &dns->cached) {
57 				/* Keep sorted by LRU: move to the head */
58 				lws_dll2_remove(&q->list);
59 				lws_dll2_add_head(&q->list, &dns->cached);
60 			}
61 
62 			return q;
63 		}
64 	} lws_end_foreach_dll_safe(d, d1);
65 
66 	return NULL;
67 }
68 
69 void
lws_async_dns_drop_server(struct lws_context * context)70 lws_async_dns_drop_server(struct lws_context *context)
71 {
72 	context->async_dns.dns_server_set = 0;
73 	lws_set_timeout(context->async_dns.wsi, 1, LWS_TO_KILL_ASYNC);
74 	context->async_dns.wsi = NULL;
75 }
76 
77 int
lws_async_dns_complete(lws_adns_q_t * q,lws_adns_cache_t * c)78 lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c)
79 {
80 
81 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
82 				   lws_dll2_get_head(&q->wsi_adns)) {
83 		struct lws *w = lws_container_of(d, struct lws, adns);
84 
85 		lws_dll2_remove(d);
86 		if (c && c->results) {
87 			lwsl_debug("%s: q: %p, c: %p, refcount %d -> %d\n",
88 				    __func__, q, c, c->refcount, c->refcount + 1);
89 			c->refcount++;
90 		}
91 		w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0,
92 				q->opaque);
93 	} lws_end_foreach_dll_safe(d, d1);
94 
95 	if (q->standalone_cb) {
96 		if (c && c->results) {
97 			lwsl_debug("%s: q: %p, c: %p, refcount %d -> %d\n",
98 				    __func__, q, c, c->refcount, c->refcount + 1);
99 			c->refcount++;
100 		}
101 
102 		q->standalone_cb(NULL, (const char *)&q[1],
103 				 c ? c->results : NULL, 0, q->opaque);
104 	}
105 
106 	return 0;
107 }
108 
109 static void
lws_async_dns_sul_cb_retry(struct lws_sorted_usec_list * sul)110 lws_async_dns_sul_cb_retry(struct lws_sorted_usec_list *sul)
111 {
112 	lws_adns_q_t *q = lws_container_of(sul, lws_adns_q_t, sul);
113 
114 	// lwsl_notice("%s\n", __func__);
115 
116 	lws_callback_on_writable(q->dns->wsi);
117 }
118 
119 static void
lws_async_dns_writeable(struct lws * wsi,lws_adns_q_t * q)120 lws_async_dns_writeable(struct lws *wsi, lws_adns_q_t *q)
121 {
122 	uint8_t pkt[LWS_PRE + DNS_PACKET_LEN], *e = &pkt[sizeof(pkt)], *p, *pl;
123 	int m, n, which;
124 	const char *name;
125 
126 	// lwsl_notice("%s: %p\n", __func__, q);
127 
128 	/*
129 	 * UDP is not reliable, it can be locally dropped, or dropped
130 	 * by any intermediary or the remote peer.  So even though we
131 	 * will do the write in a moment, we schedule another request
132 	 * for rewrite according to the wsi retry policy.
133 	 *
134 	 * If the result came before, we'll cancel it as part of the
135 	 * wsi close.
136 	 *
137 	 * If we have already reached the end of our concealed retries
138 	 * in the policy, just close without another write.
139 	 */
140 	if (lws_dll2_is_detached(&q->sul.list) &&
141 	    lws_retry_sul_schedule_retry_wsi(wsi, &q->sul,
142 				       lws_async_dns_sul_cb_retry, &q->retry)) {
143 		/* we have reached the end of our concealed retries */
144 		lwsl_notice("%s: failing query\n", __func__);
145 		/*
146 		 * our policy is to force reloading the dns server info
147 		 * if our connection ever timed out, in case it or the
148 		 * routing state changed
149 		 */
150 
151 		lws_async_dns_drop_server(q->context);
152 		goto qfail;
153 	}
154 
155 	name = (const char *)&q[1];
156 
157 	p = &pkt[LWS_PRE];
158 	memset(p, 0, DHO_SIZEOF);
159 
160 #if defined(LWS_WITH_IPV6)
161 	if (!q->responded) {
162 		/* must pick between ipv6 and ipv4 */
163 		which = q->sent[0] >= q->sent[1];
164 		q->sent[which]++;
165 		q->asked = 3; /* want results for 4 & 6 before done */
166 	} else
167 		which = q->responded & 1;
168 #else
169 	which = 0;
170 	q->asked = 1;
171 #endif
172 
173 	/* we hack b0 of the tid to be 0 = A, 1 = AAAA */
174 
175 	lws_ser_wu16be(&p[DHO_TID],
176 #if defined(LWS_WITH_IPV6)
177 			which ? q->tid | 1 :
178 #endif
179 			q->tid);
180 	lws_ser_wu16be(&p[DHO_FLAGS], (1 << 8));
181 	lws_ser_wu16be(&p[DHO_NQUERIES], 1);
182 
183 	p += DHO_SIZEOF;
184 
185 	/* start of label-formatted qname */
186 
187 	pl = p++;
188 
189 	do {
190 		if (*name == '.' || !*name) {
191 			*pl = lws_ptr_diff(p, pl + 1);
192 			pl = p;
193 			*p++ = 0; /* also serves as terminal length */
194 			if (!*name++)
195 				break;
196 		} else
197 			*p++ = *name++;
198 	} while (p + 6 < e);
199 
200 	if (p + 6 >= e) {
201 		assert(0);
202 		lwsl_err("%s: name too big\n", __func__);
203 		goto qfail;
204 	}
205 
206 	lws_ser_wu16be(p, which ? LWS_ADNS_RECORD_AAAA :
207 				     LWS_ADNS_RECORD_A);
208 	p += 2;
209 
210 	lws_ser_wu16be(p, 1); /* IN class */
211 	p += 2;
212 
213 	assert(p < pkt + sizeof(pkt) - LWS_PRE);
214 	n = lws_ptr_diff(p, pkt + LWS_PRE);
215 	m = lws_write(wsi, pkt + LWS_PRE, n, 0);
216 	if (m != n) {
217 		lwsl_notice("%s: dns write failed %d %d\n", __func__,
218 			    m, n);
219 		goto qfail;
220 	}
221 
222 #if defined(LWS_WITH_IPV6)
223 	if (!q->responded && q->sent[0] != q->sent[1])
224 		lws_callback_on_writable(wsi);
225 #endif
226 
227 	/* if we did anything, check one more time */
228 	lws_callback_on_writable(wsi);
229 
230 	return;
231 
232 qfail:
233 	lwsl_warn("%s: failing query doing NULL completion\n", __func__);
234 	/*
235 	 * in ipv6 case, we made a cache entry for the first response but
236 	 * evidently the second response didn't come in time, purge the
237 	 * incomplete cache entry
238 	 */
239 	if (q->firstcache)
240 		lws_adns_cache_destroy(q->firstcache);
241 	lws_async_dns_complete(q, NULL);
242 	lws_adns_q_destroy(q);
243 }
244 
245 static int
callback_async_dns(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)246 callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason,
247 		   void *user, void *in, size_t len)
248 {
249 	struct lws_async_dns *dns = &(lws_get_context(wsi)->async_dns);
250 
251 	switch (reason) {
252 
253 	/* callbacks related to raw socket descriptor */
254 
255         case LWS_CALLBACK_RAW_ADOPT:
256 		// lwsl_user("LWS_CALLBACK_RAW_ADOPT\n");
257                 break;
258 
259 	case LWS_CALLBACK_RAW_CLOSE:
260 		// lwsl_user("LWS_CALLBACK_RAW_CLOSE\n");
261 		break;
262 
263 	case LWS_CALLBACK_RAW_RX:
264 		// lwsl_user("LWS_CALLBACK_RAW_RX (%d)\n", (int)len);
265 		// lwsl_hexdump_level(LLL_NOTICE, in, len);
266 		lws_adns_parse_udp(dns, in, len);
267 		break;
268 
269 	case LWS_CALLBACK_RAW_WRITEABLE:
270 		// lwsl_notice("%s: WRITABLE\n", __func__);
271 
272 		lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
273 					   dns->waiting.head) {
274 			lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t,
275 							   list);
276 
277 			if (lws_dll2_is_detached(&q->sul.list) &&
278 			    (!q->asked || q->responded != q->asked))
279 				lws_async_dns_writeable(wsi, q);
280 		} lws_end_foreach_dll_safe(d, d1);
281 		break;
282 
283 	default:
284 		break;
285 	}
286 
287 	return 0;
288 }
289 
290 struct lws_protocols lws_async_dns_protocol = {
291 	"lws-async-dns", callback_async_dns, 0, 0
292 };
293 
294 int
lws_async_dns_init(struct lws_context * context)295 lws_async_dns_init(struct lws_context *context)
296 {
297 	lws_async_dns_t *dns = &context->async_dns;
298 	char ads[48];
299 	int n;
300 
301 	memset(&dns->sa46, 0, sizeof(dns->sa46));
302 
303 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
304 	if (lws_dhcpc_status(context, &dns->sa46))
305 		goto ok;
306 #endif
307 
308 	n = lws_plat_asyncdns_init(context, &dns->sa46);
309 	if (n < 0) {
310 		lwsl_warn("%s: no valid dns server, retry\n", __func__);
311 
312 		return 1;
313 	}
314 
315 	if (n != LADNS_CONF_SERVER_CHANGED)
316 		return 0;
317 
318 #if defined(LWS_WITH_SYS_DHCP_CLIENT)
319 ok:
320 #endif
321 	dns->sa46.sa4.sin_port = htons(53);
322 	lws_write_numeric_address((uint8_t *)&dns->sa46.sa4.sin_addr.s_addr, 4,
323 				  ads, sizeof(ads));
324 
325 	context->async_dns.wsi = lws_create_adopt_udp(context->vhost_list, ads,
326 				      53, 0, lws_async_dns_protocol.name, NULL,
327 				      NULL, NULL, &retry_policy);
328 	if (!dns->wsi) {
329 		lwsl_err("%s: foreign socket adoption failed\n", __func__);
330 		return 1;
331 	}
332 
333 	dns->dns_server_set = 1;
334 
335 	return 0;
336 }
337 
338 lws_adns_cache_t *
lws_adns_get_cache(lws_async_dns_t * dns,const char * name)339 lws_adns_get_cache(lws_async_dns_t *dns, const char *name)
340 {
341 	lws_adns_cache_t *c;
342 	const char *cn;
343 
344 	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
345 				   lws_dll2_get_head(&dns->cached)) {
346 		c = lws_container_of(d, lws_adns_cache_t, list);
347 		cn = (const char *)&c[1];
348 
349 		if (name && !c->incomplete && !strcasecmp(name, cn)) {
350 			/* Keep sorted by LRU: move to the head */
351 			lws_dll2_remove(&c->list);
352 			lws_dll2_add_head(&c->list, &dns->cached);
353 
354 			return c;
355 		}
356 	} lws_end_foreach_dll_safe(d, d1);
357 
358 	return NULL;
359 }
360 
361 void
lws_adns_cache_destroy(lws_adns_cache_t * c)362 lws_adns_cache_destroy(lws_adns_cache_t *c)
363 {
364 	lws_dll2_remove(&c->sul.list);
365 	lws_dll2_remove(&c->list);
366 	if (c->chain)
367 		lws_free(c->chain);
368 	lws_free(c);
369 }
370 
371 static int
cache_clean(struct lws_dll2 * d,void * user)372 cache_clean(struct lws_dll2 *d, void *user)
373 {
374 	lws_adns_cache_destroy(lws_container_of(d, lws_adns_cache_t, list));
375 
376 	return 0;
377 }
378 
379 void
sul_cb_expire(struct lws_sorted_usec_list * sul)380 sul_cb_expire(struct lws_sorted_usec_list *sul)
381 {
382 	lws_adns_cache_t *c = lws_container_of(sul, lws_adns_cache_t, sul);
383 
384 	lws_adns_cache_destroy(c);
385 }
386 
387 void
lws_async_dns_freeaddrinfo(const struct addrinfo ** pai)388 lws_async_dns_freeaddrinfo(const struct addrinfo **pai)
389 {
390 	lws_adns_cache_t *c;
391 
392 	if (!*pai)
393 		return;
394 
395 	/*
396 	 * First query may have been empty... if second has something, we
397 	 * fixed up the first result to point to second... but it means
398 	 * looking backwards from ai, which is c->result, which is the second
399 	 * packet's results, doesn't get us to the firstcache pointer.
400 	 *
401 	 * Adjust c to the firstcache in this case.
402 	 */
403 
404 	c = &((lws_adns_cache_t *)(*pai))[-1];
405 	if (c->firstcache)
406 		c = c->firstcache;
407 
408 	lwsl_debug("%s: c %p, %s, refcount %d -> %d\n", __func__, c,
409 		   (c->results && c->results->ai_canonname) ?
410 				c->results->ai_canonname : "none",
411 						c->refcount, c->refcount - 1);
412 
413 	assert(c->refcount > 0);
414 	c->refcount--;
415 	*pai = NULL;
416 }
417 
418 void
lws_async_dns_trim_cache(lws_async_dns_t * dns)419 lws_async_dns_trim_cache(lws_async_dns_t *dns)
420 {
421 	lws_adns_cache_t *c1;
422 
423 	if (dns->cached.count + 1< MAX_CACHE_ENTRIES)
424 		return;
425 
426 	c1 = lws_container_of(lws_dll2_get_tail(&dns->cached),
427 						lws_adns_cache_t, list);
428 	if (c1->refcount)
429 		lwsl_notice("%s: wsi %p: refcount %d on purge\n",
430 				__func__, c1, c1->refcount);
431 	else
432 		lws_adns_cache_destroy(c1);
433 }
434 
435 
436 static int
clean(struct lws_dll2 * d,void * user)437 clean(struct lws_dll2 *d, void *user)
438 {
439 	lws_adns_q_destroy(lws_container_of(d, lws_adns_q_t, list));
440 
441 	return 0;
442 }
443 
444 void
lws_async_dns_deinit(lws_async_dns_t * dns)445 lws_async_dns_deinit(lws_async_dns_t *dns)
446 {
447 	lws_dll2_foreach_safe(&dns->waiting, NULL, clean);
448 	lws_dll2_foreach_safe(&dns->cached, NULL, cache_clean);
449 }
450 
451 
452 static int
cancel(struct lws_dll2 * d,void * user)453 cancel(struct lws_dll2 *d, void *user)
454 {
455 	lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
456 
457 	lws_start_foreach_dll_safe(struct lws_dll2 *, d3, d4,
458 				   lws_dll2_get_head(&q->wsi_adns)) {
459 		struct lws *w = lws_container_of(d3, struct lws, adns);
460 
461 		if (user == w) {
462 			lws_dll2_remove(d3);
463 			if (!q->wsi_adns.count)
464 				lws_adns_q_destroy(q);
465 			return 1;
466 		}
467 	} lws_end_foreach_dll_safe(d3, d4);
468 
469 	return 0;
470 }
471 
472 void
lws_async_dns_cancel(struct lws * wsi)473 lws_async_dns_cancel(struct lws *wsi)
474 {
475 	lws_async_dns_t *dns = &wsi->context->async_dns;
476 
477 	lws_dll2_foreach_safe(&dns->waiting, wsi, cancel);
478 }
479 
480 
481 static int
check_tid(struct lws_dll2 * d,void * user)482 check_tid(struct lws_dll2 *d, void *user)
483 {
484 	lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
485 
486 	return q->tid == (uint16_t)(long)user;
487 }
488 
489 int
lws_async_dns_get_new_tid(struct lws_context * context,lws_adns_q_t * q)490 lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q)
491 {
492 	lws_async_dns_t *dns = &context->async_dns;
493 	int budget = 10;
494 
495 	/*
496 	 * Make the TID unpredictable, but must be unique amongst ongoing ones
497 	 */
498 	do {
499 		uint16_t tid;
500 
501 		if (lws_get_random(context, &tid, 2) != 2)
502 			return -1;
503 
504 		if (lws_dll2_foreach_safe(&dns->waiting,
505 					  (void *)(long)tid, check_tid))
506 			continue;
507 
508 		q->tid = tid;
509 
510 		return 0;
511 
512 	} while (budget--);
513 
514 	lwsl_err("%s: unable to get unique tid\n", __func__);
515 
516 	return -1;
517 }
518 
519 struct temp_q {
520 	lws_adns_q_t tq;
521 	char name[48];
522 };
523 
524 lws_async_dns_retcode_t
lws_async_dns_query(struct lws_context * context,int tsi,const char * name,adns_query_type_t qtype,lws_async_dns_cb_t cb,struct lws * wsi,void * opaque)525 lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
526 		    adns_query_type_t qtype, lws_async_dns_cb_t cb,
527 		    struct lws *wsi, void *opaque)
528 {
529 	lws_async_dns_t *dns = &context->async_dns;
530 	size_t nlen = strlen(name);
531 	lws_sockaddr46 *sa46;
532 	lws_adns_cache_t *c;
533 	struct addrinfo *ai;
534 	struct temp_q tmq;
535 	lws_adns_q_t *q;
536 	uint8_t ads[16];
537 	char *p;
538 	int m;
539 
540 #if !defined(LWS_WITH_IPV6)
541 	if (qtype == LWS_ADNS_RECORD_AAAA) {
542 		lwsl_err("%s: ipv6 not enabled\n", __func__);
543 		goto failed;
544 	}
545 #endif
546 
547 	if (nlen >= DNS_MAX - 1)
548 		goto failed;
549 
550 	/*
551 	 * we magically know 'localhost' and 'localhost6' if IPv6, this is a
552 	 * sort of canned /etc/hosts
553 	 */
554 
555 	if (!strcmp(name, "localhost"))
556 		name = "127.0.0.1";
557 
558 #if defined(LWS_WITH_IPV6)
559 	if (!strcmp(name, "localhost6"))
560 		name = "::1";
561 #endif
562 
563 	if (wsi) {
564 		if (!lws_dll2_is_detached(&wsi->adns)) {
565 			lwsl_err("%s: wsi %p already bound to query %p\n",
566 					__func__, wsi, wsi->adns.owner);
567 			goto failed;
568 		}
569 		wsi->adns_cb = cb;
570 	}
571 
572 	/* there's a done, cached query we can just reuse? */
573 
574 	c = lws_adns_get_cache(dns, name);
575 	if (c) {
576 		lwsl_err("%s: using cached, c->results %p\n", __func__, c->results);
577 		m = c->results ? LADNS_RET_FOUND : LADNS_RET_FAILED;
578 		if (c->results)
579 			c->refcount++;
580 		cb(wsi, name, c->results, m, opaque);
581 
582 		return m;
583 	}
584 
585 	/*
586 	 * It's a 1.2.3.4 type IP address already?  We don't need a dns
587 	 * server set up to be able to create an addrinfo result for that.
588 	 *
589 	 * Create it as a cached object so it follows the refcount lifecycle
590 	 * of any other result
591 	 */
592 
593 	m = lws_parse_numeric_address(name, ads, sizeof(ads));
594 	if (m == 4
595 #if defined(LWS_WITH_IPV6)
596 		|| m == 16
597 #endif
598 	) {
599 		lws_async_dns_trim_cache(dns);
600 
601 		c = lws_zalloc(sizeof(lws_adns_cache_t) +
602 			       sizeof(struct addrinfo) +
603 			       sizeof(lws_sockaddr46) + nlen + 1, "adns-numip");
604 		if (!c)
605 			goto failed;
606 
607 		ai = (struct addrinfo *)&c[1];
608 		sa46 = (lws_sockaddr46 *)&ai[1];
609 
610 		ai->ai_socktype = SOCK_STREAM;
611 		memcpy(&sa46[1], name, nlen + 1);
612 		ai->ai_canonname = (char *)&sa46[1];
613 
614 		c->results = ai;
615 		memset(&tmq.tq, 0, sizeof(tmq.tq));
616 		tmq.tq.opaque = opaque;
617 		if (wsi) {
618 			wsi->adns_cb = cb;
619 			lws_dll2_add_head(&wsi->adns, &tmq.tq.wsi_adns);
620 		} else
621 			tmq.tq.standalone_cb = cb;
622 		lws_strncpy(tmq.name, name, sizeof(tmq.name));
623 
624 		lws_dll2_add_head(&c->list, &dns->cached);
625 		lws_sul_schedule(context, 0, &c->sul, sul_cb_expire,
626 				 lws_now_usecs() + (3600ll * LWS_US_PER_SEC));
627 	}
628 
629 	if (m == 4) {
630 		ai->ai_family = sa46->sa4.sin_family = AF_INET;
631 		ai->ai_addrlen = sizeof(sa46->sa4);
632 		ai->ai_addr = (struct sockaddr *)&sa46->sa4;
633 		memcpy(&sa46->sa4.sin_addr, ads, m);
634 
635 		lws_async_dns_complete(&tmq.tq, c);
636 
637 		return LADNS_RET_FOUND;
638 	}
639 
640 #if defined(LWS_WITH_IPV6)
641 	if (m == 16) {
642 		ai->ai_family = sa46->sa6.sin6_family = AF_INET6;
643 		ai->ai_addrlen = sizeof(sa46->sa6);
644 		ai->ai_addr = (struct sockaddr *)&sa46->sa6;
645 		memcpy(&sa46->sa6.sin6_addr, ads, m);
646 
647 		lws_async_dns_complete(&tmq.tq, c);
648 
649 		return LADNS_RET_FOUND;
650 	}
651 #endif
652 
653 	/*
654 	 * to try anything else we need a remote server configured...
655 	 */
656 
657 	if (!context->async_dns.dns_server_set &&
658 	    lws_async_dns_init(context)) {
659 		lwsl_notice("%s: init failed\n", __func__);
660 		goto failed;
661 	}
662 
663 	/* there's an ongoing query we can share the result of */
664 
665 	q = lws_adns_get_query(dns, qtype, &dns->waiting, 0, name);
666 	if (q) {
667 		lwsl_debug("%s: dns piggybacking: %d:%s\n", __func__,
668 				qtype, name);
669 		if (wsi)
670 			lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
671 
672 		return LADNS_RET_CONTINUING;
673 	}
674 
675 	/*
676 	 * Allocate new query / queries... this is a bit complicated because
677 	 * multiple queries in one packet are not supported peoperly in DNS
678 	 * itself, and there's no reliable other way to get both ipv6 and ipv4
679 	 * (AAAA and A) responses in one hit.
680 	 *
681 	 * If we don't support ipv6, it's simple, we just ask for A and that's
682 	 * it.  But if we do support ipv6, we need to ask twice, once for A
683 	 * and in a separate query, again for AAAA.
684 	 *
685 	 * For ipv6, A / ipv4 is routable over ipv6.  So we always ask for A
686 	 * first and then if ipv6, AAAA separately.
687 	 *
688 	 * Allocate for DNS_MAX, because we may recurse and alter what we're
689 	 * looking for.
690 	 *
691 	 * 0             sizeof(*q)                  sizeof(*q) + DNS_MAX
692 	 * [lws_adns_q_t][ name (DNS_MAX reserved) ] [ name \0 ]
693 	 */
694 
695 	q = (lws_adns_q_t *)lws_malloc(sizeof(*q) + DNS_MAX + nlen + 1,
696 					__func__);
697 	if (!q)
698 		goto failed;
699 	memset(q, 0, sizeof(*q));
700 
701 	if (wsi)
702 		lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
703 
704 	q->qtype = (uint16_t)qtype;
705 
706 	if (lws_async_dns_get_new_tid(context, q))
707 		goto failed;
708 
709 	q->tid &= 0xfffe;
710 	q->context = context;
711 	q->tsi = tsi;
712 	q->opaque = opaque;
713 	q->dns = dns;
714 
715 	if (!wsi)
716 		q->standalone_cb = cb;
717 
718 	/* schedule a retry according to the retry policy on the wsi */
719 	if (lws_retry_sul_schedule_retry_wsi(dns->wsi, &q->sul,
720 					 lws_async_dns_sul_cb_retry, &q->retry))
721 		goto failed;
722 
723 	/*
724 	 * We may rewrite the copy at +sizeof(*q) for CNAME recursion.  Keep
725 	 * a second copy at + sizeof(*q) + DNS_MAX so we can create the cache
726 	 * entry for the original name, not the last CNAME we met.
727 	 */
728 
729 	p = (char *)&q[1];
730 	while (nlen--) {
731 		*p++ = tolower(*name++);
732 		p[DNS_MAX - 1] = p[-1];
733 	}
734 	*p = '\0';
735 	p[DNS_MAX] = '\0';
736 
737 	lws_callback_on_writable(dns->wsi);
738 
739 	lws_dll2_add_head(&q->list, &dns->waiting);
740 
741 	lwsl_debug("%s: created new query\n", __func__);
742 
743 	return LADNS_RET_CONTINUING;
744 
745 failed:
746 	cb(wsi, NULL, NULL, LADNS_RET_FAILED, opaque);
747 
748 	return LADNS_RET_FAILED;
749 }
750