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
28static const uint32_t botable[] = { 300, 500, 700, 1250, 5000
29				/* in case everything just dog slow */ };
30static const lws_retry_bo_t retry_policy = {
31	botable, LWS_ARRAY_SIZE(botable), LWS_RETRY_CONCEAL_ALWAYS,
32	/* don't conceal after the last table entry */ 0, 0, 20 };
33
34void
35lws_adns_q_destroy(lws_adns_q_t *q)
36{
37	lws_metrics_caliper_report(q->metcal, (char)q->go_nogo);
38
39	lws_sul_cancel(&q->sul);
40	lws_sul_cancel(&q->write_sul);
41	lws_dll2_remove(&q->list);
42	lws_free(q);
43}
44
45lws_adns_q_t *
46lws_adns_get_query(lws_async_dns_t *dns, adns_query_type_t qtype,
47		   lws_dll2_owner_t *owner, uint16_t tid, const char *name)
48{
49	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
50				   lws_dll2_get_head(owner)) {
51		lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
52		int n = 0, nmax = q->tids >= LWS_ARRAY_SIZE(q->tid) ?
53				  LWS_ARRAY_SIZE(q->tid) : q->tids;
54
55		if (!name)
56			for (n = 0; n < nmax; n++)
57				if ((tid & 0xfffe) == (q->tid[n] & 0xfffe))
58					return q;
59
60		if (name && q->qtype == ((tid & 1) ? LWS_ADNS_RECORD_AAAA :
61						     LWS_ADNS_RECORD_A) &&
62		    !strcasecmp(name, (const char *)&q[1])) {
63			if (owner == &dns->cached) {
64				/* Keep sorted by LRU: move to the head */
65				lws_dll2_remove(&q->list);
66				lws_dll2_add_head(&q->list, &dns->cached);
67			}
68
69			return q;
70		}
71	} lws_end_foreach_dll_safe(d, d1);
72
73	return NULL;
74}
75
76void
77lws_async_dns_drop_server(struct lws_context *context)
78{
79	context->async_dns.dns_server_set = 0;
80	lws_set_timeout(context->async_dns.wsi, 1, LWS_TO_KILL_ASYNC);
81	context->async_dns.wsi = NULL;
82	context->async_dns.dns_server_connected = 0;
83}
84
85int
86lws_async_dns_complete(lws_adns_q_t *q, lws_adns_cache_t *c)
87{
88
89	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
90				   lws_dll2_get_head(&q->wsi_adns)) {
91		struct lws *w = lws_container_of(d, struct lws, adns);
92
93		lws_dll2_remove(d);
94		if (c && c->results) {
95			lwsl_wsi_debug(w, "q: %p, c: %p, refcount %d -> %d",
96				    q, c, c->refcount, c->refcount + 1);
97			c->refcount++;
98		}
99		lws_set_timeout(w, NO_PENDING_TIMEOUT, 0);
100		/*
101		 * This may decide to close / delete w
102		 */
103		if (w->adns_cb(w, (const char *)&q[1], c ? c->results : NULL, 0,
104				q->opaque) == NULL)
105			lwsl_info("%s: failed\n", __func__);
106	//		lws_close_free_wsi(w, LWS_CLOSE_STATUS_NOSTATUS,
107	//				   "adopt udp2 fail");
108
109
110	} lws_end_foreach_dll_safe(d, d1);
111
112	if (q->standalone_cb) {
113		if (c && c->results) {
114			lwsl_wsi_debug(q->dns ? q->dns->wsi : NULL, "q: %p, c: %p, refcount %d -> %d",
115				    q, c, c->refcount, c->refcount + 1);
116			c->refcount++;
117		}
118
119		q->standalone_cb(NULL, (const char *)&q[1],
120				 c ? c->results : NULL, 0, q->opaque);
121	}
122
123	lws_adns_dump(q->dns);
124
125	return 0;
126}
127
128static void
129lws_async_dns_sul_cb_retry(struct lws_sorted_usec_list *sul)
130{
131	lws_adns_q_t *q = lws_container_of(sul, lws_adns_q_t, sul);
132
133	lwsl_wsi_info(q->dns ? q->dns->wsi : NULL, "in");
134	lws_adns_dump(q->dns);
135
136	if (q->dns && q->dns->wsi) {
137		q->is_retry = 1;
138		lws_callback_on_writable(q->dns->wsi);
139	}
140}
141
142static void
143lws_async_dns_writeable(struct lws *wsi, lws_adns_q_t *q)
144{
145	uint8_t pkt[LWS_PRE + DNS_PACKET_LEN], *e = &pkt[sizeof(pkt)], *p, *pl;
146	int m, n, which;
147	const char *name;
148
149	/*
150	 * We managed to get to the point of being WRITEABLE, which is not a
151	 * given if no routes.  So call off the write_sul timeout for that.
152	 */
153	lws_sul_cancel(&q->write_sul);
154
155	if (!q->is_retry && q->sent[0]
156#if defined(LWS_WITH_IPV6)
157	         && q->sent[0] == q->sent[1]
158#endif
159	)
160		return;
161
162	q->is_retry = 0;
163
164	/*
165	 * UDP is not reliable, it can be locally dropped, or dropped
166	 * by any intermediary or the remote peer.  So even though we
167	 * will do the write in a moment, we schedule another request
168	 * for rewrite according to the wsi retry policy.
169	 *
170	 * If the result came before, we'll cancel it as part of the
171	 * wsi close.
172	 *
173	 * If we have already reached the end of our concealed retries
174	 * in the policy, just close without another write.
175	 */
176	if (lws_dll2_is_detached(&q->sul.list) &&
177	    lws_retry_sul_schedule_retry_wsi(wsi, &q->sul,
178				       lws_async_dns_sul_cb_retry, &q->retry)) {
179		/* we have reached the end of our concealed retries */
180		lwsl_wsi_info(wsi, "failing query");
181		/*
182		 * our policy is to force reloading the dns server info
183		 * if our connection ever timed out, in case it or the
184		 * routing state changed
185		 */
186
187		lws_async_dns_drop_server(q->context);
188		goto qfail;
189	}
190
191	name = (const char *)&q[1];
192
193	p = &pkt[LWS_PRE];
194	memset(p, 0, DHO_SIZEOF);
195
196#if defined(LWS_WITH_IPV6)
197	if (!q->responded) {
198		/* must pick between ipv6 and ipv4 */
199		which = q->sent[0] >= q->sent[1];
200		q->sent[which]++;
201		q->asked = 3; /* want results for 4 & 6 before done */
202	} else
203		which = q->responded & 1;
204#else
205	which = 0;
206	q->asked = 1;
207#endif
208
209	lwsl_wsi_info(wsi, "%s, which %d", name, which);
210
211	/* we hack b0 of the tid to be 0 = A, 1 = AAAA */
212
213	lws_ser_wu16be(&p[DHO_TID],
214#if defined(LWS_WITH_IPV6)
215			which ? (LADNS_MOST_RECENT_TID(q) | 1) :
216#endif
217					LADNS_MOST_RECENT_TID(q));
218	lws_ser_wu16be(&p[DHO_FLAGS], (1 << 8));
219	lws_ser_wu16be(&p[DHO_NQUERIES], 1);
220
221	p += DHO_SIZEOF;
222
223	/* start of label-formatted qname */
224
225	pl = p++;
226
227	do {
228		if (*name == '.' || !*name) {
229			*pl = (uint8_t)(unsigned int)lws_ptr_diff(p, pl + 1);
230			pl = p;
231			*p++ = 0; /* also serves as terminal length */
232			if (!*name++)
233				break;
234		} else
235			*p++ = (uint8_t)*name++;
236	} while (p + 6 < e);
237
238	if (p + 6 >= e) {
239		assert(0);
240		lwsl_wsi_err(wsi, "name too big");
241		goto qfail;
242	}
243
244	lws_ser_wu16be(p, which ? LWS_ADNS_RECORD_AAAA : LWS_ADNS_RECORD_A);
245	p += 2;
246
247	lws_ser_wu16be(p, 1); /* IN class */
248	p += 2;
249
250	assert(p < pkt + sizeof(pkt) - LWS_PRE);
251	n = lws_ptr_diff(p, pkt + LWS_PRE);
252
253	m = lws_write(wsi, pkt + LWS_PRE, (unsigned int)n, 0);
254	if (m != n) {
255		lwsl_wsi_notice(wsi, "dns write failed %d %d errno %d",
256			    m, n, errno);
257		goto qfail;
258	}
259
260#if defined(LWS_WITH_IPV6)
261	if (!q->responded && q->sent[0] != q->sent[1]) {
262		lwsl_wsi_debug(wsi, "request writeable for ipv6");
263		lws_callback_on_writable(wsi);
264	}
265#endif
266
267	return;
268
269qfail:
270	lwsl_wsi_warn(wsi, "failing query doing NULL completion");
271	/*
272	 * in ipv6 case, we made a cache entry for the first response but
273	 * evidently the second response didn't come in time, purge the
274	 * incomplete cache entry
275	 */
276	if (q->firstcache) {
277		lwsl_wsi_debug(wsi, "destroy firstcache");
278		lws_adns_cache_destroy(q->firstcache);
279		q->firstcache = NULL;
280	}
281	lws_async_dns_complete(q, NULL);
282	lws_adns_q_destroy(q);
283}
284
285static int
286callback_async_dns(struct lws *wsi, enum lws_callback_reasons reason,
287		   void *user, void *in, size_t len)
288{
289	struct lws_async_dns *dns = &(lws_get_context(wsi)->async_dns);
290
291	switch (reason) {
292
293	/* callbacks related to raw socket descriptor */
294
295        case LWS_CALLBACK_RAW_ADOPT:
296		//lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_ADOPT");
297                break;
298
299	case LWS_CALLBACK_RAW_CLOSE:
300		//lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_CLOSE");
301		break;
302
303	case LWS_CALLBACK_RAW_RX:
304		//lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_RX (%d)", (int)len);
305		// lwsl_hexdump_wsi_notice(wsi, in, len);
306		lws_adns_parse_udp(dns, in, len);
307		break;
308
309	case LWS_CALLBACK_RAW_WRITEABLE:
310		//lwsl_wsi_user(wsi, "LWS_CALLBACK_RAW_WRITEABLE");
311		lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
312					   dns->waiting.head) {
313			lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t,
314							   list);
315
316			if (//lws_dll2_is_detached(&q->sul.list) &&
317			    (!q->asked || q->responded != q->asked))
318				lws_async_dns_writeable(wsi, q);
319		} lws_end_foreach_dll_safe(d, d1);
320		break;
321
322	default:
323		break;
324	}
325
326	return 0;
327}
328
329struct lws_protocols lws_async_dns_protocol = {
330	"lws-async-dns", callback_async_dns, 0, 0, 0, NULL, 0
331};
332
333int
334lws_async_dns_init(struct lws_context *context)
335{
336	lws_async_dns_t *dns = &context->async_dns;
337	char ads[48];
338	int n;
339
340	if (dns->wsi)
341		return 0;
342
343	if (!context->vhost_list) { /* coverity... system vhost always present */
344		lwsl_cx_err(context, "no system vhost");
345		return 1;
346	}
347
348	memset(&dns->sa46, 0, sizeof(dns->sa46));
349
350#if defined(LWS_WITH_SYS_DHCP_CLIENT)
351	if (lws_dhcpc_status(context, &dns->sa46))
352		goto ok;
353#endif
354
355	n = lws_plat_asyncdns_init(context, &dns->sa46);
356	if (n < 0) {
357		lwsl_cx_warn(context, "no valid dns server, retry");
358
359		return 1;
360	}
361
362	if (n != LADNS_CONF_SERVER_CHANGED)
363		return 0;
364
365#if defined(LWS_WITH_SYS_DHCP_CLIENT)
366ok:
367#endif
368	dns->sa46.sa4.sin_port = htons(53);
369	lws_write_numeric_address((uint8_t *)&dns->sa46.sa4.sin_addr.s_addr, 4,
370				  ads, sizeof(ads));
371
372	dns->wsi = lws_create_adopt_udp(context->vhost_list, ads, 53, 0,
373					lws_async_dns_protocol.name, NULL,
374				        NULL, NULL, &retry_policy, "asyncdns");
375	if (!dns->wsi) {
376		lwsl_cx_err(context, "foreign socket adoption failed");
377		return 1;
378	}
379
380	context->async_dns.wsi->udp->sa46 = dns->sa46;
381
382	dns->dns_server_set = 1;
383
384	return 0;
385}
386
387lws_adns_cache_t *
388lws_adns_get_cache(lws_async_dns_t *dns, const char *name)
389{
390	lws_adns_cache_t *c;
391
392	if (!name) {
393		assert(0);
394		return NULL;
395	}
396
397	lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1,
398				   lws_dll2_get_head(&dns->cached)) {
399		c = lws_container_of(d, lws_adns_cache_t, list);
400
401		// lwsl_wsi_notice(dns->wsi, "%s vs %s (inc %d)", name, c->name, c->incomplete);
402
403		if (!c->incomplete && !strcasecmp(name, c->name)) {
404			/* Keep sorted by LRU: move to the head */
405			lws_dll2_remove(&c->list);
406			lws_dll2_add_head(&c->list, &dns->cached);
407
408			return c;
409		}
410	} lws_end_foreach_dll_safe(d, d1);
411
412	return NULL;
413}
414
415#if defined(_DEBUG)
416void
417lws_adns_dump(lws_async_dns_t *dns)
418{
419	lws_adns_cache_t *c;
420
421	if (!dns)
422		return;
423
424	lwsl_wsi_info(dns->wsi, "ADNS cache %u entries",
425			(unsigned int)dns->cached.count);
426
427	lws_start_foreach_dll(struct lws_dll2 *, d,
428			      lws_dll2_get_head(&dns->cached)) {
429		c = lws_container_of(d, lws_adns_cache_t, list);
430
431		lwsl_wsi_info(dns->wsi, "cache: '%s', exp: %lldus, incomp %d, "
432			  "fl 0x%x, refc %d, res %p\n", c->name,
433			  (long long)(c->sul.us - lws_now_usecs()),
434			  c->incomplete, c->flags, c->refcount, c->results);
435	} lws_end_foreach_dll(d);
436
437	lws_start_foreach_dll(struct lws_dll2 *, d,
438				   lws_dll2_get_head(&dns->waiting)) {
439		lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
440
441		lwsl_wsi_info(dns->wsi, "q: '%s', sent %d, resp %d",
442			    (const char *)&q[1], q->sent[0],
443			    q->responded);
444	} lws_end_foreach_dll(d);
445}
446#endif
447
448void
449lws_adns_cache_destroy(lws_adns_cache_t *c)
450{
451	lws_dll2_remove(&c->sul.list);
452	lws_dll2_remove(&c->list);
453	if (c->chain)
454		lws_free(c->chain);
455	lws_free(c);
456}
457
458static int
459cache_clean(struct lws_dll2 *d, void *user)
460{
461	lws_adns_cache_destroy(lws_container_of(d, lws_adns_cache_t, list));
462
463	return 0;
464}
465
466void
467sul_cb_expire(struct lws_sorted_usec_list *sul)
468{
469	lws_adns_cache_t *c = lws_container_of(sul, lws_adns_cache_t, sul);
470
471	lws_adns_cache_destroy(c);
472}
473
474void
475sul_cb_write(struct lws_sorted_usec_list *sul)
476{
477	lws_adns_q_t *q = lws_container_of(sul, lws_adns_q_t, write_sul);
478
479	/*
480	 * Something's up, we couldn't even get from write request to
481	 * WRITEABLE within the timeout, let alone the result... fail
482	 * the query and everyone riding on it...
483	 */
484
485	lwsl_wsi_info(q->dns ? q->dns->wsi : NULL, "failing");
486	lws_adns_dump(q->dns);
487
488	lws_async_dns_complete(q, NULL); /* no cache to relate to */
489	lws_adns_q_destroy(q);
490}
491
492void
493lws_async_dns_freeaddrinfo(const struct addrinfo **pai)
494{
495	lws_adns_cache_t *c;
496
497	if (!*pai)
498		return;
499
500	/*
501	 * First query may have been empty... if second has something, we
502	 * fixed up the first result to point to second... but it means
503	 * looking backwards from ai, which is c->result, which is the second
504	 * packet's results, doesn't get us to the firstcache pointer.
505	 *
506	 * Adjust c to the firstcache in this case.
507	 */
508
509	c = &((lws_adns_cache_t *)(*pai))[-1];
510	if (c->firstcache)
511		c = c->firstcache;
512
513	lwsl_debug("%s: c %p, %s, refcount %d -> %d\n", __func__, c,
514		   (c->results && c->results->ai_canonname) ?
515				c->results->ai_canonname : "none",
516						c->refcount, c->refcount - 1);
517
518	assert(c->refcount > 0);
519	c->refcount--;
520	*pai = NULL;
521}
522
523void
524lws_async_dns_trim_cache(lws_async_dns_t *dns)
525{
526	lws_adns_cache_t *c1;
527
528	if (dns->cached.count + 1< MAX_CACHE_ENTRIES)
529		return;
530
531	c1 = lws_container_of(lws_dll2_get_tail(&dns->cached),
532						lws_adns_cache_t, list);
533	if (c1->refcount)
534		lwsl_wsi_info(dns->wsi, "acache %p: refcount %d on purge",
535				c1, c1->refcount);
536	else
537		lws_adns_cache_destroy(c1);
538}
539
540
541static int
542clean(struct lws_dll2 *d, void *user)
543{
544	lws_adns_q_destroy(lws_container_of(d, lws_adns_q_t, list));
545
546	return 0;
547}
548
549void
550lws_async_dns_deinit(lws_async_dns_t *dns)
551{
552	lws_dll2_foreach_safe(&dns->waiting, NULL, clean);
553	lws_dll2_foreach_safe(&dns->cached, NULL, cache_clean);
554
555	if (dns->wsi && !dns->dns_server_connected) {
556		lwsl_wsi_notice(dns->wsi, "late free of incomplete dns wsi");
557		__lws_lc_untag(dns->wsi->a.context, &dns->wsi->lc);
558#if defined(LWS_WITH_SYS_METRICS)
559		lws_metrics_tags_destroy(&dns->wsi->cal_conn.mtags_owner);
560#endif
561		lws_free_set_NULL(dns->wsi->udp);
562		lws_free_set_NULL(dns->wsi);
563	}
564}
565
566
567static int
568cancel(struct lws_dll2 *d, void *user)
569{
570	lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
571
572	lws_start_foreach_dll_safe(struct lws_dll2 *, d3, d4,
573				   lws_dll2_get_head(&q->wsi_adns)) {
574		struct lws *w = lws_container_of(d3, struct lws, adns);
575
576		if (user == w) {
577			lws_dll2_remove(d3);
578			if (!q->wsi_adns.count)
579				lws_adns_q_destroy(q);
580			return 1;
581		}
582	} lws_end_foreach_dll_safe(d3, d4);
583
584	return 0;
585}
586
587void
588lws_async_dns_cancel(struct lws *wsi)
589{
590	lws_async_dns_t *dns = &wsi->a.context->async_dns;
591
592	lws_dll2_foreach_safe(&dns->waiting, wsi, cancel);
593}
594
595
596static int
597check_tid(struct lws_dll2 *d, void *user)
598{
599	lws_adns_q_t *q = lws_container_of(d, lws_adns_q_t, list);
600	int n = 0, nmax = q->tids >= LWS_ARRAY_SIZE(q->tid) ?
601			  LWS_ARRAY_SIZE(q->tid) : q->tids;
602	uint16_t check = (uint16_t)(intptr_t)user;
603
604	for (n = 0; n < nmax; n++)
605		if (check == q->tid[n])
606			return 1;
607
608	return 0;
609}
610
611int
612lws_async_dns_get_new_tid(struct lws_context *context, lws_adns_q_t *q)
613{
614	lws_async_dns_t *dns = &context->async_dns;
615	int budget = 10;
616
617	/*
618	 * Make the TID unpredictable, but must be unique amongst ongoing ones
619	 */
620	do {
621		uint16_t tid;
622
623		if (lws_get_random(context, &tid, 2) != 2)
624			return -1;
625
626		if (lws_dll2_foreach_safe(&dns->waiting,
627					  (void *)(intptr_t)tid, check_tid))
628			continue;
629
630		q->tids++;
631		LADNS_MOST_RECENT_TID(q) = tid;
632
633		return 0;
634
635	} while (budget--);
636
637	lwsl_cx_err(context, "unable to get unique tid");
638
639	return -1;
640}
641
642struct temp_q {
643	lws_adns_q_t tq;
644	char name[48];
645};
646
647lws_async_dns_retcode_t
648lws_async_dns_query(struct lws_context *context, int tsi, const char *name,
649		    adns_query_type_t qtype, lws_async_dns_cb_t cb,
650		    struct lws *wsi, void *opaque)
651{
652	lws_async_dns_t *dns = &context->async_dns;
653	size_t nlen = strlen(name);
654	lws_sockaddr46 *sa46;
655	lws_adns_cache_t *c;
656	struct addrinfo *ai;
657	struct temp_q tmq;
658	lws_adns_q_t *q;
659	uint8_t ads[16];
660	char *p;
661	int m;
662
663	lwsl_cx_info(context, "entry %s", name);
664	lws_adns_dump(dns);
665
666#if !defined(LWS_WITH_IPV6)
667	if (qtype == LWS_ADNS_RECORD_AAAA) {
668		lwsl_cx_err(context, "ipv6 not enabled");
669		goto failed;
670	}
671#endif
672
673	if (nlen >= DNS_MAX - 1)
674		goto failed;
675
676	/*
677	 * we magically know 'localhost' and 'localhost6' if IPv6, this is a
678	 * sort of canned /etc/hosts
679	 */
680
681	if (!strcmp(name, "localhost"))
682		name = "127.0.0.1";
683
684#if defined(LWS_WITH_IPV6)
685	if (!strcmp(name, "localhost6"))
686		name = "::1";
687#endif
688
689	if (wsi) {
690		if (!lws_dll2_is_detached(&wsi->adns)) {
691			lwsl_cx_err(context, "%s already bound to query %p",
692					lws_wsi_tag(wsi), wsi->adns.owner);
693			goto failed;
694		}
695		wsi->adns_cb = cb;
696	}
697
698	/* there's a done, cached query we can just reuse? */
699
700	c = lws_adns_get_cache(dns, name);
701	if (c) {
702		lwsl_cx_info(context, "%s: using cached, c->results %p",
703			  name, c->results);
704		m = c->results ? LADNS_RET_FOUND : LADNS_RET_FAILED;
705		if (c->results)
706			c->refcount++;
707
708#if defined(LWS_WITH_SYS_METRICS)
709		lws_metric_event(context->mt_adns_cache,  METRES_GO, 0);
710#endif
711
712		if (cb(wsi, name, c->results, m, opaque) == NULL)
713			return LADNS_RET_FAILED_WSI_CLOSED;
714
715		return m;
716	} else
717		lwsl_cx_info(context, "%s uncached", name);
718
719#if defined(LWS_WITH_SYS_METRICS)
720	lws_metric_event(context->mt_adns_cache, METRES_NOGO, 0);
721#endif
722
723	/*
724	 * It's a 1.2.3.4 or ::1 type IP address already?  We don't need a dns
725	 * server set up to be able to create an addrinfo result for that.
726	 *
727	 * Create it as a cached object so it follows the refcount lifecycle
728	 * of any other result
729	 */
730
731	m = lws_parse_numeric_address(name, ads, sizeof(ads));
732	if (m == 4
733#if defined(LWS_WITH_IPV6)
734		|| m == 16
735#endif
736	) {
737		lws_async_dns_trim_cache(dns);
738
739		c = lws_zalloc(sizeof(lws_adns_cache_t) +
740			       sizeof(struct addrinfo) +
741			       sizeof(lws_sockaddr46) + nlen + 1, "adns-numip");
742		if (!c)
743			goto failed;
744
745		ai = (struct addrinfo *)&c[1];
746		sa46 = (lws_sockaddr46 *)&ai[1];
747
748		ai->ai_socktype = SOCK_STREAM;
749		c->name = (const char *)&sa46[1];
750		memcpy((char *)c->name, name, nlen + 1);
751		ai->ai_canonname = (char *)&sa46[1];
752
753		c->results = ai;
754		memset(&tmq.tq, 0, sizeof(tmq.tq));
755		tmq.tq.opaque = opaque;
756		if (wsi) {
757			wsi->adns_cb = cb;
758			lws_dll2_add_head(&wsi->adns, &tmq.tq.wsi_adns);
759		} else
760			tmq.tq.standalone_cb = cb;
761		lws_strncpy(tmq.name, name, sizeof(tmq.name));
762
763		lws_dll2_add_head(&c->list, &dns->cached);
764		lws_sul_schedule(context, 0, &c->sul, sul_cb_expire,
765				 3600ll * LWS_US_PER_SEC);
766
767		lws_adns_dump(dns);
768	}
769
770	if (m == 4) {
771		ai = (struct addrinfo *)&c[1];
772		sa46 = (lws_sockaddr46 *)&ai[1];
773		ai->ai_family = sa46->sa4.sin_family = AF_INET;
774		ai->ai_addrlen = sizeof(sa46->sa4);
775		ai->ai_addr = (struct sockaddr *)&sa46->sa4;
776		memcpy(&sa46->sa4.sin_addr, ads, (unsigned int)m);
777
778		lws_async_dns_complete(&tmq.tq, c);
779
780		return LADNS_RET_FOUND;
781	}
782
783#if defined(LWS_WITH_IPV6)
784	if (m == 16) {
785		ai->ai_family = sa46->sa6.sin6_family = AF_INET6;
786		ai->ai_addrlen = sizeof(sa46->sa6);
787		ai->ai_addr = (struct sockaddr *)&sa46->sa6;
788		memcpy(&sa46->sa6.sin6_addr, ads, (unsigned int)m);
789
790		lws_async_dns_complete(&tmq.tq, c);
791
792		return LADNS_RET_FOUND;
793	}
794#endif
795
796	/*
797	 * to try anything else we need a remote server configured...
798	 */
799
800	if (!context->async_dns.dns_server_set &&
801	    lws_async_dns_init(context)) {
802		lwsl_cx_notice(context, "init failed");
803		goto failed;
804	}
805
806	/* there's an ongoing query we can share the result of */
807
808	q = lws_adns_get_query(dns, qtype, &dns->waiting, 0, name);
809	if (q) {
810		lwsl_cx_debug(context, "dns piggybacking: %d:%s",
811				qtype, name);
812		if (wsi)
813			lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
814
815		return LADNS_RET_CONTINUING;
816	}
817
818	/*
819	 * Allocate new query / queries... this is a bit complicated because
820	 * multiple queries in one packet are not supported peoperly in DNS
821	 * itself, and there's no reliable other way to get both ipv6 and ipv4
822	 * (AAAA and A) responses in one hit.
823	 *
824	 * If we don't support ipv6, it's simple, we just ask for A and that's
825	 * it.  But if we do support ipv6, we need to ask twice, once for A
826	 * and in a separate query, again for AAAA.
827	 *
828	 * For ipv6, A / ipv4 is routable over ipv6.  So we always ask for A
829	 * first and then if ipv6, AAAA separately.
830	 *
831	 * Allocate for DNS_MAX, because we may recurse and alter what we're
832	 * looking for.
833	 *
834	 * 0             sizeof(*q)                  sizeof(*q) + DNS_MAX
835	 * [lws_adns_q_t][ name (DNS_MAX reserved) ] [ name \0 ]
836	 */
837
838	q = (lws_adns_q_t *)lws_malloc(sizeof(*q) + DNS_MAX + nlen + 1,
839					__func__);
840	if (!q)
841		goto failed;
842	memset(q, 0, sizeof(*q));
843
844	if (wsi)
845		lws_dll2_add_head(&wsi->adns, &q->wsi_adns);
846
847	q->qtype = (uint16_t)qtype;
848
849	if (lws_async_dns_get_new_tid(context, q)) {
850		lwsl_cx_err(context, "tid fail");
851		goto failed;
852	}
853
854	LADNS_MOST_RECENT_TID(q) &= 0xfffe;
855	q->context = context;
856	q->tsi = (uint8_t)tsi;
857	q->opaque = opaque;
858	q->dns = dns;
859
860	if (!wsi)
861		q->standalone_cb = cb;
862
863	/* schedule a retry according to the retry policy on the wsi */
864	if (lws_retry_sul_schedule_retry_wsi(dns->wsi, &q->sul,
865					 lws_async_dns_sul_cb_retry, &q->retry))
866		goto failed;
867
868	/* fail us if we can't write by this timeout */
869	lws_sul_schedule(context, 0, &q->write_sul, sul_cb_write, LWS_US_PER_SEC);
870
871	/*
872	 * We may rewrite the copy at +sizeof(*q) for CNAME recursion.  Keep
873	 * a second copy at + sizeof(*q) + DNS_MAX so we can create the cache
874	 * entry for the original name, not the last CNAME we met.
875	 */
876
877	p = (char *)&q[1];
878	while (nlen--) {
879		*p++ = (char)tolower(*name++);
880		p[DNS_MAX - 1] = p[-1];
881	}
882	*p = '\0';
883	p[DNS_MAX] = '\0';
884
885	lws_callback_on_writable(dns->wsi);
886
887	lws_dll2_add_head(&q->list, &dns->waiting);
888
889	lws_metrics_caliper_bind(q->metcal, context->mt_conn_dns);
890	q->go_nogo = METRES_NOGO;
891	/* caliper is reported in lws_adns_q_destroy */
892
893	lwsl_cx_info(context, "created new query: %s", name);
894	lws_adns_dump(dns);
895
896	return LADNS_RET_CONTINUING;
897
898failed:
899	lwsl_cx_notice(context, "failed");
900	if (!cb(wsi, NULL, NULL, LADNS_RET_FAILED, opaque))
901		return LADNS_RET_FAILED_WSI_CLOSED;
902
903	return LADNS_RET_FAILED;
904}
905