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