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.

andns_lib.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /**************************************
  2. * AUTHOR: Federico Tomassini *
  3. * Copyright (C) Federico Tomassini *
  4. * Contact effetom@gmail.com *
  5. ***********************************************
  6. ******* BEGIN 3/2006 ********
  7. *************************************************************************
  8. * *
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation; either version 2 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. * This program is distributed in the hope that it will be useful, *
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  17. * GNU General Public License for more details. *
  18. * *
  19. ************************************************************************/
  20. #include "andns_lib.h"
  21. #include "andns_net.h"
  22. #include "log.h"
  23. #include "err_errno.h"
  24. #include "xmalloc.h"
  25. #include <arpa/inet.h>
  26. #include <zlib.h>
  27. int
  28. andns_compress(char *src, int srclen)
  29. {
  30. int res;
  31. uLongf space;
  32. src += ANDNS_HDR_SZ;
  33. srclen -= ANDNS_HDR_SZ;
  34. space = compressBound(srclen);
  35. unsigned char dst[space + ANDNS_HDR_Z];
  36. /* The first four bytes will store
  37. * the uncompressed size */
  38. res = compress2(dst + ANDNS_HDR_Z, &space, (u_char *) src, srclen,
  39. ANDNS_COMPR_LEVEL);
  40. if (res != Z_OK)
  41. err_ret(ERR_ZLIBCP, -1);
  42. if (space >= srclen - ANDNS_HDR_Z) /* We have to consider the four
  43. bytes too */
  44. err_ret(ERR_ZLIBNU, -1); /* This is a
  45. silent return */
  46. res = htonl(srclen);
  47. memcpy(dst, &res, ANDNS_HDR_Z);
  48. memcpy(src, dst, space);
  49. return (int) space;
  50. }
  51. char *
  52. andns_uncompress(char *src, int srclen, int *dstlen)
  53. {
  54. unsigned char *dst;
  55. uLongf space;
  56. int res;
  57. int c_len;
  58. const int hdrsz = ANDNS_HDR_SZ + ANDNS_HDR_Z;
  59. memcpy(&c_len, src + ANDNS_HDR_SZ, ANDNS_HDR_Z);
  60. c_len = ntohl(c_len);
  61. dst = xmalloc(c_len + ANDNS_HDR_SZ);
  62. space = c_len;
  63. res =
  64. uncompress(dst + ANDNS_HDR_SZ, &space, (u_char *) src + hdrsz,
  65. srclen - hdrsz);
  66. if (res != Z_OK) {
  67. xfree(dst);
  68. err_ret(ERR_ZLIBUP, NULL);
  69. }
  70. if ((int) space != c_len) {
  71. xfree(dst);
  72. err_ret(ERR_ANDMAP, NULL);
  73. }
  74. memcpy(dst, src, ANDNS_HDR_SZ);
  75. *dstlen = c_len + ANDNS_HDR_SZ;
  76. return (char *) dst;
  77. }
  78. /*
  79. * Takes the buffer stream and translate headers to
  80. * andns_pkt struct.
  81. * Returns ALWAYS 4. The pkt_len has to be controlled
  82. * elsewhere.
  83. */
  84. int
  85. a_hdr_u(char *buf, andns_pkt * ap)
  86. {
  87. uint8_t c;
  88. uint16_t s;
  89. char *start_buf;
  90. start_buf = buf;
  91. ap->r = *(buf + 1) & 0x01;
  92. memcpy(&s, buf, 2);
  93. ap->id = ntohs(s);
  94. ap->id >>= 1;
  95. buf += 2;
  96. memcpy(&c, buf, sizeof(uint8_t));
  97. ap->qr = (c >> 7) & 0x01;
  98. ap->p = c & 0x40 ? ANDNS_PROTO_UDP : ANDNS_PROTO_TCP;
  99. ap->z = c & 0x20;
  100. ap->qtype = (c >> 3) & 0x03;
  101. ap->ancount = (c << 1) & 0x0e;
  102. buf++;
  103. memcpy(&c, buf, sizeof(uint8_t));
  104. if (((*buf) & 0x80))
  105. ap->ancount++;
  106. ap->ipv = (c >> 6) & 0x01;
  107. ap->nk = (c >> 4) & 0x03;
  108. ap->rcode = c & 0x0f;
  109. return ANDNS_HDR_SZ;
  110. }
  111. /*
  112. * Translate the andns_pkt question stream to andns_pkt struct.
  113. * -1 on error. Bytes readed otherwise.
  114. * NOTE: The qst-data size is controlled: apkt won't need
  115. * this control.
  116. */
  117. int
  118. a_qst_u(char *buf, andns_pkt * ap, int limitlen)
  119. {
  120. int ret;
  121. uint16_t s;
  122. if (limitlen < 3)
  123. err_ret(ERR_ANDMAP, -1);
  124. switch (ap->qtype) {
  125. case AT_A:
  126. memcpy(&s, buf, 2);
  127. ap->service = ntohs(s);
  128. buf += 2;
  129. if (ap->nk == NTK_REALM) {
  130. ap->qstlength = ANDNS_HASH_H;
  131. if (ap->qstlength > limitlen - 2)
  132. err_ret(ERR_ANDPLB, -1);
  133. AP_ALIGN(ap);
  134. memcpy(ap->qstdata, buf, ANDNS_HASH_H);
  135. ret = ANDNS_HASH_H + 2;
  136. } else if (ap->nk == INET_REALM) {
  137. memcpy(&s, buf, 2);
  138. ap->qstlength = ntohs(s);
  139. buf += 2;
  140. if (ap->qstlength >= ANDNS_MAX_QST_LEN ||
  141. ap->qstlength > limitlen - 4)
  142. err_ret(ERR_ANDPLB, -1);
  143. AP_ALIGN(ap);
  144. memcpy(ap->qstdata, buf, ap->qstlength);
  145. ret = ap->qstlength + 4;
  146. } else
  147. return -1;
  148. break;
  149. case AT_PTR:
  150. ap->qstlength = ap->ipv ? 16 : 4;
  151. if (ap->qstlength > limitlen)
  152. err_ret(ERR_ANDMAP, -1)
  153. AP_ALIGN(ap);
  154. memcpy(ap->qstdata, buf, ap->qstlength);
  155. ret = ap->qstlength;
  156. break;
  157. case AT_G:
  158. if (ap->nk != NTK_REALM)
  159. err_ret(ERR_ANDMAP, -1);
  160. ap->qstlength = ANDNS_HASH_H;
  161. if (ap->qstlength > limitlen)
  162. err_ret(ERR_ANDPLB, -1);
  163. AP_ALIGN(ap);
  164. memcpy(ap->qstdata, buf, ANDNS_HASH_H);
  165. ret = ap->qstlength;
  166. break;
  167. default:
  168. debug(DBG_INSANE, "In a_qst_u: unknow query type.");
  169. err_ret(ERR_ANDMAP, -1)
  170. }
  171. return ret;
  172. }
  173. int
  174. a_answ_u(char *buf, andns_pkt * ap, int limitlen)
  175. {
  176. uint16_t alen;
  177. andns_pkt_data *apd;
  178. int limit;
  179. if (limitlen < 3)
  180. err_ret(ERR_ANDMAP, -1);
  181. switch (ap->qtype) {
  182. case AT_A:
  183. limit = 2;
  184. if (limitlen < limit)
  185. err_ret(ERR_ANDPLB, -1);
  186. apd = andns_add_answ(ap);
  187. if (*buf & 0x40) {
  188. apd->m |= APD_IP;
  189. if (*buf & 0x80)
  190. apd->m |= APD_MAIN_IP;
  191. limit = ap->ipv ? 16 : 4;
  192. } else
  193. limit = ANDNS_HASH_H;
  194. if (limitlen < limit + 2)
  195. err_ret(ERR_ANDPLB, -1);
  196. apd->wg = (*buf & 0x3f);
  197. apd->prio = (*(buf + 1));
  198. apd->rdlength = limit;
  199. APD_ALIGN(apd);
  200. memcpy(apd->rdata, buf + 2, limit);
  201. limit += 2;
  202. break;
  203. case AT_PTR:
  204. memcpy(&alen, buf, 2);
  205. alen = ntohs(alen);
  206. if (alen + 2 > limitlen)
  207. err_ret(ERR_ANDPLB, -1);
  208. if (alen > ANDNS_MAX_DATA_LEN)
  209. err_ret(ERR_ANDPLB, -1);
  210. apd = andns_add_answ(ap);
  211. apd->rdlength = alen;
  212. APD_ALIGN(apd);
  213. memcpy(apd->rdata, buf + 2, alen);
  214. limit = alen + 2;
  215. break;
  216. case AT_G:
  217. if (limitlen < 8)
  218. err_ret(ERR_ANDMAP, -1);
  219. apd = andns_add_answ(ap);
  220. if (*buf & 0x40) {
  221. apd->m |= APD_IP;
  222. if (*buf & 0x80)
  223. apd->m |= APD_MAIN_IP;
  224. }
  225. apd->m |= *buf & 0x20 ? APD_UDP : APD_TCP;
  226. apd->wg = (*buf & 0x1f);
  227. apd->prio = (*(buf + 1));
  228. buf += 2;
  229. memcpy(&alen, buf, 2);
  230. apd->service = ntohs(alen);
  231. buf += 2;
  232. if (apd->m & APD_IP)
  233. apd->rdlength = (ap->ipv ? 16 : 4);
  234. else
  235. apd->rdlength = ANDNS_HASH_H;
  236. limit = 4 + apd->rdlength;
  237. if (limitlen < limit)
  238. err_ret(ERR_ANDPLB, -1);
  239. APD_ALIGN(apd);
  240. memcpy(apd->rdata, buf, apd->rdlength);
  241. break;
  242. default:
  243. err_ret(ERR_ANDMAP, -1);
  244. }
  245. return limit;
  246. }
  247. int
  248. a_answs_u(char *buf, andns_pkt * ap, int limitlen)
  249. {
  250. int ancount, i;
  251. int offset = 0, res;
  252. uint16_t alen;
  253. if (ap->qtype == AT_G) {
  254. memcpy(&alen, buf, sizeof(uint16_t));
  255. ap->ancount = ntohs(alen);
  256. offset += 2;
  257. }
  258. ancount = ap->ancount;
  259. for (i = 0; i < ancount; i++) {
  260. res = a_answ_u(buf + offset, ap, limitlen - offset);
  261. if (res == -1) {
  262. error(err_str);
  263. err_ret(ERR_ANDMAD, -1);
  264. }
  265. offset += res;
  266. }
  267. return offset;
  268. }
  269. /*
  270. * This is a main function: takes the pkt-buf and translate
  271. * it in structured data.
  272. * It cares about andns_pkt allocation.
  273. * The apkt is allocate here.
  274. *
  275. * Returns:
  276. * -1 on E_INTRPRT
  277. * 0 if pkt must be discarded.
  278. * Number of bytes readed otherwise
  279. */
  280. int
  281. a_u(char *buf, int pktlen, andns_pkt ** app)
  282. {
  283. andns_pkt *ap;
  284. int offset, res;
  285. int limitlen, u_len;
  286. char *u_buf;
  287. if (pktlen < ANDNS_HDR_SZ)
  288. err_ret(ERR_ANDPLB, 0);
  289. *app = ap = create_andns_pkt();
  290. offset = a_hdr_u(buf, ap);
  291. if (ap->z) { /* Controls the space to read
  292. uncompressed size */
  293. if (pktlen < ANDNS_HDR_SZ + ANDNS_HDR_Z) {
  294. destroy_andns_pkt(ap);
  295. err_ret(ERR_ANDPLB, 0);
  296. }
  297. if (!(u_buf = andns_uncompress(buf, pktlen, &u_len)))
  298. goto andmap;
  299. destroy_andns_pkt(ap);
  300. ANDNS_UNSET_Z(u_buf);
  301. res = a_u(u_buf, u_len, app);
  302. xfree(u_buf);
  303. return res;
  304. }
  305. buf += offset;
  306. limitlen = pktlen - offset;
  307. if ((res = a_qst_u(buf, ap, limitlen)) == -1)
  308. goto andmap;
  309. offset += res;
  310. if (!ap->ancount) /*No answers */
  311. return offset;
  312. buf += res;
  313. limitlen -= res;
  314. if ((res = a_answs_u(buf, ap, limitlen)) == -1)
  315. goto andmap;
  316. offset += res;
  317. if (offset != pktlen)
  318. error
  319. ("In a_u(): pktlen differs from readed contents: ID query %d.",
  320. ap->id);
  321. return offset;
  322. andmap:
  323. destroy_andns_pkt(ap);
  324. error(err_str);
  325. err_ret(ERR_ANDMAP, -1);
  326. }
  327. int
  328. a_hdr_p(andns_pkt * ap, char *buf)
  329. {
  330. uint16_t s;
  331. uint8_t an;
  332. ap->id <<= 1;
  333. s = htons(ap->id);
  334. memcpy(buf, &s, sizeof(uint16_t));
  335. if (ap->r)
  336. *(buf + 1) |= 0x01;
  337. else
  338. *(buf + 1) &= 0xfe;
  339. buf += 2;
  340. if (ap->qr)
  341. (*buf) |= 0x80;
  342. if (ap->p)
  343. (*buf) |= 0x40;
  344. if (ap->z)
  345. (*buf) |= 0x20;
  346. (*buf) |= ((ap->qtype) << 3);
  347. an = ap->ancount;
  348. (*buf++) |= ((an) >> 1);
  349. (*buf) |= ((ap->ancount) << 7);
  350. if (ap->ipv)
  351. *buf |= 0x40;
  352. (*buf) |= ((ap->nk) << 4);
  353. (*buf) |= (ap->rcode);
  354. return ANDNS_HDR_SZ;
  355. }
  356. int
  357. a_qst_p(andns_pkt * ap, char *buf, int limitlen)
  358. {
  359. int ret = 0;
  360. uint16_t s;
  361. int limit;
  362. switch (ap->qtype) {
  363. case AT_A:
  364. limit = ap->nk == NTK_REALM ? ANDNS_HASH_H + 2 : ap->qstlength + 4;
  365. if (limitlen < limit)
  366. err_ret(ERR_ANDMAD, -1);
  367. s = htons(ap->service);
  368. memcpy(buf, &s, 2);
  369. buf += 2; /* here INET and NTK REALM change */
  370. if (ap->nk == NTK_REALM) {
  371. memcpy(buf, ap->qstdata, ANDNS_HASH_H);
  372. ret = ANDNS_HASH_H + 2;
  373. } else if (ap->nk == INET_REALM) {
  374. s = htons(ap->qstlength);
  375. memcpy(buf, &s, 2);
  376. buf += 2;
  377. memcpy(buf, ap->qstdata, ap->qstlength);
  378. ret = ap->qstlength + 4;
  379. } else
  380. err_ret(ERR_ANDMAD, -1);
  381. break;
  382. case AT_PTR:
  383. limit = ap->ipv ? 16 : 4;
  384. if (limitlen < limit)
  385. err_ret(ERR_ANDMAD, -1);
  386. memcpy(buf, ap->qstdata, limit);
  387. ret = limit;
  388. break;
  389. case AT_G:
  390. limit = ANDNS_HASH_H;
  391. if (limitlen < limit)
  392. err_ret(ERR_ANDMAD, -1);
  393. memcpy(buf, ap->qstdata, ANDNS_HASH_H);
  394. ret = ANDNS_HASH_H;
  395. break;
  396. default:
  397. debug(DBG_INSANE, "In a_qst_p: unknow query type.");
  398. err_ret(ERR_ANDMAD, -1);
  399. break;
  400. }
  401. return ret;
  402. }
  403. int
  404. a_answ_p(andns_pkt * ap, andns_pkt_data * apd, char *buf, int limitlen)
  405. {
  406. uint16_t s;
  407. int limit;
  408. int ret;
  409. switch (ap->qtype) {
  410. case AT_A:
  411. limit = ap->ipv ? 16 : 4;
  412. if (limitlen < limit + 2)
  413. err_ret(ERR_ANDPLB, -1);
  414. if (apd->m)
  415. *buf |= 0x80;
  416. *buf++ |= (apd->wg & 0x7f);
  417. *buf++ |= apd->prio;
  418. memcpy(buf, apd->rdata, limit);
  419. ret = limit + 2;
  420. break;
  421. case AT_PTR:
  422. if (limitlen < apd->rdlength + 2)
  423. err_ret(ERR_ANDPLB, -1);
  424. s = htons(apd->rdlength);
  425. memcpy(buf, &s, sizeof(uint16_t));
  426. buf += 2;
  427. memcpy(buf, apd->rdata, apd->rdlength);
  428. ret = apd->rdlength + 2;
  429. break;
  430. case AT_G: /* TODO */
  431. if (limitlen < 4)
  432. err_ret(ERR_ANDPLB, -1);
  433. if (apd->m == 1)
  434. (*buf) |= 0xc0;
  435. else if (apd->m)
  436. (*buf) |= 0x40;
  437. *buf++ |= (apd->wg & 0x3f);
  438. *buf++ |= apd->prio;
  439. s = htons(apd->service);
  440. memcpy(buf, &s, 2);
  441. if (apd->m) {
  442. limit = ap->ipv ? 16 : 4;
  443. if (limitlen < limit + 4)
  444. err_ret(ERR_ANDPLB, -1);
  445. memcpy(buf, apd->rdata, limit);
  446. ret = limit + 4;
  447. } else {
  448. limit = strlen(apd->rdata);
  449. if (limitlen < limit + 6)
  450. err_ret(ERR_ANDPLB, -1);
  451. s = htons(limit);
  452. memcpy(buf, &s, 2);
  453. buf += 2;
  454. memcpy(buf, apd->rdata, limit);
  455. ret = limit + 6;
  456. }
  457. break;
  458. default:
  459. debug(DBG_INSANE, "In a_answ_p(): unknow query type.");
  460. err_ret(ERR_ANDMAD, -1);
  461. break;
  462. }
  463. return ret;
  464. }
  465. int
  466. a_answs_p(andns_pkt * ap, char *buf, int limitlen)
  467. {
  468. andns_pkt_data *apd;
  469. int i;
  470. int offset = 0, res;
  471. uint16_t s;
  472. if (ap->qtype == AT_G) {
  473. if (limitlen < 2)
  474. err_ret(ERR_ANDPLB, -1);
  475. s = htons(ap->ancount);
  476. memcpy(buf, &s, 2);
  477. offset += 2;
  478. }
  479. apd = ap->pkt_answ;
  480. for (i = 0; i < ap->ancount && apd; i++) {
  481. if ((res =
  482. a_answ_p(ap, apd, buf + offset, limitlen - offset)) == -1) {
  483. error(err_str);
  484. err_ret(ERR_ANDMAD, -1);
  485. }
  486. offset += res;
  487. apd = apd->next;
  488. }
  489. return offset;
  490. }
  491. int
  492. a_p(andns_pkt * ap, char *buf)
  493. {
  494. int offset, res;
  495. memset(buf, 0, ANDNS_MAX_SZ);
  496. offset = a_hdr_p(ap, buf);
  497. buf += offset;
  498. if ((res = a_qst_p(ap, buf, ANDNS_MAX_SZ - offset)) == -1)
  499. goto server_fail;
  500. offset += res;
  501. buf += res;
  502. if (ap->ancount) {
  503. if ((res = a_answs_p(ap, buf, ANDNS_MAX_SZ - offset)) == -1)
  504. goto server_fail;
  505. offset += res;
  506. }
  507. destroy_andns_pkt(ap);
  508. /* Compression */
  509. if (offset > ANDNS_COMPR_THRESHOLD) {
  510. res = andns_compress(buf, offset);
  511. if (res == -1)
  512. error(err_str);
  513. else
  514. return res;
  515. }
  516. /* end compression */
  517. return offset;
  518. server_fail:
  519. destroy_andns_pkt(ap);
  520. error(err_str);
  521. err_ret(ERR_ANDMAD, -1);
  522. }
  523. /* MEM */
  524. /* Borning functions */
  525. andns_pkt *
  526. create_andns_pkt(void)
  527. {
  528. andns_pkt *ap;
  529. ap = xmalloc(ANDNS_PKT_SZ);
  530. memset(ap, 0, ANDNS_PKT_SZ);
  531. return ap;
  532. }
  533. andns_pkt_data *
  534. create_andns_pkt_data(void)
  535. {
  536. andns_pkt_data *apd;
  537. apd = xmalloc(ANDNS_PKT_DATA_SZ);
  538. memset(apd, 0, ANDNS_PKT_DATA_SZ);
  539. return apd;
  540. }
  541. andns_pkt_data *
  542. andns_add_answ(andns_pkt * ap)
  543. {
  544. andns_pkt_data *apd, *a;
  545. apd = create_andns_pkt_data();
  546. a = ap->pkt_answ;
  547. if (!a) {
  548. ap->pkt_answ = apd;
  549. return apd;
  550. }
  551. while (a->next)
  552. a = a->next;
  553. a->next = apd;
  554. return apd;
  555. }
  556. /* Death functions */
  557. void
  558. destroy_andns_pkt_data(andns_pkt_data * apd)
  559. {
  560. if (apd->rdata)
  561. xfree(apd->rdata);
  562. xfree(apd);
  563. }
  564. void
  565. andns_del_answ(andns_pkt * ap)
  566. {
  567. andns_pkt_data *apd, *apdt;
  568. apd = ap->pkt_answ;
  569. if (!apd)
  570. return;
  571. apdt = apd->next;
  572. while (apdt) {
  573. apd = apdt;
  574. apdt = apdt->next;
  575. }
  576. apd->next = NULL;
  577. destroy_andns_pkt_data(apdt);
  578. }
  579. void
  580. destroy_andns_pkt_datas(andns_pkt * ap)
  581. {
  582. andns_pkt_data *apd, *apd_t;
  583. apd = ap->pkt_answ;
  584. while (apd) {
  585. apd_t = apd->next;
  586. destroy_andns_pkt_data(apd);
  587. apd = apd_t;
  588. }
  589. }
  590. void
  591. destroy_andns_pkt(andns_pkt * ap)
  592. {
  593. if (ap->qstdata)
  594. xfree(ap->qstdata);
  595. destroy_andns_pkt_datas(ap);
  596. xfree(ap);
  597. }