• 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[] = { 300, 500, 700, 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_RETRY_CONCEAL_ALWAYS,
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_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 
45 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)46 lws_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 
76 void
lws_async_dns_drop_server(struct lws_context * context)77 lws_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 
85 int
lws_async_dns_complete(lws_adns_q_t * q,lws_adns_cache_t * c)86 lws_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 
128 static void
lws_async_dns_sul_cb_retry(struct lws_sorted_usec_list * sul)129 lws_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 
142 static void
lws_async_dns_writeable(struct lws * wsi,lws_adns_q_t * q)143 lws_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 
269 qfail:
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 
285 static int
callback_async_dns(struct lws * wsi,enum lws_callback_reasons reason,void * user,void * in,size_t len)286 callback_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 
329 struct lws_protocols lws_async_dns_protocol = {
330 	"lws-async-dns", callback_async_dns, 0, 0, 0, NULL, 0
331 };
332 
333 int
lws_async_dns_init(struct lws_context * context)334 lws_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)
366 ok:
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 
387 lws_adns_cache_t *
lws_adns_get_cache(lws_async_dns_t * dns,const char * name)388 lws_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)
416 void
lws_adns_dump(lws_async_dns_t * dns)417 lws_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 
448 void
lws_adns_cache_destroy(lws_adns_cache_t * c)449 lws_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 
458 static int
cache_clean(struct lws_dll2 * d,void * user)459 cache_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 
466 void
sul_cb_expire(struct lws_sorted_usec_list * sul)467 sul_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 
474 void
sul_cb_write(struct lws_sorted_usec_list * sul)475 sul_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 
492 void
lws_async_dns_freeaddrinfo(const struct addrinfo ** pai)493 lws_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 
523 void
lws_async_dns_trim_cache(lws_async_dns_t * dns)524 lws_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 
541 static int
clean(struct lws_dll2 * d,void * user)542 clean(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 
549 void
lws_async_dns_deinit(lws_async_dns_t * dns)550 lws_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 
567 static int
cancel(struct lws_dll2 * d,void * user)568 cancel(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 
587 void
lws_async_dns_cancel(struct lws * wsi)588 lws_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 
596 static int
check_tid(struct lws_dll2 * d,void * user)597 check_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 
611 int
lws_async_dns_get_new_tid(struct lws_context * context,lws_adns_q_t * q)612 lws_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 
642 struct temp_q {
643 	lws_adns_q_t tq;
644 	char name[48];
645 };
646 
647 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)648 lws_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 
898 failed:
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