1d4afb5ceSopenharmony_ci/* 2d4afb5ceSopenharmony_ci * libwebsockets - small server side websockets and web server implementation 3d4afb5ceSopenharmony_ci * 4d4afb5ceSopenharmony_ci * Copyright (C) 2010 - 2021 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_ci 29d4afb5ceSopenharmony_ci/* updates *dest, returns chars used from ls directly, else -1 for fail */ 30d4afb5ceSopenharmony_ci 31d4afb5ceSopenharmony_cistatic int 32d4afb5ceSopenharmony_cilws_adns_parse_label(const uint8_t *pkt, int len, const uint8_t *ls, int budget, 33d4afb5ceSopenharmony_ci char **dest, size_t dl) 34d4afb5ceSopenharmony_ci{ 35d4afb5ceSopenharmony_ci const uint8_t *e = pkt + len, *ols = ls; 36d4afb5ceSopenharmony_ci char pointer = 0, first = 1; 37d4afb5ceSopenharmony_ci uint8_t ll; 38d4afb5ceSopenharmony_ci int n; 39d4afb5ceSopenharmony_ci 40d4afb5ceSopenharmony_ci if (budget < 1) 41d4afb5ceSopenharmony_ci return 0; 42d4afb5ceSopenharmony_ci 43d4afb5ceSopenharmony_ci /* caller must catch end of labels */ 44d4afb5ceSopenharmony_ci assert(*ls); 45d4afb5ceSopenharmony_ci 46d4afb5ceSopenharmony_ciagain1: 47d4afb5ceSopenharmony_ci if (ls >= e) 48d4afb5ceSopenharmony_ci return -1; 49d4afb5ceSopenharmony_ci 50d4afb5ceSopenharmony_ci if (((*ls) & 0xc0) == 0xc0) { 51d4afb5ceSopenharmony_ci if (budget < 2) 52d4afb5ceSopenharmony_ci return -1; 53d4afb5ceSopenharmony_ci /* pointer into message pkt to name to actually use */ 54d4afb5ceSopenharmony_ci n = lws_ser_ru16be(ls) & 0x3fff; 55d4afb5ceSopenharmony_ci if (n >= len) { 56d4afb5ceSopenharmony_ci lwsl_notice("%s: illegal name pointer\n", __func__); 57d4afb5ceSopenharmony_ci 58d4afb5ceSopenharmony_ci return -1; 59d4afb5ceSopenharmony_ci } 60d4afb5ceSopenharmony_ci 61d4afb5ceSopenharmony_ci /* dereference the label pointer */ 62d4afb5ceSopenharmony_ci ls = pkt + n; 63d4afb5ceSopenharmony_ci 64d4afb5ceSopenharmony_ci /* are we being fuzzed or messed with? */ 65d4afb5ceSopenharmony_ci if (((*ls) & 0xc0) == 0xc0) { 66d4afb5ceSopenharmony_ci /* ... pointer to pointer is unreasonable */ 67d4afb5ceSopenharmony_ci lwsl_notice("%s: label ptr to ptr invalid\n", __func__); 68d4afb5ceSopenharmony_ci 69d4afb5ceSopenharmony_ci return -1; 70d4afb5ceSopenharmony_ci } 71d4afb5ceSopenharmony_ci pointer = 1; 72d4afb5ceSopenharmony_ci } 73d4afb5ceSopenharmony_ci 74d4afb5ceSopenharmony_ci if (ls >= e) 75d4afb5ceSopenharmony_ci return -1; 76d4afb5ceSopenharmony_ci 77d4afb5ceSopenharmony_ci ll = *ls++; 78d4afb5ceSopenharmony_ci if (ls + ll + 1 > e) { 79d4afb5ceSopenharmony_ci lwsl_notice("%s: label len invalid, %d vs %d\n", __func__, 80d4afb5ceSopenharmony_ci lws_ptr_diff((ls + ll + 1), pkt), lws_ptr_diff(e, pkt)); 81d4afb5ceSopenharmony_ci 82d4afb5ceSopenharmony_ci return -1; 83d4afb5ceSopenharmony_ci } 84d4afb5ceSopenharmony_ci 85d4afb5ceSopenharmony_ci if (ls + ll > ols + budget) { 86d4afb5ceSopenharmony_ci lwsl_notice("%s: label too long %d vs %d\n", __func__, ll, budget); 87d4afb5ceSopenharmony_ci 88d4afb5ceSopenharmony_ci return -1; 89d4afb5ceSopenharmony_ci } 90d4afb5ceSopenharmony_ci 91d4afb5ceSopenharmony_ci if ((unsigned int)ll + 2 > dl) { 92d4afb5ceSopenharmony_ci lwsl_notice("%s: qname too large\n", __func__); 93d4afb5ceSopenharmony_ci 94d4afb5ceSopenharmony_ci return -1; 95d4afb5ceSopenharmony_ci } 96d4afb5ceSopenharmony_ci 97d4afb5ceSopenharmony_ci /* copy the label content into place */ 98d4afb5ceSopenharmony_ci 99d4afb5ceSopenharmony_ci memcpy(*dest, ls, ll); 100d4afb5ceSopenharmony_ci (*dest)[ll] = '.'; 101d4afb5ceSopenharmony_ci (*dest)[ll + 1] = '\0'; 102d4afb5ceSopenharmony_ci *dest += ll + 1; 103d4afb5ceSopenharmony_ci ls += ll; 104d4afb5ceSopenharmony_ci 105d4afb5ceSopenharmony_ci if (pointer) { 106d4afb5ceSopenharmony_ci if (*ls) 107d4afb5ceSopenharmony_ci goto again1; 108d4afb5ceSopenharmony_ci 109d4afb5ceSopenharmony_ci /* 110d4afb5ceSopenharmony_ci * special fun rule... if whole qname was a pointer label, 111d4afb5ceSopenharmony_ci * it has no 00 terminator afterwards 112d4afb5ceSopenharmony_ci */ 113d4afb5ceSopenharmony_ci if (first) 114d4afb5ceSopenharmony_ci return 2; /* we just took the 16-bit pointer */ 115d4afb5ceSopenharmony_ci 116d4afb5ceSopenharmony_ci return 3; 117d4afb5ceSopenharmony_ci } 118d4afb5ceSopenharmony_ci 119d4afb5ceSopenharmony_ci first = 0; 120d4afb5ceSopenharmony_ci 121d4afb5ceSopenharmony_ci if (*ls) 122d4afb5ceSopenharmony_ci goto again1; 123d4afb5ceSopenharmony_ci 124d4afb5ceSopenharmony_ci ls++; 125d4afb5ceSopenharmony_ci 126d4afb5ceSopenharmony_ci return lws_ptr_diff(ls, ols); 127d4afb5ceSopenharmony_ci} 128d4afb5ceSopenharmony_ci 129d4afb5ceSopenharmony_citypedef int (*lws_async_dns_find_t)(const char *name, void *opaque, 130d4afb5ceSopenharmony_ci uint32_t ttl, adns_query_type_t type, 131d4afb5ceSopenharmony_ci const uint8_t *payload); 132d4afb5ceSopenharmony_ci 133d4afb5ceSopenharmony_ci/* locally query the response packet */ 134d4afb5ceSopenharmony_ci 135d4afb5ceSopenharmony_cistruct label_stack { 136d4afb5ceSopenharmony_ci char name[DNS_MAX]; 137d4afb5ceSopenharmony_ci int enl; 138d4afb5ceSopenharmony_ci const uint8_t *p; 139d4afb5ceSopenharmony_ci}; 140d4afb5ceSopenharmony_ci 141d4afb5ceSopenharmony_ci/* 142d4afb5ceSopenharmony_ci * Walk the response packet, calling back to the user-provided callback for each 143d4afb5ceSopenharmony_ci * A (and AAAA if LWS_IPV6=1) record with a matching name found in there. 144d4afb5ceSopenharmony_ci * 145d4afb5ceSopenharmony_ci * Able to recurse using an explicit non-CPU stack to resolve CNAME usages 146d4afb5ceSopenharmony_ci * 147d4afb5ceSopenharmony_ci * Return -1: unexpectedly failed 148d4afb5ceSopenharmony_ci * 0: found 149d4afb5ceSopenharmony_ci * 1: didn't find anything matching 150d4afb5ceSopenharmony_ci */ 151d4afb5ceSopenharmony_ci 152d4afb5ceSopenharmony_cistatic int 153d4afb5ceSopenharmony_cilws_adns_iterate(lws_adns_q_t *q, const uint8_t *pkt, int len, 154d4afb5ceSopenharmony_ci const char *expname, lws_async_dns_find_t cb, void *opaque) 155d4afb5ceSopenharmony_ci{ 156d4afb5ceSopenharmony_ci const uint8_t *e = pkt + len, *p, *pay; 157d4afb5ceSopenharmony_ci struct label_stack stack[4]; 158d4afb5ceSopenharmony_ci int n = 0, stp = 0, ansc, m; 159d4afb5ceSopenharmony_ci uint16_t rrtype, rrpaylen; 160d4afb5ceSopenharmony_ci char *sp, inq; 161d4afb5ceSopenharmony_ci uint32_t ttl; 162d4afb5ceSopenharmony_ci 163d4afb5ceSopenharmony_ci lws_strncpy(stack[0].name, expname, sizeof(stack[0].name)); 164d4afb5ceSopenharmony_ci stack[0].enl = (int)strlen(expname); 165d4afb5ceSopenharmony_ci 166d4afb5ceSopenharmony_cistart: 167d4afb5ceSopenharmony_ci ansc = lws_ser_ru16be(pkt + DHO_NANSWERS); 168d4afb5ceSopenharmony_ci p = pkt + DHO_SIZEOF; 169d4afb5ceSopenharmony_ci inq = 1; 170d4afb5ceSopenharmony_ci 171d4afb5ceSopenharmony_ci /* 172d4afb5ceSopenharmony_ci * The response also includes the query... and we have to parse it 173d4afb5ceSopenharmony_ci * so we can understand we reached the response... there's a QNAME 174d4afb5ceSopenharmony_ci * made up of labels and then 2 x 16-bit fields, for query type and 175d4afb5ceSopenharmony_ci * query class 176d4afb5ceSopenharmony_ci */ 177d4afb5ceSopenharmony_ci 178d4afb5ceSopenharmony_ci 179d4afb5ceSopenharmony_ci while (p + 14 < e && (inq || ansc)) { 180d4afb5ceSopenharmony_ci 181d4afb5ceSopenharmony_ci if (!inq && !stp) 182d4afb5ceSopenharmony_ci ansc--; 183d4afb5ceSopenharmony_ci 184d4afb5ceSopenharmony_ci /* 185d4afb5ceSopenharmony_ci * First is the name the query applies to... two main 186d4afb5ceSopenharmony_ci * formats can appear here, one is a pointer to 187d4afb5ceSopenharmony_ci * elsewhere in the message, the other separately 188d4afb5ceSopenharmony_ci * provides len / data for each dotted "label", so for 189d4afb5ceSopenharmony_ci * "warmcat.com" warmcat and com are given each with a 190d4afb5ceSopenharmony_ci * prepended length byte. Any of those may be a pointer 191d4afb5ceSopenharmony_ci * to somewhere else in the packet :-/ 192d4afb5ceSopenharmony_ci * 193d4afb5ceSopenharmony_ci * Paranoia is appropriate since the name length must be 194d4afb5ceSopenharmony_ci * parsed out before the rest of the RR can be used and 195d4afb5ceSopenharmony_ci * we can be attacked with absolutely any crafted 196d4afb5ceSopenharmony_ci * content easily via UDP. 197d4afb5ceSopenharmony_ci * 198d4afb5ceSopenharmony_ci * So parse the name and additionally confirm it matches 199d4afb5ceSopenharmony_ci * what the query the TID belongs to actually asked for. 200d4afb5ceSopenharmony_ci */ 201d4afb5ceSopenharmony_ci 202d4afb5ceSopenharmony_ci sp = stack[0].name; 203d4afb5ceSopenharmony_ci 204d4afb5ceSopenharmony_ci /* while we have more labels */ 205d4afb5ceSopenharmony_ci 206d4afb5ceSopenharmony_ci n = lws_adns_parse_label(pkt, len, p, len, &sp, 207d4afb5ceSopenharmony_ci sizeof(stack[0].name) - 208d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(sp, stack[0].name)); 209d4afb5ceSopenharmony_ci /* includes case name won't fit */ 210d4afb5ceSopenharmony_ci if (n < 0) 211d4afb5ceSopenharmony_ci return -1; 212d4afb5ceSopenharmony_ci 213d4afb5ceSopenharmony_ci p += n; 214d4afb5ceSopenharmony_ci 215d4afb5ceSopenharmony_ci if (p + (inq ? 5 : 14) > e) 216d4afb5ceSopenharmony_ci return -1; 217d4afb5ceSopenharmony_ci 218d4afb5ceSopenharmony_ci /* 219d4afb5ceSopenharmony_ci * p is now just after the decoded RR name, pointing at: type 220d4afb5ceSopenharmony_ci * 221d4afb5ceSopenharmony_ci * We sent class = 1 = IN query... response must match 222d4afb5ceSopenharmony_ci */ 223d4afb5ceSopenharmony_ci 224d4afb5ceSopenharmony_ci if (lws_ser_ru16be(&p[2]) != 1) { 225d4afb5ceSopenharmony_ci lwsl_err("%s: non-IN response 0x%x\n", __func__, 226d4afb5ceSopenharmony_ci lws_ser_ru16be(&p[2])); 227d4afb5ceSopenharmony_ci 228d4afb5ceSopenharmony_ci return -1; 229d4afb5ceSopenharmony_ci } 230d4afb5ceSopenharmony_ci 231d4afb5ceSopenharmony_ci if (inq) { 232d4afb5ceSopenharmony_ci lwsl_debug("%s: reached end of inq\n", __func__); 233d4afb5ceSopenharmony_ci inq = 0; 234d4afb5ceSopenharmony_ci p += 4; 235d4afb5ceSopenharmony_ci continue; 236d4afb5ceSopenharmony_ci } 237d4afb5ceSopenharmony_ci 238d4afb5ceSopenharmony_ci /* carefully validate the claimed RR payload length */ 239d4afb5ceSopenharmony_ci 240d4afb5ceSopenharmony_ci rrpaylen = lws_ser_ru16be(&p[8]); 241d4afb5ceSopenharmony_ci if (p + 10 + rrpaylen > e) { /* it may be == e */ 242d4afb5ceSopenharmony_ci lwsl_notice("%s: invalid RR data length\n", __func__); 243d4afb5ceSopenharmony_ci 244d4afb5ceSopenharmony_ci return -1; 245d4afb5ceSopenharmony_ci } 246d4afb5ceSopenharmony_ci 247d4afb5ceSopenharmony_ci ttl = lws_ser_ru32be(&p[4]); 248d4afb5ceSopenharmony_ci rrtype = lws_ser_ru16be(&p[0]); 249d4afb5ceSopenharmony_ci p += 10; /* point to the payload */ 250d4afb5ceSopenharmony_ci pay = p; 251d4afb5ceSopenharmony_ci 252d4afb5ceSopenharmony_ci /* 253d4afb5ceSopenharmony_ci * Compare the RR names, allowing for the decoded labelname 254d4afb5ceSopenharmony_ci * to have an extra '.' at the end. 255d4afb5ceSopenharmony_ci */ 256d4afb5ceSopenharmony_ci 257d4afb5ceSopenharmony_ci n = lws_ptr_diff(sp, stack[0].name); 258d4afb5ceSopenharmony_ci if (stack[0].name[n - 1] == '.') 259d4afb5ceSopenharmony_ci n--; 260d4afb5ceSopenharmony_ci 261d4afb5ceSopenharmony_ci m = stack[stp].enl; 262d4afb5ceSopenharmony_ci if (stack[stp].name[m - 1] == '.') 263d4afb5ceSopenharmony_ci m--; 264d4afb5ceSopenharmony_ci 265d4afb5ceSopenharmony_ci if (n < 1 || n != m || 266d4afb5ceSopenharmony_ci strncmp(stack[0].name, stack[stp].name, (unsigned int)n)) { 267d4afb5ceSopenharmony_ci //lwsl_notice("%s: skipping %s vs %s\n", __func__, 268d4afb5ceSopenharmony_ci // stack[0].name, stack[stp].name); 269d4afb5ceSopenharmony_ci goto skip; 270d4afb5ceSopenharmony_ci } 271d4afb5ceSopenharmony_ci 272d4afb5ceSopenharmony_ci /* 273d4afb5ceSopenharmony_ci * It's something we could be interested in... 274d4afb5ceSopenharmony_ci * 275d4afb5ceSopenharmony_ci * We can skip RRs we don't understand. But we need to deal 276d4afb5ceSopenharmony_ci * with at least these and their payloads: 277d4afb5ceSopenharmony_ci * 278d4afb5ceSopenharmony_ci * A: 4: ipv4 address 279d4afb5ceSopenharmony_ci * AAAA: 16: ipv6 address (if asked for AAAA) 280d4afb5ceSopenharmony_ci * CNAME: ?: labelized name 281d4afb5ceSopenharmony_ci * 282d4afb5ceSopenharmony_ci * If we hit a CNAME we need to try to dereference it with 283d4afb5ceSopenharmony_ci * stuff that is in the same response packet and judge it 284d4afb5ceSopenharmony_ci * from that, without losing our place here. CNAMEs may 285d4afb5ceSopenharmony_ci * point to CNAMEs to whatever depth we're willing to handle. 286d4afb5ceSopenharmony_ci */ 287d4afb5ceSopenharmony_ci 288d4afb5ceSopenharmony_ci switch (rrtype) { 289d4afb5ceSopenharmony_ci 290d4afb5ceSopenharmony_ci case LWS_ADNS_RECORD_AAAA: 291d4afb5ceSopenharmony_ci if (rrpaylen != 16) { 292d4afb5ceSopenharmony_ci lwsl_err("%s: unexpected rrpaylen\n", __func__); 293d4afb5ceSopenharmony_ci return -1; 294d4afb5ceSopenharmony_ci } 295d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 296d4afb5ceSopenharmony_ci goto do_cb; 297d4afb5ceSopenharmony_ci#else 298d4afb5ceSopenharmony_ci break; 299d4afb5ceSopenharmony_ci#endif 300d4afb5ceSopenharmony_ci 301d4afb5ceSopenharmony_ci case LWS_ADNS_RECORD_A: 302d4afb5ceSopenharmony_ci if (rrpaylen != 4) { 303d4afb5ceSopenharmony_ci lwsl_err("%s: unexpected rrpaylen4\n", __func__); 304d4afb5ceSopenharmony_ci 305d4afb5ceSopenharmony_ci return -1; 306d4afb5ceSopenharmony_ci } 307d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 308d4afb5ceSopenharmony_cido_cb: 309d4afb5ceSopenharmony_ci#endif 310d4afb5ceSopenharmony_ci cb(stack[0].name, opaque, ttl, rrtype, p); 311d4afb5ceSopenharmony_ci break; 312d4afb5ceSopenharmony_ci 313d4afb5ceSopenharmony_ci case LWS_ADNS_RECORD_CNAME: 314d4afb5ceSopenharmony_ci /* 315d4afb5ceSopenharmony_ci * The name the CNAME refers to MAY itself be 316d4afb5ceSopenharmony_ci * included elsewhere in the response packet. 317d4afb5ceSopenharmony_ci * 318d4afb5ceSopenharmony_ci * So switch tack, stack where to resume from and 319d4afb5ceSopenharmony_ci * search for the decoded CNAME label name definition 320d4afb5ceSopenharmony_ci * instead. 321d4afb5ceSopenharmony_ci * 322d4afb5ceSopenharmony_ci * First decode the CNAME label payload into the next 323d4afb5ceSopenharmony_ci * stack level buffer for it. 324d4afb5ceSopenharmony_ci */ 325d4afb5ceSopenharmony_ci 326d4afb5ceSopenharmony_ci if (++stp == (int)LWS_ARRAY_SIZE(stack)) { 327d4afb5ceSopenharmony_ci lwsl_notice("%s: CNAMEs too deep\n", __func__); 328d4afb5ceSopenharmony_ci 329d4afb5ceSopenharmony_ci return -1; 330d4afb5ceSopenharmony_ci } 331d4afb5ceSopenharmony_ci sp = stack[stp].name; 332d4afb5ceSopenharmony_ci /* get the cname alias */ 333d4afb5ceSopenharmony_ci n = lws_adns_parse_label(pkt, len, p, rrpaylen, &sp, 334d4afb5ceSopenharmony_ci sizeof(stack[stp].name) - 335d4afb5ceSopenharmony_ci lws_ptr_diff_size_t(sp, stack[stp].name)); 336d4afb5ceSopenharmony_ci /* includes case name won't fit */ 337d4afb5ceSopenharmony_ci if (n < 0) 338d4afb5ceSopenharmony_ci return -1; 339d4afb5ceSopenharmony_ci 340d4afb5ceSopenharmony_ci p += n; 341d4afb5ceSopenharmony_ci 342d4afb5ceSopenharmony_ci if (p + 14 > e) 343d4afb5ceSopenharmony_ci return -1; 344d4afb5ceSopenharmony_ci#if 0 345d4afb5ceSopenharmony_ci /* it should have exactly reached rrpaylen if only one 346d4afb5ceSopenharmony_ci * CNAME, else somewhere in the middle */ 347d4afb5ceSopenharmony_ci 348d4afb5ceSopenharmony_ci if (p != pay + rrpaylen) { 349d4afb5ceSopenharmony_ci lwsl_err("%s: cname name bad len %d\n", __func__, rrpaylen); 350d4afb5ceSopenharmony_ci 351d4afb5ceSopenharmony_ci return -1; 352d4afb5ceSopenharmony_ci } 353d4afb5ceSopenharmony_ci#endif 354d4afb5ceSopenharmony_ci lwsl_notice("%s: recursing looking for %s\n", __func__, stack[stp].name); 355d4afb5ceSopenharmony_ci 356d4afb5ceSopenharmony_ci lwsl_info("%s: recursing looking for %s\n", __func__, 357d4afb5ceSopenharmony_ci stack[stp].name); 358d4afb5ceSopenharmony_ci 359d4afb5ceSopenharmony_ci stack[stp].enl = lws_ptr_diff(sp, stack[stp].name); 360d4afb5ceSopenharmony_ci /* when we unstack, resume from here */ 361d4afb5ceSopenharmony_ci stack[stp].p = pay + rrpaylen; 362d4afb5ceSopenharmony_ci goto start; 363d4afb5ceSopenharmony_ci 364d4afb5ceSopenharmony_ci default: 365d4afb5ceSopenharmony_ci break; 366d4afb5ceSopenharmony_ci } 367d4afb5ceSopenharmony_ci 368d4afb5ceSopenharmony_ciskip: 369d4afb5ceSopenharmony_ci p += rrpaylen; 370d4afb5ceSopenharmony_ci } 371d4afb5ceSopenharmony_ci 372d4afb5ceSopenharmony_ci if (!stp) 373d4afb5ceSopenharmony_ci return 1; /* we didn't find anything, but we didn't error */ 374d4afb5ceSopenharmony_ci 375d4afb5ceSopenharmony_ci lwsl_info("%s: '%s' -> CNAME '%s' resolution not provided, recursing\n", 376d4afb5ceSopenharmony_ci __func__, ((const char *)&q[1]) + DNS_MAX, 377d4afb5ceSopenharmony_ci stack[stp].name); 378d4afb5ceSopenharmony_ci 379d4afb5ceSopenharmony_ci /* 380d4afb5ceSopenharmony_ci * This implies there wasn't any usable definition for the 381d4afb5ceSopenharmony_ci * CNAME in the end, eg, only AAAA when we needed an A. 382d4afb5ceSopenharmony_ci * 383d4afb5ceSopenharmony_ci * It's also legit if the DNS just returns the CNAME, and that server 384d4afb5ceSopenharmony_ci * did not directly know the next step in resolution of the CNAME, so 385d4afb5ceSopenharmony_ci * instead of putting the resolution elsewhere in the response, has 386d4afb5ceSopenharmony_ci * told us just the CNAME and left it to us to find out its resolution 387d4afb5ceSopenharmony_ci * separately. 388d4afb5ceSopenharmony_ci * 389d4afb5ceSopenharmony_ci * Reset this request to be for the CNAME, and restart the request 390d4afb5ceSopenharmony_ci * action with a new tid. 391d4afb5ceSopenharmony_ci */ 392d4afb5ceSopenharmony_ci 393d4afb5ceSopenharmony_ci if (lws_async_dns_get_new_tid(q->context, q)) 394d4afb5ceSopenharmony_ci return -1; 395d4afb5ceSopenharmony_ci 396d4afb5ceSopenharmony_ci LADNS_MOST_RECENT_TID(q) &= 0xfffe; 397d4afb5ceSopenharmony_ci q->asked = q->responded = 0; 398d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 399d4afb5ceSopenharmony_ci q->sent[1] = 0; 400d4afb5ceSopenharmony_ci#endif 401d4afb5ceSopenharmony_ci q->sent[0] = 0; 402d4afb5ceSopenharmony_ci q->recursion++; 403d4afb5ceSopenharmony_ci if (q->recursion == DNS_RECURSION_LIMIT) { 404d4afb5ceSopenharmony_ci lwsl_err("%s: recursion overflow\n", __func__); 405d4afb5ceSopenharmony_ci 406d4afb5ceSopenharmony_ci return -1; 407d4afb5ceSopenharmony_ci } 408d4afb5ceSopenharmony_ci 409d4afb5ceSopenharmony_ci if (q->firstcache) 410d4afb5ceSopenharmony_ci lws_adns_cache_destroy(q->firstcache); 411d4afb5ceSopenharmony_ci q->firstcache = NULL; 412d4afb5ceSopenharmony_ci 413d4afb5ceSopenharmony_ci /* overwrite the query name with the CNAME */ 414d4afb5ceSopenharmony_ci 415d4afb5ceSopenharmony_ci n = 0; 416d4afb5ceSopenharmony_ci { 417d4afb5ceSopenharmony_ci char *cp = (char *)&q[1]; 418d4afb5ceSopenharmony_ci 419d4afb5ceSopenharmony_ci while (stack[stp].name[n]) 420d4afb5ceSopenharmony_ci *cp++ = (char)tolower(stack[stp].name[n++]); 421d4afb5ceSopenharmony_ci /* trim the following . if any */ 422d4afb5ceSopenharmony_ci if (n && cp[-1] == '.') 423d4afb5ceSopenharmony_ci cp--; 424d4afb5ceSopenharmony_ci *cp = '\0'; 425d4afb5ceSopenharmony_ci } 426d4afb5ceSopenharmony_ci 427d4afb5ceSopenharmony_ci lws_callback_on_writable(q->dns->wsi); 428d4afb5ceSopenharmony_ci 429d4afb5ceSopenharmony_ci return 2; 430d4afb5ceSopenharmony_ci} 431d4afb5ceSopenharmony_ci 432d4afb5ceSopenharmony_ciint 433d4afb5ceSopenharmony_cilws_async_dns_estimate(const char *name, void *opaque, uint32_t ttl, 434d4afb5ceSopenharmony_ci adns_query_type_t type, const uint8_t *payload) 435d4afb5ceSopenharmony_ci{ 436d4afb5ceSopenharmony_ci size_t *est = (size_t *)opaque, my; 437d4afb5ceSopenharmony_ci 438d4afb5ceSopenharmony_ci my = sizeof(struct addrinfo); 439d4afb5ceSopenharmony_ci if (type == LWS_ADNS_RECORD_AAAA) 440d4afb5ceSopenharmony_ci my += sizeof(struct sockaddr_in6); 441d4afb5ceSopenharmony_ci else 442d4afb5ceSopenharmony_ci my += sizeof(struct sockaddr_in); 443d4afb5ceSopenharmony_ci 444d4afb5ceSopenharmony_ci *est += my; 445d4afb5ceSopenharmony_ci 446d4afb5ceSopenharmony_ci return 0; 447d4afb5ceSopenharmony_ci} 448d4afb5ceSopenharmony_ci 449d4afb5ceSopenharmony_cistruct adstore { 450d4afb5ceSopenharmony_ci const char *name; 451d4afb5ceSopenharmony_ci struct addrinfo *pos; 452d4afb5ceSopenharmony_ci struct addrinfo *prev; 453d4afb5ceSopenharmony_ci int ctr; 454d4afb5ceSopenharmony_ci uint32_t smallest_ttl; 455d4afb5ceSopenharmony_ci uint8_t flags; 456d4afb5ceSopenharmony_ci}; 457d4afb5ceSopenharmony_ci 458d4afb5ceSopenharmony_ci/* 459d4afb5ceSopenharmony_ci * Callback for each A or AAAA record, creating getaddrinfo-compatible results 460d4afb5ceSopenharmony_ci * into the preallocated exact-sized storage. 461d4afb5ceSopenharmony_ci */ 462d4afb5ceSopenharmony_ciint 463d4afb5ceSopenharmony_cilws_async_dns_store(const char *name, void *opaque, uint32_t ttl, 464d4afb5ceSopenharmony_ci adns_query_type_t type, const uint8_t *payload) 465d4afb5ceSopenharmony_ci{ 466d4afb5ceSopenharmony_ci struct adstore *adst = (struct adstore *)opaque; 467d4afb5ceSopenharmony_ci#if defined(_DEBUG) 468d4afb5ceSopenharmony_ci char buf[48]; 469d4afb5ceSopenharmony_ci#endif 470d4afb5ceSopenharmony_ci size_t i; 471d4afb5ceSopenharmony_ci 472d4afb5ceSopenharmony_ci if (ttl < adst->smallest_ttl || !adst->ctr) 473d4afb5ceSopenharmony_ci adst->smallest_ttl = ttl; 474d4afb5ceSopenharmony_ci 475d4afb5ceSopenharmony_ci if (adst->prev) 476d4afb5ceSopenharmony_ci adst->prev->ai_next = adst->pos; 477d4afb5ceSopenharmony_ci adst->prev = adst->pos; 478d4afb5ceSopenharmony_ci 479d4afb5ceSopenharmony_ci adst->pos->ai_flags = 0; 480d4afb5ceSopenharmony_ci adst->pos->ai_family = type == LWS_ADNS_RECORD_AAAA ? 481d4afb5ceSopenharmony_ci AF_INET6 : AF_INET; 482d4afb5ceSopenharmony_ci adst->pos->ai_socktype = SOCK_STREAM; 483d4afb5ceSopenharmony_ci adst->pos->ai_protocol = IPPROTO_UDP; /* no meaning */ 484d4afb5ceSopenharmony_ci adst->pos->ai_addrlen = type == LWS_ADNS_RECORD_AAAA ? 485d4afb5ceSopenharmony_ci sizeof(struct sockaddr_in6) : 486d4afb5ceSopenharmony_ci sizeof(struct sockaddr_in); 487d4afb5ceSopenharmony_ci adst->pos->ai_canonname = (char *)adst->name; 488d4afb5ceSopenharmony_ci adst->pos->ai_addr = (struct sockaddr *)&adst->pos[1]; 489d4afb5ceSopenharmony_ci adst->pos->ai_next = NULL; 490d4afb5ceSopenharmony_ci 491d4afb5ceSopenharmony_ci#if defined(LWS_WITH_IPV6) 492d4afb5ceSopenharmony_ci if (type == LWS_ADNS_RECORD_AAAA) { 493d4afb5ceSopenharmony_ci struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&adst->pos[1]; 494d4afb5ceSopenharmony_ci 495d4afb5ceSopenharmony_ci i = sizeof(*in6); 496d4afb5ceSopenharmony_ci memset(in6, 0, i); 497d4afb5ceSopenharmony_ci in6->sin6_family = (sa_family_t)adst->pos->ai_family; 498d4afb5ceSopenharmony_ci memcpy(in6->sin6_addr.s6_addr, payload, 16); 499d4afb5ceSopenharmony_ci adst->flags |= 2; 500d4afb5ceSopenharmony_ci } else 501d4afb5ceSopenharmony_ci#endif 502d4afb5ceSopenharmony_ci { 503d4afb5ceSopenharmony_ci struct sockaddr_in *in = (struct sockaddr_in *)&adst->pos[1]; 504d4afb5ceSopenharmony_ci 505d4afb5ceSopenharmony_ci i = sizeof(*in); 506d4afb5ceSopenharmony_ci memset(in, 0, i); 507d4afb5ceSopenharmony_ci in->sin_family = (sa_family_t)adst->pos->ai_family; 508d4afb5ceSopenharmony_ci memcpy(&in->sin_addr.s_addr, payload, 4); 509d4afb5ceSopenharmony_ci adst->flags |= 1; 510d4afb5ceSopenharmony_ci } 511d4afb5ceSopenharmony_ci 512d4afb5ceSopenharmony_ci adst->pos = (struct addrinfo *)((uint8_t *)adst->pos + 513d4afb5ceSopenharmony_ci sizeof(struct addrinfo) + i); 514d4afb5ceSopenharmony_ci 515d4afb5ceSopenharmony_ci#if defined(_DEBUG) 516d4afb5ceSopenharmony_ci if (lws_write_numeric_address(payload, 517d4afb5ceSopenharmony_ci type == LWS_ADNS_RECORD_AAAA ? 16 : 4, 518d4afb5ceSopenharmony_ci buf, sizeof(buf)) > 0) 519d4afb5ceSopenharmony_ci lwsl_info("%s: %d: %s: %s\n", __func__, adst->ctr, 520d4afb5ceSopenharmony_ci adst->name, buf); 521d4afb5ceSopenharmony_ci#endif 522d4afb5ceSopenharmony_ci adst->ctr++; 523d4afb5ceSopenharmony_ci 524d4afb5ceSopenharmony_ci return 0; 525d4afb5ceSopenharmony_ci} 526d4afb5ceSopenharmony_ci 527d4afb5ceSopenharmony_ci/* 528d4afb5ceSopenharmony_ci * We want to parse out all A or AAAA records 529d4afb5ceSopenharmony_ci */ 530d4afb5ceSopenharmony_ci 531d4afb5ceSopenharmony_civoid 532d4afb5ceSopenharmony_cilws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len) 533d4afb5ceSopenharmony_ci{ 534d4afb5ceSopenharmony_ci const char *nm, *nmcname; 535d4afb5ceSopenharmony_ci lws_adns_cache_t *c; 536d4afb5ceSopenharmony_ci struct adstore adst; 537d4afb5ceSopenharmony_ci lws_adns_q_t *q; 538d4afb5ceSopenharmony_ci int n, ncname; 539d4afb5ceSopenharmony_ci size_t est; 540d4afb5ceSopenharmony_ci 541d4afb5ceSopenharmony_ci // lwsl_hexdump_notice(pkt, len); 542d4afb5ceSopenharmony_ci 543d4afb5ceSopenharmony_ci /* we have to at least have the header */ 544d4afb5ceSopenharmony_ci 545d4afb5ceSopenharmony_ci if (len < DHO_SIZEOF) 546d4afb5ceSopenharmony_ci return; 547d4afb5ceSopenharmony_ci 548d4afb5ceSopenharmony_ci /* we asked with one query, so anything else is bogus */ 549d4afb5ceSopenharmony_ci 550d4afb5ceSopenharmony_ci if (lws_ser_ru16be(pkt + DHO_NQUERIES) != 1) 551d4afb5ceSopenharmony_ci return; 552d4afb5ceSopenharmony_ci 553d4afb5ceSopenharmony_ci /* match both A and AAAA queries if any */ 554d4afb5ceSopenharmony_ci 555d4afb5ceSopenharmony_ci q = lws_adns_get_query(dns, 0, &dns->waiting, 556d4afb5ceSopenharmony_ci lws_ser_ru16be(pkt + DHO_TID), NULL); 557d4afb5ceSopenharmony_ci if (!q) { 558d4afb5ceSopenharmony_ci lwsl_info("%s: dropping unknown query tid 0x%x\n", 559d4afb5ceSopenharmony_ci __func__, lws_ser_ru16be(pkt + DHO_TID)); 560d4afb5ceSopenharmony_ci 561d4afb5ceSopenharmony_ci return; 562d4afb5ceSopenharmony_ci } 563d4afb5ceSopenharmony_ci 564d4afb5ceSopenharmony_ci /* we can get dups... drop any that have already happened */ 565d4afb5ceSopenharmony_ci 566d4afb5ceSopenharmony_ci n = 1 << (lws_ser_ru16be(pkt + DHO_TID) & 1); 567d4afb5ceSopenharmony_ci if (q->responded & n) { 568d4afb5ceSopenharmony_ci lwsl_notice("%s: dup\n", __func__); 569d4afb5ceSopenharmony_ci goto fail_out; 570d4afb5ceSopenharmony_ci } 571d4afb5ceSopenharmony_ci 572d4afb5ceSopenharmony_ci q->responded = (uint8_t)(q->responded | n); 573d4afb5ceSopenharmony_ci 574d4afb5ceSopenharmony_ci /* we want to confirm the results against what we last requested... */ 575d4afb5ceSopenharmony_ci 576d4afb5ceSopenharmony_ci nmcname = ((const char *)&q[1]); 577d4afb5ceSopenharmony_ci 578d4afb5ceSopenharmony_ci /* 579d4afb5ceSopenharmony_ci * First walk the packet figuring out the allocation needed for all 580d4afb5ceSopenharmony_ci * the results. Produce the following layout at c 581d4afb5ceSopenharmony_ci * 582d4afb5ceSopenharmony_ci * lws_adns_cache_t: new cache object 583d4afb5ceSopenharmony_ci * [struct addrinfo + struct sockaddr_in or _in6]: for each A or AAAA 584d4afb5ceSopenharmony_ci * char []: copy of resolved name 585d4afb5ceSopenharmony_ci */ 586d4afb5ceSopenharmony_ci 587d4afb5ceSopenharmony_ci ncname = (int)strlen(nmcname) + 1; 588d4afb5ceSopenharmony_ci 589d4afb5ceSopenharmony_ci est = sizeof(lws_adns_cache_t) + (unsigned int)ncname; 590d4afb5ceSopenharmony_ci if (lws_ser_ru16be(pkt + DHO_NANSWERS)) { 591d4afb5ceSopenharmony_ci int ir = lws_adns_iterate(q, pkt, (int)len, nmcname, 592d4afb5ceSopenharmony_ci lws_async_dns_estimate, &est); 593d4afb5ceSopenharmony_ci if (ir < 0) 594d4afb5ceSopenharmony_ci goto fail_out; 595d4afb5ceSopenharmony_ci 596d4afb5ceSopenharmony_ci if (ir == 2) /* CNAME recursive resolution */ 597d4afb5ceSopenharmony_ci return; 598d4afb5ceSopenharmony_ci } 599d4afb5ceSopenharmony_ci 600d4afb5ceSopenharmony_ci /* but we want to create the cache entry against the original request */ 601d4afb5ceSopenharmony_ci 602d4afb5ceSopenharmony_ci nm = ((const char *)&q[1]) + DNS_MAX; 603d4afb5ceSopenharmony_ci n = (int)strlen(nm) + 1; 604d4afb5ceSopenharmony_ci 605d4afb5ceSopenharmony_ci lwsl_info("%s: create cache entry for %s, %zu\n", __func__, nm, 606d4afb5ceSopenharmony_ci est - sizeof(lws_adns_cache_t)); 607d4afb5ceSopenharmony_ci c = lws_malloc(est + 1, "async-dns-entry"); 608d4afb5ceSopenharmony_ci if (!c) { 609d4afb5ceSopenharmony_ci lwsl_err("%s: OOM %zu\n", __func__, est); 610d4afb5ceSopenharmony_ci goto fail_out; 611d4afb5ceSopenharmony_ci } 612d4afb5ceSopenharmony_ci memset(c, 0, sizeof(*c)); 613d4afb5ceSopenharmony_ci 614d4afb5ceSopenharmony_ci /* place it at end, no need to care about alignment padding */ 615d4afb5ceSopenharmony_ci c->name = adst.name = ((const char *)c) + est - n; 616d4afb5ceSopenharmony_ci memcpy((char *)c->name, nm, (unsigned int)n); 617d4afb5ceSopenharmony_ci 618d4afb5ceSopenharmony_ci /* 619d4afb5ceSopenharmony_ci * Then walk the packet again, placing the objects we accounted for 620d4afb5ceSopenharmony_ci * the first time into the result allocation after the cache object 621d4afb5ceSopenharmony_ci * and copy of the name 622d4afb5ceSopenharmony_ci */ 623d4afb5ceSopenharmony_ci 624d4afb5ceSopenharmony_ci adst.pos = (struct addrinfo *)&c[1]; 625d4afb5ceSopenharmony_ci adst.prev = NULL; 626d4afb5ceSopenharmony_ci adst.ctr = 0; 627d4afb5ceSopenharmony_ci adst.smallest_ttl = 3600; 628d4afb5ceSopenharmony_ci adst.flags = 0; 629d4afb5ceSopenharmony_ci 630d4afb5ceSopenharmony_ci /* 631d4afb5ceSopenharmony_ci * smallest_ttl applies as it is to empty results (NXDOMAIN), or is 632d4afb5ceSopenharmony_ci * set to the minimum ttl seen in all the results. 633d4afb5ceSopenharmony_ci */ 634d4afb5ceSopenharmony_ci 635d4afb5ceSopenharmony_ci if (lws_ser_ru16be(pkt + DHO_NANSWERS) && 636d4afb5ceSopenharmony_ci lws_adns_iterate(q, pkt, (int)len, nmcname, lws_async_dns_store, &adst) < 0) { 637d4afb5ceSopenharmony_ci lws_free(c); 638d4afb5ceSopenharmony_ci goto fail_out; 639d4afb5ceSopenharmony_ci } 640d4afb5ceSopenharmony_ci 641d4afb5ceSopenharmony_ci if (lws_ser_ru16be(pkt + DHO_NANSWERS)) { 642d4afb5ceSopenharmony_ci c->results = (struct addrinfo *)&c[1]; 643d4afb5ceSopenharmony_ci if (q->last) /* chain the second one on */ 644d4afb5ceSopenharmony_ci *q->last = c->results; 645d4afb5ceSopenharmony_ci else /* first one had no results, set first guy's c->results */ 646d4afb5ceSopenharmony_ci if (q->firstcache) 647d4afb5ceSopenharmony_ci q->firstcache->results = c->results; 648d4afb5ceSopenharmony_ci } 649d4afb5ceSopenharmony_ci 650d4afb5ceSopenharmony_ci if (adst.prev) /* so we know where to continue the addrinfo list */ 651d4afb5ceSopenharmony_ci /* can be NULL if first resp empty */ 652d4afb5ceSopenharmony_ci q->last = &adst.prev->ai_next; 653d4afb5ceSopenharmony_ci 654d4afb5ceSopenharmony_ci if (q->firstcache) { /* also need to free chain when we free this guy */ 655d4afb5ceSopenharmony_ci q->firstcache->chain = c; 656d4afb5ceSopenharmony_ci c->firstcache = q->firstcache; 657d4afb5ceSopenharmony_ci } else { 658d4afb5ceSopenharmony_ci 659d4afb5ceSopenharmony_ci q->firstcache = c; 660d4afb5ceSopenharmony_ci c->incomplete = !q->responded;// != q->asked; 661d4afb5ceSopenharmony_ci 662d4afb5ceSopenharmony_ci /* 663d4afb5ceSopenharmony_ci * Only register the first one into the cache... 664d4afb5ceSopenharmony_ci * Trim the oldest cache entry if necessary 665d4afb5ceSopenharmony_ci */ 666d4afb5ceSopenharmony_ci 667d4afb5ceSopenharmony_ci lws_async_dns_trim_cache(dns); 668d4afb5ceSopenharmony_ci 669d4afb5ceSopenharmony_ci /* 670d4afb5ceSopenharmony_ci * cache the first results object... if a second one comes, 671d4afb5ceSopenharmony_ci * we won't directly register it but will chain it on to this 672d4afb5ceSopenharmony_ci * first one and continue to addinfo ai_next linked list from 673d4afb5ceSopenharmony_ci * the first into the second 674d4afb5ceSopenharmony_ci */ 675d4afb5ceSopenharmony_ci 676d4afb5ceSopenharmony_ci c->flags = adst.flags; 677d4afb5ceSopenharmony_ci lws_dll2_add_head(&c->list, &dns->cached); 678d4afb5ceSopenharmony_ci lws_sul_schedule(q->context, 0, &c->sul, sul_cb_expire, 679d4afb5ceSopenharmony_ci lws_now_usecs() + 680d4afb5ceSopenharmony_ci (adst.smallest_ttl * LWS_US_PER_SEC)); 681d4afb5ceSopenharmony_ci } 682d4afb5ceSopenharmony_ci 683d4afb5ceSopenharmony_ci if (q->responded != q->asked) 684d4afb5ceSopenharmony_ci return; 685d4afb5ceSopenharmony_ci 686d4afb5ceSopenharmony_ci /* 687d4afb5ceSopenharmony_ci * Now we captured everything into the new object, return the 688d4afb5ceSopenharmony_ci * addrinfo results, if any, to all interested wsi, if any... 689d4afb5ceSopenharmony_ci */ 690d4afb5ceSopenharmony_ci 691d4afb5ceSopenharmony_ci c->incomplete = 0; 692d4afb5ceSopenharmony_ci lws_async_dns_complete(q, q->firstcache); 693d4afb5ceSopenharmony_ci 694d4afb5ceSopenharmony_ci q->go_nogo = METRES_GO; 695d4afb5ceSopenharmony_ci 696d4afb5ceSopenharmony_ci /* 697d4afb5ceSopenharmony_ci * the query is completely finished with 698d4afb5ceSopenharmony_ci */ 699d4afb5ceSopenharmony_ci 700d4afb5ceSopenharmony_cifail_out: 701d4afb5ceSopenharmony_ci lws_adns_q_destroy(q); 702d4afb5ceSopenharmony_ci} 703d4afb5ceSopenharmony_ci 704