/contrib/bind9/lib/dns/compress.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 341 lines · 240 code · 60 blank · 41 comment · 43 complexity · 0968bdaaa757f30faed0787ebfb87b70 MD5 · raw file

  1. /*
  2. * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
  3. * Copyright (C) 1999-2001 Internet Software Consortium.
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  10. * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  11. * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  12. * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  13. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  14. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  15. * PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* $Id: compress.c,v 1.59 2007/06/19 23:47:16 tbox Exp $ */
  18. /*! \file */
  19. #define DNS_NAME_USEINLINE 1
  20. #include <config.h>
  21. #include <isc/mem.h>
  22. #include <isc/string.h>
  23. #include <isc/util.h>
  24. #include <dns/compress.h>
  25. #include <dns/fixedname.h>
  26. #include <dns/rbt.h>
  27. #include <dns/result.h>
  28. #define CCTX_MAGIC ISC_MAGIC('C', 'C', 'T', 'X')
  29. #define VALID_CCTX(x) ISC_MAGIC_VALID(x, CCTX_MAGIC)
  30. #define DCTX_MAGIC ISC_MAGIC('D', 'C', 'T', 'X')
  31. #define VALID_DCTX(x) ISC_MAGIC_VALID(x, DCTX_MAGIC)
  32. /***
  33. *** Compression
  34. ***/
  35. isc_result_t
  36. dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx) {
  37. unsigned int i;
  38. REQUIRE(cctx != NULL);
  39. REQUIRE(mctx != NULL); /* See: rdataset.c:towiresorted(). */
  40. cctx->allowed = 0;
  41. cctx->edns = edns;
  42. for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++)
  43. cctx->table[i] = NULL;
  44. cctx->mctx = mctx;
  45. cctx->count = 0;
  46. cctx->magic = CCTX_MAGIC;
  47. return (ISC_R_SUCCESS);
  48. }
  49. void
  50. dns_compress_invalidate(dns_compress_t *cctx) {
  51. dns_compressnode_t *node;
  52. unsigned int i;
  53. REQUIRE(VALID_CCTX(cctx));
  54. cctx->magic = 0;
  55. for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
  56. while (cctx->table[i] != NULL) {
  57. node = cctx->table[i];
  58. cctx->table[i] = cctx->table[i]->next;
  59. if (node->count < DNS_COMPRESS_INITIALNODES)
  60. continue;
  61. isc_mem_put(cctx->mctx, node, sizeof(*node));
  62. }
  63. }
  64. cctx->allowed = 0;
  65. cctx->edns = -1;
  66. }
  67. void
  68. dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed) {
  69. REQUIRE(VALID_CCTX(cctx));
  70. cctx->allowed &= ~DNS_COMPRESS_ALL;
  71. cctx->allowed |= (allowed & DNS_COMPRESS_ALL);
  72. }
  73. unsigned int
  74. dns_compress_getmethods(dns_compress_t *cctx) {
  75. REQUIRE(VALID_CCTX(cctx));
  76. return (cctx->allowed & DNS_COMPRESS_ALL);
  77. }
  78. void
  79. dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive) {
  80. REQUIRE(VALID_CCTX(cctx));
  81. if (sensitive)
  82. cctx->allowed |= DNS_COMPRESS_CASESENSITIVE;
  83. else
  84. cctx->allowed &= ~DNS_COMPRESS_CASESENSITIVE;
  85. }
  86. isc_boolean_t
  87. dns_compress_getsensitive(dns_compress_t *cctx) {
  88. REQUIRE(VALID_CCTX(cctx));
  89. return (ISC_TF((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0));
  90. }
  91. int
  92. dns_compress_getedns(dns_compress_t *cctx) {
  93. REQUIRE(VALID_CCTX(cctx));
  94. return (cctx->edns);
  95. }
  96. #define NODENAME(node, name) \
  97. do { \
  98. (name)->length = (node)->r.length; \
  99. (name)->labels = (node)->labels; \
  100. (name)->ndata = (node)->r.base; \
  101. (name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
  102. } while (0)
  103. /*
  104. * Find the longest match of name in the table.
  105. * If match is found return ISC_TRUE. prefix, suffix and offset are updated.
  106. * If no match is found return ISC_FALSE.
  107. */
  108. isc_boolean_t
  109. dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
  110. dns_name_t *prefix, isc_uint16_t *offset)
  111. {
  112. dns_name_t tname, nname;
  113. dns_compressnode_t *node = NULL;
  114. unsigned int labels, hash, n;
  115. REQUIRE(VALID_CCTX(cctx));
  116. REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
  117. REQUIRE(offset != NULL);
  118. if (cctx->count == 0)
  119. return (ISC_FALSE);
  120. labels = dns_name_countlabels(name);
  121. INSIST(labels > 0);
  122. dns_name_init(&tname, NULL);
  123. dns_name_init(&nname, NULL);
  124. for (n = 0; n < labels - 1; n++) {
  125. dns_name_getlabelsequence(name, n, labels - n, &tname);
  126. hash = dns_name_hash(&tname, ISC_FALSE) %
  127. DNS_COMPRESS_TABLESIZE;
  128. for (node = cctx->table[hash]; node != NULL; node = node->next)
  129. {
  130. NODENAME(node, &nname);
  131. if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
  132. if (dns_name_caseequal(&nname, &tname))
  133. break;
  134. } else {
  135. if (dns_name_equal(&nname, &tname))
  136. break;
  137. }
  138. }
  139. if (node != NULL)
  140. break;
  141. }
  142. /*
  143. * If node == NULL, we found no match at all.
  144. */
  145. if (node == NULL)
  146. return (ISC_FALSE);
  147. if (n == 0)
  148. dns_name_reset(prefix);
  149. else
  150. dns_name_getlabelsequence(name, 0, n, prefix);
  151. *offset = node->offset;
  152. return (ISC_TRUE);
  153. }
  154. static inline unsigned int
  155. name_length(const dns_name_t *name) {
  156. isc_region_t r;
  157. dns_name_toregion(name, &r);
  158. return (r.length);
  159. }
  160. void
  161. dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
  162. const dns_name_t *prefix, isc_uint16_t offset)
  163. {
  164. dns_name_t tname;
  165. unsigned int start;
  166. unsigned int n;
  167. unsigned int count;
  168. unsigned int hash;
  169. dns_compressnode_t *node;
  170. unsigned int length;
  171. unsigned int tlength;
  172. isc_uint16_t toffset;
  173. REQUIRE(VALID_CCTX(cctx));
  174. REQUIRE(dns_name_isabsolute(name));
  175. dns_name_init(&tname, NULL);
  176. n = dns_name_countlabels(name);
  177. count = dns_name_countlabels(prefix);
  178. if (dns_name_isabsolute(prefix))
  179. count--;
  180. start = 0;
  181. length = name_length(name);
  182. while (count > 0) {
  183. if (offset >= 0x4000)
  184. break;
  185. dns_name_getlabelsequence(name, start, n, &tname);
  186. hash = dns_name_hash(&tname, ISC_FALSE) %
  187. DNS_COMPRESS_TABLESIZE;
  188. tlength = name_length(&tname);
  189. toffset = (isc_uint16_t)(offset + (length - tlength));
  190. /*
  191. * Create a new node and add it.
  192. */
  193. if (cctx->count < DNS_COMPRESS_INITIALNODES)
  194. node = &cctx->initialnodes[cctx->count];
  195. else {
  196. node = isc_mem_get(cctx->mctx,
  197. sizeof(dns_compressnode_t));
  198. if (node == NULL)
  199. return;
  200. }
  201. node->count = cctx->count++;
  202. node->offset = toffset;
  203. dns_name_toregion(&tname, &node->r);
  204. node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
  205. node->next = cctx->table[hash];
  206. cctx->table[hash] = node;
  207. start++;
  208. n--;
  209. count--;
  210. }
  211. }
  212. void
  213. dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) {
  214. unsigned int i;
  215. dns_compressnode_t *node;
  216. REQUIRE(VALID_CCTX(cctx));
  217. for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
  218. node = cctx->table[i];
  219. /*
  220. * This relies on nodes with greater offsets being
  221. * closer to the beginning of the list, and the
  222. * items with the greatest offsets being at the end
  223. * of the initialnodes[] array.
  224. */
  225. while (node != NULL && node->offset >= offset) {
  226. cctx->table[i] = node->next;
  227. if (node->count >= DNS_COMPRESS_INITIALNODES)
  228. isc_mem_put(cctx->mctx, node, sizeof(*node));
  229. cctx->count--;
  230. node = cctx->table[i];
  231. }
  232. }
  233. }
  234. /***
  235. *** Decompression
  236. ***/
  237. void
  238. dns_decompress_init(dns_decompress_t *dctx, int edns,
  239. dns_decompresstype_t type) {
  240. REQUIRE(dctx != NULL);
  241. REQUIRE(edns >= -1 && edns <= 255);
  242. dctx->allowed = DNS_COMPRESS_NONE;
  243. dctx->edns = edns;
  244. dctx->type = type;
  245. dctx->magic = DCTX_MAGIC;
  246. }
  247. void
  248. dns_decompress_invalidate(dns_decompress_t *dctx) {
  249. REQUIRE(VALID_DCTX(dctx));
  250. dctx->magic = 0;
  251. }
  252. void
  253. dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed) {
  254. REQUIRE(VALID_DCTX(dctx));
  255. switch (dctx->type) {
  256. case DNS_DECOMPRESS_ANY:
  257. dctx->allowed = DNS_COMPRESS_ALL;
  258. break;
  259. case DNS_DECOMPRESS_NONE:
  260. dctx->allowed = DNS_COMPRESS_NONE;
  261. break;
  262. case DNS_DECOMPRESS_STRICT:
  263. dctx->allowed = allowed;
  264. break;
  265. }
  266. }
  267. unsigned int
  268. dns_decompress_getmethods(dns_decompress_t *dctx) {
  269. REQUIRE(VALID_DCTX(dctx));
  270. return (dctx->allowed);
  271. }
  272. int
  273. dns_decompress_edns(dns_decompress_t *dctx) {
  274. REQUIRE(VALID_DCTX(dctx));
  275. return (dctx->edns);
  276. }
  277. dns_decompresstype_t
  278. dns_decompress_type(dns_decompress_t *dctx) {
  279. REQUIRE(VALID_DCTX(dctx));
  280. return (dctx->type);
  281. }