1999-02-22 07:24:05 +00:00
|
|
|
/*
|
2015-03-01 23:45:20 +00:00
|
|
|
* Copyright (C) 2004-2007, 2015 Internet Systems Consortium, Inc. ("ISC")
|
2001-01-09 22:01:04 +00:00
|
|
|
* Copyright (C) 1999-2001 Internet Software Consortium.
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
2007-06-18 23:47:57 +00:00
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
1999-02-22 07:24:05 +00:00
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
2000-08-01 01:33:37 +00:00
|
|
|
*
|
2004-03-05 05:14:21 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
|
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
|
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
|
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
|
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
|
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
|
* PERFORMANCE OF THIS SOFTWARE.
|
1999-02-22 07:24:05 +00:00
|
|
|
*/
|
|
|
|
|
2015-02-27 23:45:24 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2005-04-27 04:57:32 +00:00
|
|
|
/*! \file */
|
2000-04-27 21:46:31 +00:00
|
|
|
|
|
|
|
#define DNS_NAME_USEINLINE 1
|
1999-02-22 07:24:05 +00:00
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2000-05-08 14:38:29 +00:00
|
|
|
#include <isc/mem.h>
|
|
|
|
#include <isc/string.h>
|
2000-04-28 01:12:23 +00:00
|
|
|
#include <isc/util.h>
|
1999-02-22 07:24:05 +00:00
|
|
|
|
|
|
|
#include <dns/compress.h>
|
1999-04-14 06:03:15 +00:00
|
|
|
#include <dns/fixedname.h>
|
2000-04-12 21:25:10 +00:00
|
|
|
#include <dns/rbt.h>
|
2000-05-02 03:54:17 +00:00
|
|
|
#include <dns/result.h>
|
1999-02-22 07:24:05 +00:00
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define CCTX_MAGIC ISC_MAGIC('C', 'C', 'T', 'X')
|
2000-05-08 14:38:29 +00:00
|
|
|
#define VALID_CCTX(x) ISC_MAGIC_VALID(x, CCTX_MAGIC)
|
1999-02-22 07:24:05 +00:00
|
|
|
|
2001-06-04 19:33:39 +00:00
|
|
|
#define DCTX_MAGIC ISC_MAGIC('D', 'C', 'T', 'X')
|
2000-05-08 14:38:29 +00:00
|
|
|
#define VALID_DCTX(x) ISC_MAGIC_VALID(x, DCTX_MAGIC)
|
1999-02-24 06:31:35 +00:00
|
|
|
|
|
|
|
/***
|
|
|
|
*** Compression
|
|
|
|
***/
|
1999-02-22 07:24:05 +00:00
|
|
|
|
1999-12-23 00:09:04 +00:00
|
|
|
isc_result_t
|
2000-04-27 00:08:44 +00:00
|
|
|
dns_compress_init(dns_compress_t *cctx, int edns, isc_mem_t *mctx) {
|
2000-12-29 00:59:41 +00:00
|
|
|
unsigned int i;
|
1999-02-22 07:24:05 +00:00
|
|
|
|
|
|
|
REQUIRE(cctx != NULL);
|
2004-02-19 01:23:42 +00:00
|
|
|
REQUIRE(mctx != NULL); /* See: rdataset.c:towiresorted(). */
|
1999-02-22 07:24:05 +00:00
|
|
|
|
|
|
|
cctx->allowed = 0;
|
|
|
|
cctx->edns = edns;
|
2000-12-29 00:59:41 +00:00
|
|
|
for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++)
|
|
|
|
cctx->table[i] = NULL;
|
1999-02-22 07:24:05 +00:00
|
|
|
cctx->mctx = mctx;
|
2000-12-29 00:59:41 +00:00
|
|
|
cctx->count = 0;
|
1999-02-22 07:24:05 +00:00
|
|
|
cctx->magic = CCTX_MAGIC;
|
2000-04-06 22:03:35 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_compress_invalidate(dns_compress_t *cctx) {
|
2000-12-29 00:59:41 +00:00
|
|
|
dns_compressnode_t *node;
|
|
|
|
unsigned int i;
|
1999-02-22 07:24:05 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
|
|
|
|
cctx->magic = 0;
|
2001-02-15 01:14:16 +00:00
|
|
|
for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
|
|
|
|
while (cctx->table[i] != NULL) {
|
|
|
|
node = cctx->table[i];
|
|
|
|
cctx->table[i] = cctx->table[i]->next;
|
2015-02-27 15:08:38 +11:00
|
|
|
if ((node->offset & 0x8000) != 0)
|
|
|
|
isc_mem_put(cctx->mctx, node->r.base,
|
|
|
|
node->r.length);
|
2001-02-15 01:14:16 +00:00
|
|
|
if (node->count < DNS_COMPRESS_INITIALNODES)
|
|
|
|
continue;
|
|
|
|
isc_mem_put(cctx->mctx, node, sizeof(*node));
|
2000-12-29 00:59:41 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-22 07:24:05 +00:00
|
|
|
cctx->allowed = 0;
|
|
|
|
cctx->edns = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_compress_setmethods(dns_compress_t *cctx, unsigned int allowed) {
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
|
2005-03-04 02:56:21 +00:00
|
|
|
cctx->allowed &= ~DNS_COMPRESS_ALL;
|
|
|
|
cctx->allowed |= (allowed & DNS_COMPRESS_ALL);
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
dns_compress_getmethods(dns_compress_t *cctx) {
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
2005-03-04 02:56:21 +00:00
|
|
|
return (cctx->allowed & DNS_COMPRESS_ALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_compress_setsensitive(dns_compress_t *cctx, isc_boolean_t sensitive) {
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
|
|
|
|
if (sensitive)
|
|
|
|
cctx->allowed |= DNS_COMPRESS_CASESENSITIVE;
|
|
|
|
else
|
|
|
|
cctx->allowed &= ~DNS_COMPRESS_CASESENSITIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_boolean_t
|
|
|
|
dns_compress_getsensitive(dns_compress_t *cctx) {
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
|
|
|
|
return (ISC_TF((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0));
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
dns_compress_getedns(dns_compress_t *cctx) {
|
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
return (cctx->edns);
|
|
|
|
}
|
|
|
|
|
2001-02-09 02:13:07 +00:00
|
|
|
#define NODENAME(node, name) \
|
|
|
|
do { \
|
|
|
|
(name)->length = (node)->r.length; \
|
|
|
|
(name)->labels = (node)->labels; \
|
|
|
|
(name)->ndata = (node)->r.base; \
|
|
|
|
(name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
|
|
|
|
} while (0)
|
|
|
|
|
2000-12-29 19:38:50 +00:00
|
|
|
/*
|
|
|
|
* Find the longest match of name in the table.
|
|
|
|
* If match is found return ISC_TRUE. prefix, suffix and offset are updated.
|
|
|
|
* If no match is found return ISC_FALSE.
|
|
|
|
*/
|
1999-02-22 07:24:05 +00:00
|
|
|
isc_boolean_t
|
2006-02-28 02:39:52 +00:00
|
|
|
dns_compress_findglobal(dns_compress_t *cctx, const dns_name_t *name,
|
2001-02-12 18:07:52 +00:00
|
|
|
dns_name_t *prefix, isc_uint16_t *offset)
|
1999-02-22 07:24:05 +00:00
|
|
|
{
|
2000-12-29 19:38:50 +00:00
|
|
|
dns_name_t tname, nname;
|
|
|
|
dns_compressnode_t *node = NULL;
|
|
|
|
unsigned int labels, hash, n;
|
|
|
|
|
1999-02-22 07:24:05 +00:00
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
REQUIRE(dns_name_isabsolute(name) == ISC_TRUE);
|
|
|
|
REQUIRE(offset != NULL);
|
|
|
|
|
2001-02-10 01:18:19 +00:00
|
|
|
if (cctx->count == 0)
|
|
|
|
return (ISC_FALSE);
|
|
|
|
|
2000-12-29 19:38:50 +00:00
|
|
|
labels = dns_name_countlabels(name);
|
|
|
|
INSIST(labels > 0);
|
|
|
|
|
|
|
|
dns_name_init(&tname, NULL);
|
|
|
|
dns_name_init(&nname, NULL);
|
|
|
|
|
|
|
|
for (n = 0; n < labels - 1; n++) {
|
|
|
|
dns_name_getlabelsequence(name, n, labels - n, &tname);
|
|
|
|
hash = dns_name_hash(&tname, ISC_FALSE) %
|
|
|
|
DNS_COMPRESS_TABLESIZE;
|
|
|
|
for (node = cctx->table[hash]; node != NULL; node = node->next)
|
|
|
|
{
|
2001-02-09 02:13:07 +00:00
|
|
|
NODENAME(node, &nname);
|
2005-03-04 02:56:21 +00:00
|
|
|
if ((cctx->allowed & DNS_COMPRESS_CASESENSITIVE) != 0) {
|
|
|
|
if (dns_name_caseequal(&nname, &tname))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (dns_name_equal(&nname, &tname))
|
|
|
|
break;
|
|
|
|
}
|
2000-12-29 19:38:50 +00:00
|
|
|
}
|
|
|
|
if (node != NULL)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If node == NULL, we found no match at all.
|
|
|
|
*/
|
|
|
|
if (node == NULL)
|
|
|
|
return (ISC_FALSE);
|
|
|
|
|
2001-02-12 18:07:52 +00:00
|
|
|
if (n == 0)
|
2001-02-10 02:55:05 +00:00
|
|
|
dns_name_reset(prefix);
|
2001-02-12 18:07:52 +00:00
|
|
|
else
|
2001-02-10 02:55:05 +00:00
|
|
|
dns_name_getlabelsequence(name, 0, n, prefix);
|
2001-02-12 18:07:52 +00:00
|
|
|
|
2015-02-27 15:08:38 +11:00
|
|
|
*offset = (node->offset & 0x7fff);
|
2000-12-29 19:38:50 +00:00
|
|
|
return (ISC_TRUE);
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
2001-01-23 02:19:48 +00:00
|
|
|
static inline unsigned int
|
2006-02-28 02:39:52 +00:00
|
|
|
name_length(const dns_name_t *name) {
|
2001-01-23 02:19:48 +00:00
|
|
|
isc_region_t r;
|
|
|
|
dns_name_toregion(name, &r);
|
|
|
|
return (r.length);
|
|
|
|
}
|
|
|
|
|
1999-02-22 07:24:05 +00:00
|
|
|
void
|
2006-02-28 02:39:52 +00:00
|
|
|
dns_compress_add(dns_compress_t *cctx, const dns_name_t *name,
|
|
|
|
const dns_name_t *prefix, isc_uint16_t offset)
|
2001-01-04 19:25:59 +00:00
|
|
|
{
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_name_t tname, xname;
|
2000-12-29 19:38:50 +00:00
|
|
|
unsigned int start;
|
|
|
|
unsigned int n;
|
2001-01-04 19:25:59 +00:00
|
|
|
unsigned int count;
|
2000-12-29 19:38:50 +00:00
|
|
|
unsigned int hash;
|
|
|
|
dns_compressnode_t *node;
|
2001-01-23 02:19:48 +00:00
|
|
|
unsigned int length;
|
|
|
|
unsigned int tlength;
|
|
|
|
isc_uint16_t toffset;
|
2015-02-27 15:08:38 +11:00
|
|
|
unsigned char *tmp;
|
|
|
|
isc_region_t r;
|
2000-12-29 19:38:50 +00:00
|
|
|
|
1999-02-22 07:24:05 +00:00
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
2000-12-29 00:59:41 +00:00
|
|
|
REQUIRE(dns_name_isabsolute(name));
|
1999-02-22 07:24:05 +00:00
|
|
|
|
2015-02-27 15:08:38 +11:00
|
|
|
if (offset > 0x4000)
|
|
|
|
return;
|
2000-12-29 19:38:50 +00:00
|
|
|
dns_name_init(&tname, NULL);
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_name_init(&xname, NULL);
|
2000-12-29 19:38:50 +00:00
|
|
|
|
|
|
|
n = dns_name_countlabels(name);
|
2001-01-04 19:25:59 +00:00
|
|
|
count = dns_name_countlabels(prefix);
|
|
|
|
if (dns_name_isabsolute(prefix))
|
|
|
|
count--;
|
2015-02-27 15:08:38 +11:00
|
|
|
if (count == 0)
|
|
|
|
return;
|
2000-12-29 19:38:50 +00:00
|
|
|
start = 0;
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_name_toregion(name, &r);
|
|
|
|
length = r.length;
|
|
|
|
tmp = isc_mem_get(cctx->mctx, length);
|
|
|
|
if (tmp == NULL)
|
|
|
|
return;
|
|
|
|
memmove(tmp, r.base, r.length);
|
|
|
|
r.base = tmp;
|
|
|
|
dns_name_fromregion(&xname, &r);
|
|
|
|
|
2001-01-04 19:25:59 +00:00
|
|
|
while (count > 0) {
|
2000-12-29 19:38:50 +00:00
|
|
|
if (offset >= 0x4000)
|
|
|
|
break;
|
2015-02-27 15:08:38 +11:00
|
|
|
dns_name_getlabelsequence(&xname, start, n, &tname);
|
2000-12-29 19:38:50 +00:00
|
|
|
hash = dns_name_hash(&tname, ISC_FALSE) %
|
|
|
|
DNS_COMPRESS_TABLESIZE;
|
2001-01-23 02:19:48 +00:00
|
|
|
tlength = name_length(&tname);
|
|
|
|
toffset = (isc_uint16_t)(offset + (length - tlength));
|
2000-12-29 19:38:50 +00:00
|
|
|
/*
|
2001-02-09 02:13:07 +00:00
|
|
|
* Create a new node and add it.
|
2000-12-29 19:38:50 +00:00
|
|
|
*/
|
|
|
|
if (cctx->count < DNS_COMPRESS_INITIALNODES)
|
|
|
|
node = &cctx->initialnodes[cctx->count];
|
|
|
|
else {
|
|
|
|
node = isc_mem_get(cctx->mctx,
|
|
|
|
sizeof(dns_compressnode_t));
|
2015-02-27 15:08:38 +11:00
|
|
|
if (node == NULL) {
|
|
|
|
if (start == 0)
|
|
|
|
isc_mem_put(cctx->mctx,
|
|
|
|
r.base, r.length);
|
2000-12-29 19:38:50 +00:00
|
|
|
return;
|
2015-02-27 15:08:38 +11:00
|
|
|
}
|
2000-12-29 19:38:50 +00:00
|
|
|
}
|
|
|
|
node->count = cctx->count++;
|
2015-02-27 15:08:38 +11:00
|
|
|
if (start == 0)
|
|
|
|
toffset |= 0x8000;
|
2001-01-23 02:19:48 +00:00
|
|
|
node->offset = toffset;
|
2000-12-29 19:38:50 +00:00
|
|
|
dns_name_toregion(&tname, &node->r);
|
2001-02-09 02:13:07 +00:00
|
|
|
node->labels = (isc_uint8_t)dns_name_countlabels(&tname);
|
2000-12-29 19:38:50 +00:00
|
|
|
node->next = cctx->table[hash];
|
|
|
|
cctx->table[hash] = node;
|
|
|
|
start++;
|
|
|
|
n--;
|
2001-01-04 19:25:59 +00:00
|
|
|
count--;
|
2000-12-29 19:38:50 +00:00
|
|
|
}
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
1999-05-03 03:07:16 +00:00
|
|
|
dns_compress_rollback(dns_compress_t *cctx, isc_uint16_t offset) {
|
2000-12-29 00:59:41 +00:00
|
|
|
unsigned int i;
|
|
|
|
dns_compressnode_t *node;
|
1999-05-03 03:07:16 +00:00
|
|
|
|
1999-02-22 07:24:05 +00:00
|
|
|
REQUIRE(VALID_CCTX(cctx));
|
|
|
|
|
2000-12-29 00:59:41 +00:00
|
|
|
for (i = 0; i < DNS_COMPRESS_TABLESIZE; i++) {
|
|
|
|
node = cctx->table[i];
|
2001-01-07 22:01:12 +00:00
|
|
|
/*
|
|
|
|
* This relies on nodes with greater offsets being
|
|
|
|
* closer to the beginning of the list, and the
|
2015-03-01 23:45:20 +00:00
|
|
|
* items with the greatest offsets being at the end
|
2001-01-07 22:01:12 +00:00
|
|
|
* of the initialnodes[] array.
|
|
|
|
*/
|
2015-02-27 15:08:38 +11:00
|
|
|
while (node != NULL && (node->offset & 0x7fff) >= offset) {
|
2000-12-29 00:59:41 +00:00
|
|
|
cctx->table[i] = node->next;
|
2015-02-27 15:08:38 +11:00
|
|
|
if ((node->offset & 0x8000) != 0)
|
|
|
|
isc_mem_put(cctx->mctx, node->r.base,
|
|
|
|
node->r.length);
|
2000-12-29 00:59:41 +00:00
|
|
|
if (node->count >= DNS_COMPRESS_INITIALNODES)
|
2001-01-07 22:01:12 +00:00
|
|
|
isc_mem_put(cctx->mctx, node, sizeof(*node));
|
2000-12-29 00:59:41 +00:00
|
|
|
cctx->count--;
|
|
|
|
node = cctx->table[i];
|
1999-05-03 03:07:16 +00:00
|
|
|
}
|
|
|
|
}
|
1999-02-22 07:24:05 +00:00
|
|
|
}
|
|
|
|
|
1999-02-24 06:31:35 +00:00
|
|
|
/***
|
|
|
|
*** Decompression
|
|
|
|
***/
|
|
|
|
|
|
|
|
void
|
2000-11-14 23:29:55 +00:00
|
|
|
dns_decompress_init(dns_decompress_t *dctx, int edns,
|
|
|
|
dns_decompresstype_t type) {
|
1999-02-24 06:31:35 +00:00
|
|
|
|
|
|
|
REQUIRE(dctx != NULL);
|
|
|
|
REQUIRE(edns >= -1 && edns <= 255);
|
|
|
|
|
|
|
|
dctx->allowed = DNS_COMPRESS_NONE;
|
|
|
|
dctx->edns = edns;
|
2000-11-14 23:29:55 +00:00
|
|
|
dctx->type = type;
|
1999-02-24 06:31:35 +00:00
|
|
|
dctx->magic = DCTX_MAGIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_decompress_invalidate(dns_decompress_t *dctx) {
|
|
|
|
|
|
|
|
REQUIRE(VALID_DCTX(dctx));
|
|
|
|
|
|
|
|
dctx->magic = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
dns_decompress_setmethods(dns_decompress_t *dctx, unsigned int allowed) {
|
|
|
|
|
|
|
|
REQUIRE(VALID_DCTX(dctx));
|
|
|
|
|
2000-11-14 23:29:55 +00:00
|
|
|
switch (dctx->type) {
|
|
|
|
case DNS_DECOMPRESS_ANY:
|
2000-05-04 22:19:34 +00:00
|
|
|
dctx->allowed = DNS_COMPRESS_ALL;
|
2000-11-14 23:29:55 +00:00
|
|
|
break;
|
|
|
|
case DNS_DECOMPRESS_NONE:
|
|
|
|
dctx->allowed = DNS_COMPRESS_NONE;
|
|
|
|
break;
|
|
|
|
case DNS_DECOMPRESS_STRICT:
|
|
|
|
dctx->allowed = allowed;
|
|
|
|
break;
|
|
|
|
}
|
1999-02-24 06:31:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int
|
|
|
|
dns_decompress_getmethods(dns_decompress_t *dctx) {
|
|
|
|
|
|
|
|
REQUIRE(VALID_DCTX(dctx));
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-02-24 06:31:35 +00:00
|
|
|
return (dctx->allowed);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
dns_decompress_edns(dns_decompress_t *dctx) {
|
|
|
|
|
|
|
|
REQUIRE(VALID_DCTX(dctx));
|
2000-08-01 01:33:37 +00:00
|
|
|
|
1999-02-24 06:31:35 +00:00
|
|
|
return (dctx->edns);
|
|
|
|
}
|
|
|
|
|
2000-11-14 23:29:55 +00:00
|
|
|
dns_decompresstype_t
|
|
|
|
dns_decompress_type(dns_decompress_t *dctx) {
|
1999-02-24 06:31:35 +00:00
|
|
|
|
|
|
|
REQUIRE(VALID_DCTX(dctx));
|
|
|
|
|
2000-11-14 23:29:55 +00:00
|
|
|
return (dctx->type);
|
1999-02-24 06:31:35 +00:00
|
|
|
}
|