2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2001 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: compress.c,v 1.50.206.4 2006/03/02 00:37:20 marka Exp $ */
20 #define DNS_NAME_USEINLINE 1
25 #include <isc/string.h>
28 #include <dns/compress.h>
29 #include <dns/fixedname.h>
31 #include <dns/result.h>
33 #define CCTX_MAGIC ISC_MAGIC('C', 'C', 'T', 'X')
34 #define VALID_CCTX(x) ISC_MAGIC_VALID(x, CCTX_MAGIC)
36 #define DCTX_MAGIC ISC_MAGIC('D', 'C', 'T', 'X')
37 #define VALID_DCTX(x) ISC_MAGIC_VALID(x, DCTX_MAGIC)
44 dns_compress_init(dns_compress_t
*cctx
, int edns
, isc_mem_t
*mctx
) {
47 REQUIRE(cctx
!= NULL
);
48 REQUIRE(mctx
!= NULL
); /* See: rdataset.c:towiresorted(). */
52 for (i
= 0; i
< DNS_COMPRESS_TABLESIZE
; i
++)
53 cctx
->table
[i
] = NULL
;
56 cctx
->magic
= CCTX_MAGIC
;
57 return (ISC_R_SUCCESS
);
61 dns_compress_invalidate(dns_compress_t
*cctx
) {
62 dns_compressnode_t
*node
;
65 REQUIRE(VALID_CCTX(cctx
));
68 for (i
= 0; i
< DNS_COMPRESS_TABLESIZE
; i
++) {
69 while (cctx
->table
[i
] != NULL
) {
70 node
= cctx
->table
[i
];
71 cctx
->table
[i
] = cctx
->table
[i
]->next
;
72 if (node
->count
< DNS_COMPRESS_INITIALNODES
)
74 isc_mem_put(cctx
->mctx
, node
, sizeof(*node
));
82 dns_compress_setmethods(dns_compress_t
*cctx
, unsigned int allowed
) {
83 REQUIRE(VALID_CCTX(cctx
));
85 cctx
->allowed
= allowed
;
89 dns_compress_getmethods(dns_compress_t
*cctx
) {
90 REQUIRE(VALID_CCTX(cctx
));
91 return (cctx
->allowed
);
95 dns_compress_getedns(dns_compress_t
*cctx
) {
96 REQUIRE(VALID_CCTX(cctx
));
100 #define NODENAME(node, name) \
102 (name)->length = (node)->r.length; \
103 (name)->labels = (node)->labels; \
104 (name)->ndata = (node)->r.base; \
105 (name)->attributes = DNS_NAMEATTR_ABSOLUTE; \
109 * Find the longest match of name in the table.
110 * If match is found return ISC_TRUE. prefix, suffix and offset are updated.
111 * If no match is found return ISC_FALSE.
114 dns_compress_findglobal(dns_compress_t
*cctx
, const dns_name_t
*name
,
115 dns_name_t
*prefix
, isc_uint16_t
*offset
)
117 dns_name_t tname
, nname
;
118 dns_compressnode_t
*node
= NULL
;
119 unsigned int labels
, hash
, n
;
121 REQUIRE(VALID_CCTX(cctx
));
122 REQUIRE(dns_name_isabsolute(name
) == ISC_TRUE
);
123 REQUIRE(offset
!= NULL
);
125 if (cctx
->count
== 0)
128 labels
= dns_name_countlabels(name
);
131 dns_name_init(&tname
, NULL
);
132 dns_name_init(&nname
, NULL
);
134 for (n
= 0; n
< labels
- 1; n
++) {
135 dns_name_getlabelsequence(name
, n
, labels
- n
, &tname
);
136 hash
= dns_name_hash(&tname
, ISC_FALSE
) %
137 DNS_COMPRESS_TABLESIZE
;
138 for (node
= cctx
->table
[hash
]; node
!= NULL
; node
= node
->next
)
140 NODENAME(node
, &nname
);
141 if (dns_name_equal(&nname
, &tname
))
149 * If node == NULL, we found no match at all.
155 dns_name_reset(prefix
);
157 dns_name_getlabelsequence(name
, 0, n
, prefix
);
159 *offset
= node
->offset
;
163 static inline unsigned int
164 name_length(const dns_name_t
*name
) {
166 dns_name_toregion(name
, &r
);
171 dns_compress_add(dns_compress_t
*cctx
, const dns_name_t
*name
,
172 const dns_name_t
*prefix
, isc_uint16_t offset
)
179 dns_compressnode_t
*node
;
181 unsigned int tlength
;
182 isc_uint16_t toffset
;
184 REQUIRE(VALID_CCTX(cctx
));
185 REQUIRE(dns_name_isabsolute(name
));
187 dns_name_init(&tname
, NULL
);
189 n
= dns_name_countlabels(name
);
190 count
= dns_name_countlabels(prefix
);
191 if (dns_name_isabsolute(prefix
))
194 length
= name_length(name
);
196 if (offset
>= 0x4000)
198 dns_name_getlabelsequence(name
, start
, n
, &tname
);
199 hash
= dns_name_hash(&tname
, ISC_FALSE
) %
200 DNS_COMPRESS_TABLESIZE
;
201 tlength
= name_length(&tname
);
202 toffset
= (isc_uint16_t
)(offset
+ (length
- tlength
));
204 * Create a new node and add it.
206 if (cctx
->count
< DNS_COMPRESS_INITIALNODES
)
207 node
= &cctx
->initialnodes
[cctx
->count
];
209 node
= isc_mem_get(cctx
->mctx
,
210 sizeof(dns_compressnode_t
));
214 node
->count
= cctx
->count
++;
215 node
->offset
= toffset
;
216 dns_name_toregion(&tname
, &node
->r
);
217 node
->labels
= (isc_uint8_t
)dns_name_countlabels(&tname
);
218 node
->next
= cctx
->table
[hash
];
219 cctx
->table
[hash
] = node
;
227 dns_compress_rollback(dns_compress_t
*cctx
, isc_uint16_t offset
) {
229 dns_compressnode_t
*node
;
231 REQUIRE(VALID_CCTX(cctx
));
233 for (i
= 0; i
< DNS_COMPRESS_TABLESIZE
; i
++) {
234 node
= cctx
->table
[i
];
236 * This relies on nodes with greater offsets being
237 * closer to the beginning of the list, and the
238 * items with the greatest offsets being at the end
239 * of the initialnodes[] array.
241 while (node
!= NULL
&& node
->offset
>= offset
) {
242 cctx
->table
[i
] = node
->next
;
243 if (node
->count
>= DNS_COMPRESS_INITIALNODES
)
244 isc_mem_put(cctx
->mctx
, node
, sizeof(*node
));
246 node
= cctx
->table
[i
];
256 dns_decompress_init(dns_decompress_t
*dctx
, int edns
,
257 dns_decompresstype_t type
) {
259 REQUIRE(dctx
!= NULL
);
260 REQUIRE(edns
>= -1 && edns
<= 255);
262 dctx
->allowed
= DNS_COMPRESS_NONE
;
265 dctx
->magic
= DCTX_MAGIC
;
269 dns_decompress_invalidate(dns_decompress_t
*dctx
) {
271 REQUIRE(VALID_DCTX(dctx
));
277 dns_decompress_setmethods(dns_decompress_t
*dctx
, unsigned int allowed
) {
279 REQUIRE(VALID_DCTX(dctx
));
281 switch (dctx
->type
) {
282 case DNS_DECOMPRESS_ANY
:
283 dctx
->allowed
= DNS_COMPRESS_ALL
;
285 case DNS_DECOMPRESS_NONE
:
286 dctx
->allowed
= DNS_COMPRESS_NONE
;
288 case DNS_DECOMPRESS_STRICT
:
289 dctx
->allowed
= allowed
;
295 dns_decompress_getmethods(dns_decompress_t
*dctx
) {
297 REQUIRE(VALID_DCTX(dctx
));
299 return (dctx
->allowed
);
303 dns_decompress_edns(dns_decompress_t
*dctx
) {
305 REQUIRE(VALID_DCTX(dctx
));
311 dns_decompress_type(dns_decompress_t
*dctx
) {
313 REQUIRE(VALID_DCTX(dctx
));