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