compress.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004-2007, 2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1999-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #define DNS_NAME_USEINLINE 1
00023 
00024 #include <config.h>
00025 
00026 #include <isc/mem.h>
00027 #include <isc/string.h>
00028 #include <isc/util.h>
00029 
00030 #include <dns/compress.h>
00031 #include <dns/fixedname.h>
00032 #include <dns/rbt.h>
00033 #include <dns/result.h>
00034 
00035 #define CCTX_MAGIC      ISC_MAGIC('C', 'C', 'T', 'X')
00036 #define VALID_CCTX(x)   ISC_MAGIC_VALID(x, CCTX_MAGIC)
00037 
00038 #define DCTX_MAGIC      ISC_MAGIC('D', 'C', 'T', 'X')
00039 #define VALID_DCTX(x)   ISC_MAGIC_VALID(x, DCTX_MAGIC)
00040 
00041 /***
00042  ***    Compression
00043  ***/
00044 
00045 isc_result_t
00046 dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx) {
00047         unsigned int i;
00048 
00049         REQUIRE(cctx != NULL);
00050         REQUIRE(mctx != NULL);  /* See: rdataset.c:towiresorted(). */
00051 
00052         cctx->allowed = 0;
00053         cctx->edns = edns;
00054         for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++)
00055                 cctx->table[i] = NULL;
00056         cctx->mctx = mctx;
00057         cctx->count = 0;
00058         cctx->magic = CCTX_MAGIC;
00059         return (ISC_R_SUCCESS);
00060 }
00061 
00062 void
00063 dns_compress_invalidate(dns_compress_t *cctx) {
00064         dns_compressnode_t *node;
00065         unsigned int i;
00066 
00067         REQUIRE(VALID_CCTX(cctx));
00068 
00069         cctx->magic = 0;
00070         for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
00071                 while (cctx->table[i] != NULL) {
00072                         node = cctx->table[i];
00073                         cctx->table[i] = cctx->table[i]->next;
00074                         if ((node->offset & 0x8000) != 0)
00075                                 isc_mem_put(cctx->mctx, node->r.base,
00076                                             node->r.length);
00077                         if (node->count < DNS_COMPRESS_INITIALNODES)
00078                                 continue;
00079                         isc_mem_put(cctx->mctx, node, sizeof(*node));
00080                 }
00081         }
00082         cctx->allowed = 0;
00083         cctx->edns = -1;
00084 }
00085 
00086 void
00087 dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed) {
00088         REQUIRE(VALID_CCTX(cctx));
00089 
00090         cctx->allowed &= ~DNS_COMPRESS_ALL;
00091         cctx->allowed |= (allowed & DNS_COMPRESS_ALL);
00092 }
00093 
00094 unsigned int
00095 dns_compress_getmethods(dns_compress_t *cctx) {
00096         REQUIRE(VALID_CCTX(cctx));
00097         return (cctx->allowed & DNS_COMPRESS_ALL);
00098 }
00099 
00100 void
00101 dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive) {
00102         REQUIRE(VALID_CCTX(cctx));
00103 
00104         if (sensitive)
00105                 cctx->allowed |= DNS_COMPRESS_CASESENSITIVE;
00106         else
00107                 cctx->allowed &= ~DNS_COMPRESS_CASESENSITIVE;
00108 }
00109 
00110 isc_boolean_t
00111 dns_compress_getsensitive(dns_compress_t *cctx) {
00112         REQUIRE(VALID_CCTX(cctx));
00113 
00114         return (ISC_TF((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0));
00115 }
00116 
00117 int
00118 dns_compress_getedns(dns_compress_t *cctx) {
00119         REQUIRE(VALID_CCTX(cctx));
00120         return (cctx->edns);
00121 }
00122 
00123 #define NODENAME(node, name) \
00124 do { \
00125         (name)->length = (node)->r.length; \
00126         (name)->labels = (node)->labels; \
00127         (name)->ndata = (node)->r.base; \
00128         (name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
00129 } while (0)
00130 
00131 /*
00132  * Find the longest match of name in the table.
00133  * If match is found return ISC_TRUE. prefix, suffix and offset are updated.
00134  * If no match is found return ISC_FALSE.
00135  */
00136 isc_boolean_t
00137 dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
00138                         dns_name_t *prefix, isc_uint16_t *offset)
00139 {
00140         dns_name_t tname, nname;
00141         dns_compressnode_t *node = NULL;
00142         unsigned int labels, hash, n;
00143 
00144         REQUIRE(VALID_CCTX(cctx));
00145         REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
00146         REQUIRE(offset != NULL);
00147 
00148         if (cctx->count == 0)
00149                 return (ISC_FALSE);
00150 
00151         labels = dns_name_countlabels(name);
00152         INSIST(labels > 0);
00153 
00154         dns_name_init(&tname, NULL);
00155         dns_name_init(&nname, NULL);
00156 
00157         for (n = 0; n < labels - 1; n++) {
00158                 dns_name_getlabelsequence(name, n, labels - n, &tname);
00159                 hash = dns_name_hash(&tname, ISC_FALSE) %
00160                        DNS_COMPRESS_TABLESIZE;
00161                 for (node = cctx->table[hash]; node != NULL; node = node->next)
00162                 {
00163                         NODENAME(node, &nname);
00164                         if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
00165                                 if (dns_name_caseequal(&nname, &tname))
00166                                         break;
00167                         } else {
00168                                 if (dns_name_equal(&nname, &tname))
00169                                         break;
00170                         }
00171                 }
00172                 if (node != NULL)
00173                         break;
00174         }
00175 
00176         /*
00177          * If node == NULL, we found no match at all.
00178          */
00179         if (node == NULL)
00180                 return (ISC_FALSE);
00181 
00182         if (n == 0)
00183                 dns_name_reset(prefix);
00184         else
00185                 dns_name_getlabelsequence(name, 0, n, prefix);
00186 
00187         *offset = (node->offset & 0x7fff);
00188         return (ISC_TRUE);
00189 }
00190 
00191 static inline unsigned int
00192 name_length(const dns_name_t *name) {
00193         isc_region_t r;
00194         dns_name_toregion(name, &r);
00195         return (r.length);
00196 }
00197 
00198 void
00199 dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
00200                  const dns_name_t *prefix, isc_uint16_t offset)
00201 {
00202         dns_name_t tname, xname;
00203         unsigned int start;
00204         unsigned int n;
00205         unsigned int count;
00206         unsigned int hash;
00207         dns_compressnode_t *node;
00208         unsigned int length;
00209         unsigned int tlength;
00210         isc_uint16_t toffset;
00211         unsigned char *tmp;
00212         isc_region_t r;
00213 
00214         REQUIRE(VALID_CCTX(cctx));
00215         REQUIRE(dns_name_isabsolute(name));
00216 
00217         if (offset > 0x4000)
00218                 return;
00219         dns_name_init(&tname, NULL);
00220         dns_name_init(&xname, NULL);
00221 
00222         n = dns_name_countlabels(name);
00223         count = dns_name_countlabels(prefix);
00224         if (dns_name_isabsolute(prefix))
00225                 count--;
00226         if (count == 0)
00227                 return;
00228         start = 0;
00229         dns_name_toregion(name, &r);
00230         length = r.length;
00231         tmp = isc_mem_get(cctx->mctx, length);
00232         if (tmp == NULL)
00233                 return;
00234         memmove(tmp, r.base, r.length);
00235         r.base = tmp;
00236         dns_name_fromregion(&xname, &r);
00237 
00238         while (count > 0) {
00239                 if (offset >= 0x4000)
00240                         break;
00241                 dns_name_getlabelsequence(&xname, start, n, &tname);
00242                 hash = dns_name_hash(&tname, ISC_FALSE) %
00243                        DNS_COMPRESS_TABLESIZE;
00244                 tlength = name_length(&tname);
00245                 toffset = (isc_uint16_t)(offset + (length - tlength));
00246                 /*
00247                  * Create a new node and add it.
00248                  */
00249                 if (cctx->count < DNS_COMPRESS_INITIALNODES)
00250                         node = &cctx->initialnodes[cctx->count];
00251                 else {
00252                         node = isc_mem_get(cctx->mctx,
00253                                            sizeof(dns_compressnode_t));
00254                         if (node == NULL) {
00255                                 if (start == 0)
00256                                         isc_mem_put(cctx->mctx,
00257                                                     r.base, r.length);
00258                                 return;
00259                         }
00260                 }
00261                 node->count = cctx->count++;
00262                 if (start == 0)
00263                         toffset |= 0x8000;
00264                 node->offset = toffset;
00265                 dns_name_toregion(&tname, &node->r);
00266                 node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
00267                 node->next = cctx->table[hash];
00268                 cctx->table[hash] = node;
00269                 start++;
00270                 n--;
00271                 count--;
00272         }
00273 }
00274 
00275 void
00276 dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) {
00277         unsigned int i;
00278         dns_compressnode_t *node;
00279 
00280         REQUIRE(VALID_CCTX(cctx));
00281 
00282         for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
00283                 node = cctx->table[i];
00284                 /*
00285                  * This relies on nodes with greater offsets being
00286                  * closer to the beginning of the list, and the
00287                  * items with the greatest offsets being at the end
00288                  * of the initialnodes[] array.
00289                  */
00290                 while (node != NULL && (node->offset & 0x7fff) >= offset) {
00291                         cctx->table[i] = node->next;
00292                         if ((node->offset & 0x8000) != 0)
00293                                 isc_mem_put(cctx->mctx, node->r.base,
00294                                             node->r.length);
00295                         if (node->count >= DNS_COMPRESS_INITIALNODES)
00296                                 isc_mem_put(cctx->mctx, node, sizeof(*node));
00297                         cctx->count--;
00298                         node = cctx->table[i];
00299                 }
00300         }
00301 }
00302 
00303 /***
00304  ***    Decompression
00305  ***/
00306 
00307 void
00308 dns_decompress_init(dns_decompress_t *dctx, int edns,
00309                     dns_decompresstype_t type) {
00310 
00311         REQUIRE(dctx != NULL);
00312         REQUIRE(edns >= -1 && edns <= 255);
00313 
00314         dctx->allowed = DNS_COMPRESS_NONE;
00315         dctx->edns = edns;
00316         dctx->type = type;
00317         dctx->magic = DCTX_MAGIC;
00318 }
00319 
00320 void
00321 dns_decompress_invalidate(dns_decompress_t *dctx) {
00322 
00323         REQUIRE(VALID_DCTX(dctx));
00324 
00325         dctx->magic = 0;
00326 }
00327 
00328 void
00329 dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed) {
00330 
00331         REQUIRE(VALID_DCTX(dctx));
00332 
00333         switch (dctx->type) {
00334         case DNS_DECOMPRESS_ANY:
00335                 dctx->allowed = DNS_COMPRESS_ALL;
00336                 break;
00337         case DNS_DECOMPRESS_NONE:
00338                 dctx->allowed = DNS_COMPRESS_NONE;
00339                 break;
00340         case DNS_DECOMPRESS_STRICT:
00341                 dctx->allowed = allowed;
00342                 break;
00343         }
00344 }
00345 
00346 unsigned int
00347 dns_decompress_getmethods(dns_decompress_t *dctx) {
00348 
00349         REQUIRE(VALID_DCTX(dctx));
00350 
00351         return (dctx->allowed);
00352 }
00353 
00354 int
00355 dns_decompress_edns(dns_decompress_t *dctx) {
00356 
00357         REQUIRE(VALID_DCTX(dctx));
00358 
00359         return (dctx->edns);
00360 }
00361 
00362 dns_decompresstype_t
00363 dns_decompress_type(dns_decompress_t *dctx) {
00364 
00365         REQUIRE(VALID_DCTX(dctx));
00366 
00367         return (dctx->type);
00368 }

Generated on Tue Apr 28 17:40:56 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha