You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parse.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /* Copyright (c) 2014, Vsevolod Stakhov
  2. * All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. *
  12. * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
  13. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  14. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  15. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  16. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  17. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  18. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  19. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  20. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  21. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  22. */
  23. #include "rdns.h"
  24. #include "dns_private.h"
  25. #include "parse.h"
  26. #include "logger.h"
  27. static uint8_t *
  28. rdns_decompress_label (uint8_t *begin, uint16_t *len, uint16_t max)
  29. {
  30. uint16_t offset = (*len);
  31. if (offset > max) {
  32. return NULL;
  33. }
  34. *len = *(begin + offset);
  35. return begin + offset;
  36. }
  37. #define UNCOMPRESS_DNS_OFFSET(p) (((*(p)) ^ DNS_COMPRESSION_BITS) << 8) + *((p) + 1)
  38. uint8_t *
  39. rdns_request_reply_cmp (struct rdns_request *req, uint8_t *in, int len)
  40. {
  41. uint8_t *p, *c, *l1, *l2;
  42. uint16_t len1, len2;
  43. int decompressed = 0;
  44. struct rdns_resolver *resolver = req->resolver;
  45. /* QR format:
  46. * labels - len:octets
  47. * null label - 0
  48. * class - 2 octets
  49. * type - 2 octets
  50. */
  51. /* In p we would store current position in reply and in c - position in request */
  52. p = in;
  53. c = req->packet + req->pos;
  54. for (;;) {
  55. /* Get current label */
  56. len1 = *p;
  57. len2 = *c;
  58. if (p - in > len) {
  59. rdns_info ("invalid dns reply");
  60. return NULL;
  61. }
  62. /* This may be compressed, so we need to decompress it */
  63. if (len1 & DNS_COMPRESSION_BITS) {
  64. len1 = UNCOMPRESS_DNS_OFFSET(p);
  65. l1 = rdns_decompress_label (in, &len1, len);
  66. if (l1 == NULL) {
  67. return NULL;
  68. }
  69. decompressed ++;
  70. l1 ++;
  71. p += 2;
  72. }
  73. else {
  74. l1 = ++p;
  75. p += len1;
  76. }
  77. if (len2 & DNS_COMPRESSION_BITS) {
  78. len2 = UNCOMPRESS_DNS_OFFSET(c);
  79. l2 = rdns_decompress_label (c, &len2, len);
  80. if (l2 == NULL) {
  81. rdns_info ("invalid DNS pointer, cannot decompress");
  82. return NULL;
  83. }
  84. decompressed ++;
  85. l2 ++;
  86. c += 2;
  87. }
  88. else {
  89. l2 = ++c;
  90. c += len2;
  91. }
  92. if (len1 != len2) {
  93. return NULL;
  94. }
  95. if (len1 == 0) {
  96. break;
  97. }
  98. if (memcmp (l1, l2, len1) != 0) {
  99. return NULL;
  100. }
  101. if (decompressed == 2) {
  102. break;
  103. }
  104. }
  105. /* p now points to the end of QR section */
  106. /* Compare class and type */
  107. if (memcmp (p, c, sizeof (uint16_t) * 2) == 0) {
  108. req->pos = c - req->packet + sizeof (uint16_t) * 2;
  109. return p + sizeof (uint16_t) * 2;
  110. }
  111. return NULL;
  112. }
  113. #define MAX_RECURSION_LEVEL 10
  114. bool
  115. rdns_parse_labels (struct rdns_resolver *resolver,
  116. uint8_t *in, char **target, uint8_t **pos, struct rdns_reply *rep,
  117. int *remain, bool make_name)
  118. {
  119. uint16_t namelen = 0;
  120. uint8_t *p = *pos, *begin = *pos, *l, *t, *end = *pos + *remain, *new_pos = *pos;
  121. uint16_t llen;
  122. int length = *remain, new_remain = *remain;
  123. int ptrs = 0, labels = 0;
  124. bool got_compression = false;
  125. /* First go through labels and calculate name length */
  126. while (p - begin < length) {
  127. if (ptrs > MAX_RECURSION_LEVEL) {
  128. rdns_info ("dns pointers are nested too much");
  129. return false;
  130. }
  131. llen = *p;
  132. if (llen == 0) {
  133. if (!got_compression) {
  134. /* In case of compression we have already decremented the processing position */
  135. new_remain -= sizeof (uint8_t);
  136. new_pos += sizeof (uint8_t);
  137. }
  138. break;
  139. }
  140. else if ((llen & DNS_COMPRESSION_BITS)) {
  141. if (end - p > 1) {
  142. ptrs ++;
  143. llen = UNCOMPRESS_DNS_OFFSET(p);
  144. l = rdns_decompress_label (in, &llen, end - in);
  145. if (l == NULL) {
  146. rdns_info ("invalid DNS pointer");
  147. return false;
  148. }
  149. if (!got_compression) {
  150. /* Our label processing is finished actually */
  151. new_remain -= sizeof (uint16_t);
  152. new_pos += sizeof (uint16_t);
  153. got_compression = true;
  154. }
  155. if (l < in || l > begin + length) {
  156. rdns_info ("invalid pointer in DNS packet");
  157. return false;
  158. }
  159. begin = l;
  160. length = end - begin;
  161. p = l + *l + 1;
  162. namelen += *l;
  163. labels ++;
  164. }
  165. else {
  166. rdns_info ("DNS packet has incomplete compressed label, input length: %d bytes, remain: %d",
  167. *remain, new_remain);
  168. return false;
  169. }
  170. }
  171. else {
  172. namelen += llen;
  173. p += llen + 1;
  174. labels ++;
  175. if (!got_compression) {
  176. new_remain -= llen + 1;
  177. new_pos += llen + 1;
  178. }
  179. }
  180. }
  181. if (!make_name) {
  182. goto end;
  183. }
  184. *target = malloc (namelen + labels + 3);
  185. t = (uint8_t *)*target;
  186. p = *pos;
  187. begin = *pos;
  188. length = *remain;
  189. /* Now copy labels to name */
  190. while (p - begin < length) {
  191. llen = *p;
  192. if (llen == 0) {
  193. break;
  194. }
  195. else if (llen & DNS_COMPRESSION_BITS) {
  196. llen = UNCOMPRESS_DNS_OFFSET(p);
  197. l = rdns_decompress_label (in, &llen, end - in);
  198. if (l == NULL) {
  199. goto end;
  200. }
  201. begin = l;
  202. length = end - begin;
  203. p = l + *l + 1;
  204. memcpy (t, l + 1, *l);
  205. t += *l;
  206. *t ++ = '.';
  207. }
  208. else {
  209. memcpy (t, p + 1, *p);
  210. t += *p;
  211. *t ++ = '.';
  212. p += *p + 1;
  213. }
  214. }
  215. if (t > (uint8_t *)*target) {
  216. *(t - 1) = '\0';
  217. }
  218. else {
  219. /* Handle empty labels */
  220. **target = '\0';
  221. }
  222. end:
  223. *remain = new_remain;
  224. *pos = new_pos;
  225. return true;
  226. }
  227. #define GET8(x) do {(x) = ((*p)); p += sizeof (uint8_t); *remain -= sizeof (uint8_t); } while(0)
  228. #define GET16(x) do {(x) = ((*p) << 8) + *(p + 1); p += sizeof (uint16_t); *remain -= sizeof (uint16_t); } while(0)
  229. #define GET32(x) do {(x) = ((*p) << 24) + ((*(p + 1)) << 16) + ((*(p + 2)) << 8) + *(p + 3); p += sizeof (uint32_t); *remain -= sizeof (uint32_t); } while(0)
  230. #define SKIP(type) do { p += sizeof(type); *remain -= sizeof(type); } while (0)
  231. int
  232. rdns_parse_rr (struct rdns_resolver *resolver,
  233. uint8_t *in, struct rdns_reply_entry *elt, uint8_t **pos,
  234. struct rdns_reply *rep, int *remain)
  235. {
  236. uint8_t *p = *pos, parts;
  237. uint16_t type, datalen, txtlen, copied;
  238. int32_t ttl;
  239. bool parsed = false;
  240. /* Skip the whole name */
  241. if (!rdns_parse_labels (resolver, in, NULL, &p, rep, remain, false)) {
  242. rdns_info ("bad RR name");
  243. return -1;
  244. }
  245. if (*remain < (int)sizeof (uint16_t) * 6) {
  246. rdns_info ("stripped dns reply: %d bytes remain; domain %s", *remain,
  247. rep->requested_name);
  248. return -1;
  249. }
  250. GET16 (type);
  251. /* Skip class */
  252. SKIP (uint16_t);
  253. GET32 (ttl);
  254. GET16 (datalen);
  255. elt->type = type;
  256. /* Now p points to RR data */
  257. switch (type) {
  258. case DNS_T_A:
  259. if (!(datalen & 0x3) && datalen <= *remain) {
  260. memcpy (&elt->content.a.addr, p, sizeof (struct in_addr));
  261. p += datalen;
  262. *remain -= datalen;
  263. parsed = true;
  264. }
  265. else {
  266. rdns_info ("corrupted A record; domain: %s", rep->requested_name);
  267. return -1;
  268. }
  269. break;
  270. case DNS_T_AAAA:
  271. if (datalen == sizeof (struct in6_addr) && datalen <= *remain) {
  272. memcpy (&elt->content.aaa.addr, p, sizeof (struct in6_addr));
  273. p += datalen;
  274. *remain -= datalen;
  275. parsed = true;
  276. }
  277. else {
  278. rdns_info ("corrupted AAAA record; domain %s", rep->requested_name);
  279. return -1;
  280. }
  281. break;
  282. case DNS_T_PTR:
  283. if (! rdns_parse_labels (resolver, in, &elt->content.ptr.name, &p,
  284. rep, remain, true)) {
  285. rdns_info ("invalid labels in PTR record; domain %s", rep->requested_name);
  286. return -1;
  287. }
  288. parsed = true;
  289. break;
  290. case DNS_T_NS:
  291. if (! rdns_parse_labels (resolver, in, &elt->content.ns.name, &p,
  292. rep, remain, true)) {
  293. rdns_info ("invalid labels in NS record; domain %s", rep->requested_name);
  294. return -1;
  295. }
  296. parsed = true;
  297. break;
  298. case DNS_T_SOA:
  299. if (! rdns_parse_labels (resolver, in, &elt->content.soa.mname, &p,
  300. rep, remain, true)) {
  301. rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name);
  302. return -1;
  303. }
  304. if (! rdns_parse_labels (resolver, in, &elt->content.soa.admin, &p,
  305. rep, remain, true)) {
  306. rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name);
  307. return -1;
  308. }
  309. if (*remain >= sizeof(int32_t) * 5) {
  310. GET32 (elt->content.soa.serial);
  311. GET32 (elt->content.soa.refresh);
  312. GET32 (elt->content.soa.retry);
  313. GET32 (elt->content.soa.expire);
  314. GET32 (elt->content.soa.minimum);
  315. }
  316. else {
  317. rdns_info ("invalid data in SOA record; domain %s", rep->requested_name);
  318. return -1;
  319. }
  320. parsed = true;
  321. break;
  322. case DNS_T_MX:
  323. GET16 (elt->content.mx.priority);
  324. if (! rdns_parse_labels (resolver, in, &elt->content.mx.name, &p,
  325. rep, remain, true)) {
  326. rdns_info ("invalid labels in MX record; domain %s", rep->requested_name);
  327. return -1;
  328. }
  329. parsed = true;
  330. break;
  331. case DNS_T_TXT:
  332. case DNS_T_SPF:
  333. if (datalen <= *remain) {
  334. elt->content.txt.data = malloc(datalen + 1);
  335. if (elt->content.txt.data == NULL) {
  336. rdns_err ("failed to allocate %d bytes for TXT record; domain %s",
  337. (int) datalen + 1, rep->requested_name);
  338. return -1;
  339. }
  340. /* Now we should compose data from parts */
  341. copied = 0;
  342. parts = 0;
  343. while (copied + parts < datalen && *remain > 0) {
  344. txtlen = *p;
  345. if (txtlen + copied + parts <= datalen && *remain >= txtlen + 1) {
  346. parts++;
  347. memcpy (elt->content.txt.data + copied, p + 1, txtlen);
  348. copied += txtlen;
  349. p += txtlen + 1;
  350. *remain -= txtlen + 1;
  351. }
  352. else {
  353. if (txtlen + copied + parts > datalen) {
  354. /* Incorrect datalen reported ! */
  355. rdns_err ("incorrect txtlen (%d) > datalen (%d) reported; domain %s",
  356. (txtlen + copied + parts), datalen,
  357. rep->requested_name);
  358. return -1;
  359. }
  360. /* Reported equal to the actual data copied */
  361. break;
  362. }
  363. }
  364. *(elt->content.txt.data + copied) = '\0';
  365. parsed = true;
  366. elt->type = RDNS_REQUEST_TXT;
  367. }
  368. else {
  369. rdns_info ("stripped data in TXT record (%d bytes available, %d requested); "
  370. "domain %s", (int)*remain, (int)datalen, rep->requested_name);
  371. return -1;
  372. }
  373. break;
  374. case DNS_T_SRV:
  375. if (p - *pos > (int)(*remain - sizeof (uint16_t) * 3)) {
  376. rdns_info ("stripped dns reply while reading SRV record; domain %s", rep->requested_name);
  377. return -1;
  378. }
  379. GET16 (elt->content.srv.priority);
  380. GET16 (elt->content.srv.weight);
  381. GET16 (elt->content.srv.port);
  382. if (! rdns_parse_labels (resolver, in, &elt->content.srv.target,
  383. &p, rep, remain, true)) {
  384. rdns_info ("invalid labels in SRV record; domain %s", rep->requested_name);
  385. return -1;
  386. }
  387. parsed = true;
  388. break;
  389. case DNS_T_TLSA:
  390. if (p - *pos > (int)(*remain - sizeof (uint8_t) * 3) || datalen <= 3) {
  391. rdns_info ("stripped dns reply while reading TLSA record; domain %s", rep->requested_name);
  392. return -1;
  393. }
  394. if (datalen > *remain) {
  395. rdns_info ("too large datalen; domain %s", rep->requested_name);
  396. return -1;
  397. }
  398. GET8 (elt->content.tlsa.usage);
  399. GET8 (elt->content.tlsa.selector);
  400. GET8 (elt->content.tlsa.match_type);
  401. datalen -= 3;
  402. elt->content.tlsa.data = malloc (datalen);
  403. if (elt->content.tlsa.data == NULL) {
  404. rdns_err ("failed to allocate %d bytes for TLSA record; domain %s",
  405. (int)datalen + 1, rep->requested_name);
  406. return -1;
  407. }
  408. elt->content.tlsa.datalen = datalen;
  409. memcpy (elt->content.tlsa.data, p, datalen);
  410. p += datalen;
  411. *remain -= datalen;
  412. parsed = true;
  413. break;
  414. case DNS_T_CNAME:
  415. if (! rdns_parse_labels (resolver, in, &elt->content.cname.name, &p,
  416. rep, remain, true)) {
  417. rdns_info ("invalid labels in CNAME record; domain %s", rep->requested_name);
  418. return -1;
  419. }
  420. parsed = true;
  421. break;
  422. default:
  423. rdns_info ("unexpected RR type: %d; domain %s", type, rep->requested_name);
  424. p += datalen;
  425. *remain -= datalen;
  426. break;
  427. }
  428. *pos = p;
  429. if (parsed) {
  430. elt->ttl = ttl;
  431. return 1;
  432. }
  433. return 0;
  434. }