async-dns-parse.c 17 KB

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