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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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. ap->r = *(buf + 1) & 0x01;
  90. memcpy(&s, buf, 2);
  91. ap->id = ntohs(s);
  92. ap->id >>= 1;
  93. buf += 2;
  94. memcpy(&c, buf, sizeof(uint8_t));
  95. ap->qr = (c >> 7) & 0x01;
  96. ap->p = c & 0x40 ? ANDNS_PROTO_UDP : ANDNS_PROTO_TCP;
  97. ap->z = c & 0x20;
  98. ap->qtype = (c >> 3) & 0x03;
  99. ap->ancount = (c << 1) & 0x0e;
  100. buf++;
  101. memcpy(&c, buf, sizeof(uint8_t));
  102. if (((*buf) & 0x80))
  103. ap->ancount++;
  104. ap->ipv = (c >> 6) & 0x01;
  105. ap->nk = (c >> 4) & 0x03;
  106. ap->rcode = c & 0x0f;
  107. return ANDNS_HDR_SZ;
  108. }
  109. /*
  110. * Translate the andns_pkt question stream to andns_pkt struct.
  111. * -1 on error. Bytes readed otherwise.
  112. * NOTE: The qst-data size is controlled: apkt won't need
  113. * this control.
  114. */
  115. int
  116. a_qst_u(char *buf, andns_pkt * ap, int limitlen)
  117. {
  118. int ret;
  119. uint16_t s;
  120. if (limitlen < 3)
  121. err_ret(ERR_ANDMAP, -1);
  122. switch (ap->qtype) {
  123. case AT_A:
  124. memcpy(&s, buf, 2);
  125. ap->service = ntohs(s);
  126. buf += 2;
  127. if (ap->nk == NTK_REALM) {
  128. ap->qstlength = ANDNS_HASH_H;
  129. if (ap->qstlength > limitlen - 2)
  130. err_ret(ERR_ANDPLB, -1);
  131. AP_ALIGN(ap);
  132. memcpy(ap->qstdata, buf, ANDNS_HASH_H);
  133. ret = ANDNS_HASH_H + 2;
  134. } else if (ap->nk == INET_REALM) {
  135. memcpy(&s, buf, 2);
  136. ap->qstlength = ntohs(s);
  137. buf += 2;
  138. if (ap->qstlength >= ANDNS_MAX_QST_LEN ||
  139. ap->qstlength > limitlen - 4)
  140. err_ret(ERR_ANDPLB, -1);
  141. AP_ALIGN(ap);
  142. memcpy(ap->qstdata, buf, ap->qstlength);
  143. ret = ap->qstlength + 4;
  144. } else
  145. return -1;
  146. break;
  147. case AT_PTR:
  148. ap->qstlength = ap->ipv ? 16 : 4;
  149. if (ap->qstlength > limitlen)
  150. err_ret(ERR_ANDMAP, -1)
  151. AP_ALIGN(ap);
  152. memcpy(ap->qstdata, buf, ap->qstlength);
  153. ret = ap->qstlength;
  154. break;
  155. case AT_G:
  156. if (ap->nk != NTK_REALM)
  157. err_ret(ERR_ANDMAP, -1);
  158. ap->qstlength = ANDNS_HASH_H;
  159. if (ap->qstlength > limitlen)
  160. err_ret(ERR_ANDPLB, -1);
  161. AP_ALIGN(ap);
  162. memcpy(ap->qstdata, buf, ANDNS_HASH_H);
  163. ret = ap->qstlength;
  164. break;
  165. default:
  166. debug(DBG_INSANE, "In a_qst_u: unknow query type.");
  167. err_ret(ERR_ANDMAP, -1)
  168. }
  169. return ret;
  170. }
  171. int
  172. a_answ_u(char *buf, andns_pkt * ap, int limitlen)
  173. {
  174. uint16_t alen;
  175. andns_pkt_data *apd;
  176. int limit;
  177. if (limitlen < 3)
  178. err_ret(ERR_ANDMAP, -1);
  179. switch (ap->qtype) {
  180. case AT_A:
  181. limit = 2;
  182. if (limitlen < limit)
  183. err_ret(ERR_ANDPLB, -1);
  184. apd = andns_add_answ(ap);
  185. if (*buf & 0x40) {
  186. apd->m |= APD_IP;
  187. if (*buf & 0x80)
  188. apd->m |= APD_MAIN_IP;
  189. limit = ap->ipv ? 16 : 4;
  190. } else
  191. limit = ANDNS_HASH_H;
  192. if (limitlen < limit + 2)
  193. err_ret(ERR_ANDPLB, -1);
  194. apd->wg = (*buf & 0x3f);
  195. apd->prio = (*(buf + 1));
  196. apd->rdlength = limit;
  197. APD_ALIGN(apd);
  198. memcpy(apd->rdata, buf + 2, limit);
  199. limit += 2;
  200. break;
  201. case AT_PTR:
  202. memcpy(&alen, buf, 2);
  203. alen = ntohs(alen);
  204. if (alen + 2 > limitlen)
  205. err_ret(ERR_ANDPLB, -1);
  206. if (alen > ANDNS_MAX_DATA_LEN)
  207. err_ret(ERR_ANDPLB, -1);
  208. apd = andns_add_answ(ap);
  209. apd->rdlength = alen;
  210. APD_ALIGN(apd);
  211. memcpy(apd->rdata, buf + 2, alen);
  212. limit = alen + 2;
  213. break;
  214. case AT_G:
  215. if (limitlen < 8)
  216. err_ret(ERR_ANDMAP, -1);
  217. apd = andns_add_answ(ap);
  218. if (*buf & 0x40) {
  219. apd->m |= APD_IP;
  220. if (*buf & 0x80)
  221. apd->m |= APD_MAIN_IP;
  222. }
  223. apd->m |= *buf & 0x20 ? APD_UDP : APD_TCP;
  224. apd->wg = (*buf & 0x1f);
  225. apd->prio = (*(buf + 1));
  226. buf += 2;
  227. memcpy(&alen, buf, 2);
  228. apd->service = ntohs(alen);
  229. buf += 2;
  230. if (apd->m & APD_IP)
  231. apd->rdlength = (ap->ipv ? 16 : 4);
  232. else
  233. apd->rdlength = ANDNS_HASH_H;
  234. limit = 4 + apd->rdlength;
  235. if (limitlen < limit)
  236. err_ret(ERR_ANDPLB, -1);
  237. APD_ALIGN(apd);
  238. memcpy(apd->rdata, buf, apd->rdlength);
  239. break;
  240. default:
  241. err_ret(ERR_ANDMAP, -1);
  242. }
  243. return limit;
  244. }
  245. int
  246. a_answs_u(char *buf, andns_pkt * ap, int limitlen)
  247. {
  248. int ancount, i;
  249. int offset = 0, res;
  250. uint16_t alen;
  251. if (ap->qtype == AT_G) {
  252. memcpy(&alen, buf, sizeof(uint16_t));
  253. ap->ancount = ntohs(alen);
  254. offset += 2;
  255. }
  256. ancount = ap->ancount;
  257. for (i = 0; i < ancount; i++) {
  258. res = a_answ_u(buf + offset, ap, limitlen - offset);
  259. if (res == -1) {
  260. error(err_str);
  261. err_ret(ERR_ANDMAD, -1);
  262. }
  263. offset += res;
  264. }
  265. return offset;
  266. }
  267. /*
  268. * This is a main function: takes the pkt-buf and translate
  269. * it in structured data.
  270. * It cares about andns_pkt allocation.
  271. * The apkt is allocate here.
  272. *
  273. * Returns:
  274. * -1 on E_INTRPRT
  275. * 0 if pkt must be discarded.
  276. * Number of bytes readed otherwise
  277. */
  278. int
  279. a_u(char *buf, int pktlen, andns_pkt ** app)
  280. {
  281. andns_pkt *ap;
  282. int offset, res;
  283. int limitlen, u_len;
  284. char *u_buf;
  285. if (pktlen < ANDNS_HDR_SZ)
  286. err_ret(ERR_ANDPLB, 0);
  287. *app = ap = create_andns_pkt();
  288. offset = a_hdr_u(buf, ap);
  289. if (ap->z) { /* Controls the space to read
  290. uncompressed size */
  291. if (pktlen < ANDNS_HDR_SZ + ANDNS_HDR_Z) {
  292. destroy_andns_pkt(ap);
  293. err_ret(ERR_ANDPLB, 0);
  294. }
  295. if (!(u_buf = andns_uncompress(buf, pktlen, &u_len)))
  296. goto andmap;
  297. destroy_andns_pkt(ap);
  298. ANDNS_UNSET_Z(u_buf);
  299. res = a_u(u_buf, u_len, app);
  300. xfree(u_buf);
  301. return res;
  302. }
  303. buf += offset;
  304. limitlen = pktlen - offset;
  305. if ((res = a_qst_u(buf, ap, limitlen)) == -1)
  306. goto andmap;
  307. offset += res;
  308. if (!ap->ancount) /*No answers */
  309. return offset;
  310. buf += res;
  311. limitlen -= res;
  312. if ((res = a_answs_u(buf, ap, limitlen)) == -1)
  313. goto andmap;
  314. offset += res;
  315. if (offset != pktlen)
  316. error
  317. ("In a_u(): pktlen differs from readed contents: ID query %d.",
  318. ap->id);
  319. return offset;
  320. andmap:
  321. destroy_andns_pkt(ap);
  322. error(err_str);
  323. err_ret(ERR_ANDMAP, -1);
  324. }
  325. int
  326. a_hdr_p(andns_pkt * ap, char *buf)
  327. {
  328. uint16_t s;
  329. uint8_t an;
  330. ap->id <<= 1;
  331. s = htons(ap->id);
  332. memcpy(buf, &s, sizeof(uint16_t));
  333. if (ap->r)
  334. *(buf + 1) |= 0x01;
  335. else
  336. *(buf + 1) &= 0xfe;
  337. buf += 2;
  338. if (ap->qr)
  339. (*buf) |= 0x80;
  340. if (ap->p)
  341. (*buf) |= 0x40;
  342. if (ap->z)
  343. (*buf) |= 0x20;
  344. (*buf) |= ((ap->qtype) << 3);
  345. an = ap->ancount;
  346. (*buf++) |= ((an) >> 1);
  347. (*buf) |= ((ap->ancount) << 7);
  348. if (ap->ipv)
  349. *buf |= 0x40;
  350. (*buf) |= ((ap->nk) << 4);
  351. (*buf) |= (ap->rcode);
  352. return ANDNS_HDR_SZ;
  353. }
  354. int
  355. a_qst_p(andns_pkt * ap, char *buf, int limitlen)
  356. {
  357. int ret = 0;
  358. uint16_t s;
  359. int limit;
  360. switch (ap->qtype) {
  361. case AT_A:
  362. limit = ap->nk == NTK_REALM ? ANDNS_HASH_H + 2 : ap->qstlength + 4;
  363. if (limitlen < limit)
  364. err_ret(ERR_ANDMAD, -1);
  365. s = htons(ap->service);
  366. memcpy(buf, &s, 2);
  367. buf += 2; /* here INET and NTK REALM change */
  368. if (ap->nk == NTK_REALM) {
  369. memcpy(buf, ap->qstdata, ANDNS_HASH_H);
  370. ret = ANDNS_HASH_H + 2;
  371. } else if (ap->nk == INET_REALM) {
  372. s = htons(ap->qstlength);
  373. memcpy(buf, &s, 2);
  374. buf += 2;
  375. memcpy(buf, ap->qstdata, ap->qstlength);
  376. ret = ap->qstlength + 4;
  377. } else
  378. err_ret(ERR_ANDMAD, -1);
  379. break;
  380. case AT_PTR:
  381. limit = ap->ipv ? 16 : 4;
  382. if (limitlen < limit)
  383. err_ret(ERR_ANDMAD, -1);
  384. memcpy(buf, ap->qstdata, limit);
  385. ret = limit;
  386. break;
  387. case AT_G:
  388. limit = ANDNS_HASH_H;
  389. if (limitlen < limit)
  390. err_ret(ERR_ANDMAD, -1);
  391. memcpy(buf, ap->qstdata, ANDNS_HASH_H);
  392. ret = ANDNS_HASH_H;
  393. break;
  394. default:
  395. debug(DBG_INSANE, "In a_qst_p: unknow query type.");
  396. err_ret(ERR_ANDMAD, -1);
  397. break;
  398. }
  399. return ret;
  400. }
  401. int
  402. a_answ_p(andns_pkt * ap, andns_pkt_data * apd, char *buf, int limitlen)
  403. {
  404. uint16_t s;
  405. int limit;
  406. int ret;
  407. switch (ap->qtype) {
  408. case AT_A:
  409. limit = ap->ipv ? 16 : 4;
  410. if (limitlen < limit + 2)
  411. err_ret(ERR_ANDPLB, -1);
  412. if (apd->m)
  413. *buf |= 0x80;
  414. *buf++ |= (apd->wg & 0x7f);
  415. *buf++ |= apd->prio;
  416. memcpy(buf, apd->rdata, limit);
  417. ret = limit + 2;
  418. break;
  419. case AT_PTR:
  420. if (limitlen < apd->rdlength + 2)
  421. err_ret(ERR_ANDPLB, -1);
  422. s = htons(apd->rdlength);
  423. memcpy(buf, &s, sizeof(uint16_t));
  424. buf += 2;
  425. memcpy(buf, apd->rdata, apd->rdlength);
  426. ret = apd->rdlength + 2;
  427. break;
  428. case AT_G: /* TODO */
  429. if (limitlen < 4)
  430. err_ret(ERR_ANDPLB, -1);
  431. if (apd->m == 1)
  432. (*buf) |= 0xc0;
  433. else if (apd->m)
  434. (*buf) |= 0x40;
  435. *buf++ |= (apd->wg & 0x3f);
  436. *buf++ |= apd->prio;
  437. s = htons(apd->service);
  438. memcpy(buf, &s, 2);
  439. if (apd->m) {
  440. limit = ap->ipv ? 16 : 4;
  441. if (limitlen < limit + 4)
  442. err_ret(ERR_ANDPLB, -1);
  443. memcpy(buf, apd->rdata, limit);
  444. ret = limit + 4;
  445. } else {
  446. limit = strlen(apd->rdata);
  447. if (limitlen < limit + 6)
  448. err_ret(ERR_ANDPLB, -1);
  449. s = htons(limit);
  450. memcpy(buf, &s, 2);
  451. buf += 2;
  452. memcpy(buf, apd->rdata, limit);
  453. ret = limit + 6;
  454. }
  455. break;
  456. default:
  457. debug(DBG_INSANE, "In a_answ_p(): unknow query type.");
  458. err_ret(ERR_ANDMAD, -1);
  459. break;
  460. }
  461. return ret;
  462. }
  463. int
  464. a_answs_p(andns_pkt * ap, char *buf, int limitlen)
  465. {
  466. andns_pkt_data *apd;
  467. int i;
  468. int offset = 0, res;
  469. uint16_t s;
  470. if (ap->qtype == AT_G) {
  471. if (limitlen < 2)
  472. err_ret(ERR_ANDPLB, -1);
  473. s = htons(ap->ancount);
  474. memcpy(buf, &s, 2);
  475. offset += 2;
  476. }
  477. apd = ap->pkt_answ;
  478. for (i = 0; i < ap->ancount && apd; i++) {
  479. if ((res =
  480. a_answ_p(ap, apd, buf + offset, limitlen - offset)) == -1) {
  481. error(err_str);
  482. err_ret(ERR_ANDMAD, -1);
  483. }
  484. offset += res;
  485. apd = apd->next;
  486. }
  487. return offset;
  488. }
  489. int
  490. a_p(andns_pkt * ap, char *buf)
  491. {
  492. int offset, res;
  493. memset(buf, 0, ANDNS_MAX_SZ);
  494. offset = a_hdr_p(ap, buf);
  495. buf += offset;
  496. if ((res = a_qst_p(ap, buf, ANDNS_MAX_SZ - offset)) == -1)
  497. goto server_fail;
  498. offset += res;
  499. buf += res;
  500. if (ap->ancount) {
  501. if ((res = a_answs_p(ap, buf, ANDNS_MAX_SZ - offset)) == -1)
  502. goto server_fail;
  503. offset += res;
  504. }
  505. destroy_andns_pkt(ap);
  506. /* Compression */
  507. if (offset > ANDNS_COMPR_THRESHOLD) {
  508. res = andns_compress(buf, offset);
  509. if (res == -1)
  510. error(err_str);
  511. else
  512. return res;
  513. }
  514. /* end compression */
  515. return offset;
  516. server_fail:
  517. destroy_andns_pkt(ap);
  518. error(err_str);
  519. err_ret(ERR_ANDMAD, -1);
  520. }
  521. /* MEM */
  522. /* Borning functions */
  523. andns_pkt *
  524. create_andns_pkt(void)
  525. {
  526. andns_pkt *ap;
  527. ap = xmalloc(ANDNS_PKT_SZ);
  528. memset(ap, 0, ANDNS_PKT_SZ);
  529. return ap;
  530. }
  531. andns_pkt_data *
  532. create_andns_pkt_data(void)
  533. {
  534. andns_pkt_data *apd;
  535. apd = xmalloc(ANDNS_PKT_DATA_SZ);
  536. memset(apd, 0, ANDNS_PKT_DATA_SZ);
  537. return apd;
  538. }
  539. andns_pkt_data *
  540. andns_add_answ(andns_pkt * ap)
  541. {
  542. andns_pkt_data *apd, *a;
  543. apd = create_andns_pkt_data();
  544. a = ap->pkt_answ;
  545. if (!a) {
  546. ap->pkt_answ = apd;
  547. return apd;
  548. }
  549. while (a->next)
  550. a = a->next;
  551. a->next = apd;
  552. return apd;
  553. }
  554. /* Death functions */
  555. void
  556. destroy_andns_pkt_data(andns_pkt_data * apd)
  557. {
  558. if (apd->rdata)
  559. xfree(apd->rdata);
  560. xfree(apd);
  561. }
  562. void
  563. andns_del_answ(andns_pkt * ap)
  564. {
  565. andns_pkt_data *apd, *apdt;
  566. apd = ap->pkt_answ;
  567. if (!apd)
  568. return;
  569. apdt = apd->next;
  570. while (apdt) {
  571. apd = apdt;
  572. apdt = apdt->next;
  573. }
  574. apd->next = NULL;
  575. destroy_andns_pkt_data(apdt);
  576. }
  577. void
  578. destroy_andns_pkt_datas(andns_pkt * ap)
  579. {
  580. andns_pkt_data *apd, *apd_t;
  581. apd = ap->pkt_answ;
  582. while (apd) {
  583. apd_t = apd->next;
  584. destroy_andns_pkt_data(apd);
  585. apd = apd_t;
  586. }
  587. }
  588. void
  589. destroy_andns_pkt(andns_pkt * ap)
  590. {
  591. if (ap->qstdata)
  592. xfree(ap->qstdata);
  593. destroy_andns_pkt_datas(ap);
  594. xfree(ap);
  595. }