1*4ac1c27eSchristos /* $NetBSD: name.c,v 1.12 2023/01/25 21:43:30 christos Exp $ */
2e2b1b9c0Schristos
3e2b1b9c0Schristos /*
4e2b1b9c0Schristos * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5e2b1b9c0Schristos *
6c0b5d9fbSchristos * SPDX-License-Identifier: MPL-2.0
7c0b5d9fbSchristos *
8e2b1b9c0Schristos * This Source Code Form is subject to the terms of the Mozilla Public
9e2b1b9c0Schristos * License, v. 2.0. If a copy of the MPL was not distributed with this
1073584a28Schristos * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11e2b1b9c0Schristos *
12e2b1b9c0Schristos * See the COPYRIGHT file distributed with this work for additional
13e2b1b9c0Schristos * information regarding copyright ownership.
14e2b1b9c0Schristos */
15e2b1b9c0Schristos
16e2b1b9c0Schristos /*! \file */
17e2b1b9c0Schristos
18e2b1b9c0Schristos #include <ctype.h>
19f2e20987Schristos #include <inttypes.h>
20f2e20987Schristos #include <stdbool.h>
21e2b1b9c0Schristos #include <stdlib.h>
22e2b1b9c0Schristos
23e2b1b9c0Schristos #include <isc/buffer.h>
24e2b1b9c0Schristos #include <isc/hash.h>
25e2b1b9c0Schristos #include <isc/mem.h>
26e2b1b9c0Schristos #include <isc/once.h>
27e2b1b9c0Schristos #include <isc/print.h>
28e2b1b9c0Schristos #include <isc/random.h>
29e2b1b9c0Schristos #include <isc/string.h>
30e2b1b9c0Schristos #include <isc/thread.h>
31e2b1b9c0Schristos #include <isc/util.h>
32e2b1b9c0Schristos
33e2b1b9c0Schristos #include <dns/compress.h>
34e2b1b9c0Schristos #include <dns/fixedname.h>
35e2b1b9c0Schristos #include <dns/name.h>
36e2b1b9c0Schristos #include <dns/result.h>
37e2b1b9c0Schristos
38e2b1b9c0Schristos #define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
39e2b1b9c0Schristos
40e2b1b9c0Schristos typedef enum {
41e2b1b9c0Schristos ft_init = 0,
42e2b1b9c0Schristos ft_start,
43e2b1b9c0Schristos ft_ordinary,
44e2b1b9c0Schristos ft_initialescape,
45e2b1b9c0Schristos ft_escape,
46e2b1b9c0Schristos ft_escdecimal,
47e2b1b9c0Schristos ft_at
48e2b1b9c0Schristos } ft_state;
49e2b1b9c0Schristos
509742fdb4Schristos typedef enum { fw_start = 0, fw_ordinary, fw_newcurrent } fw_state;
51e2b1b9c0Schristos
52e2b1b9c0Schristos static char digitvalue[256] = {
53e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
54e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
55e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
56e2b1b9c0Schristos 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
57e2b1b9c0Schristos -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
58e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
59e2b1b9c0Schristos -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
60e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
61e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
66e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
68e2b1b9c0Schristos -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
69e2b1b9c0Schristos };
70e2b1b9c0Schristos
71e2b1b9c0Schristos static unsigned char maptolower[] = {
729742fdb4Schristos 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
739742fdb4Schristos 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
749742fdb4Schristos 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
759742fdb4Schristos 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
769742fdb4Schristos 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
779742fdb4Schristos 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
789742fdb4Schristos 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
799742fdb4Schristos 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
809742fdb4Schristos 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
819742fdb4Schristos 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
829742fdb4Schristos 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
839742fdb4Schristos 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
849742fdb4Schristos 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
859742fdb4Schristos 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
869742fdb4Schristos 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
879742fdb4Schristos 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
889742fdb4Schristos 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
899742fdb4Schristos 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
909742fdb4Schristos 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
919742fdb4Schristos 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
929742fdb4Schristos 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
939742fdb4Schristos 0xfc, 0xfd, 0xfe, 0xff
94e2b1b9c0Schristos };
95e2b1b9c0Schristos
96e2b1b9c0Schristos #define CONVERTTOASCII(c)
97e2b1b9c0Schristos #define CONVERTFROMASCII(c)
98e2b1b9c0Schristos
99e2b1b9c0Schristos #define INIT_OFFSETS(name, var, default_offsets) \
100e2b1b9c0Schristos if ((name)->offsets != NULL) \
101e2b1b9c0Schristos var = (name)->offsets; \
102e2b1b9c0Schristos else \
103e2b1b9c0Schristos var = (default_offsets);
104e2b1b9c0Schristos
105e2b1b9c0Schristos #define SETUP_OFFSETS(name, var, default_offsets) \
1069742fdb4Schristos if ((name)->offsets != NULL) { \
107e2b1b9c0Schristos var = (name)->offsets; \
1089742fdb4Schristos } else { \
109e2b1b9c0Schristos var = (default_offsets); \
110e2b1b9c0Schristos set_offsets(name, var, NULL); \
111e2b1b9c0Schristos }
112e2b1b9c0Schristos
113e2b1b9c0Schristos /*%
114e2b1b9c0Schristos * Note: If additional attributes are added that should not be set for
115e2b1b9c0Schristos * empty names, MAKE_EMPTY() must be changed so it clears them.
116e2b1b9c0Schristos */
117e2b1b9c0Schristos #define MAKE_EMPTY(name) \
118e2b1b9c0Schristos do { \
119e2b1b9c0Schristos name->ndata = NULL; \
120e2b1b9c0Schristos name->length = 0; \
121e2b1b9c0Schristos name->labels = 0; \
122e2b1b9c0Schristos name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
123245a9365Srillig } while (0)
124e2b1b9c0Schristos
125e2b1b9c0Schristos /*%
126e2b1b9c0Schristos * A name is "bindable" if it can be set to point to a new value, i.e.
127e2b1b9c0Schristos * name->ndata and name->length may be changed.
128e2b1b9c0Schristos */
129e2b1b9c0Schristos #define BINDABLE(name) \
1309742fdb4Schristos ((name->attributes & \
1319742fdb4Schristos (DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC)) == 0)
132e2b1b9c0Schristos
133e2b1b9c0Schristos /*%
134e2b1b9c0Schristos * Note that the name data must be a char array, not a string
135e2b1b9c0Schristos * literal, to avoid compiler warnings about discarding
136e2b1b9c0Schristos * the const attribute of a string.
137e2b1b9c0Schristos */
138e2b1b9c0Schristos static unsigned char root_ndata[] = { "" };
139e2b1b9c0Schristos static unsigned char root_offsets[] = { 0 };
140e2b1b9c0Schristos
141e2b1b9c0Schristos static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets);
142e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_rootname = &root;
143e2b1b9c0Schristos
144e2b1b9c0Schristos static unsigned char wild_ndata[] = { "\001*" };
145e2b1b9c0Schristos static unsigned char wild_offsets[] = { 0 };
146e2b1b9c0Schristos
1479742fdb4Schristos static dns_name_t const wild = DNS_NAME_INITNONABSOLUTE(wild_ndata,
1489742fdb4Schristos wild_offsets);
149e2b1b9c0Schristos
150e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_wildcardname = &wild;
151e2b1b9c0Schristos
152e2b1b9c0Schristos /*
153e2b1b9c0Schristos * dns_name_t to text post-conversion procedure.
154e2b1b9c0Schristos */
1559742fdb4Schristos ISC_THREAD_LOCAL dns_name_totextfilter_t *totext_filter_proc = NULL;
156e2b1b9c0Schristos
157e2b1b9c0Schristos static void
158e2b1b9c0Schristos set_offsets(const dns_name_t *name, unsigned char *offsets,
159e2b1b9c0Schristos dns_name_t *set_name);
160e2b1b9c0Schristos
161e2b1b9c0Schristos void
dns_name_init(dns_name_t * name,unsigned char * offsets)162e2b1b9c0Schristos dns_name_init(dns_name_t *name, unsigned char *offsets) {
163e2b1b9c0Schristos /*
164e2b1b9c0Schristos * Initialize 'name'.
165e2b1b9c0Schristos */
166e2b1b9c0Schristos DNS_NAME_INIT(name, offsets);
167e2b1b9c0Schristos }
168e2b1b9c0Schristos
169e2b1b9c0Schristos void
dns_name_reset(dns_name_t * name)170e2b1b9c0Schristos dns_name_reset(dns_name_t *name) {
171e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
172e2b1b9c0Schristos REQUIRE(BINDABLE(name));
173e2b1b9c0Schristos
174e2b1b9c0Schristos DNS_NAME_RESET(name);
175e2b1b9c0Schristos }
176e2b1b9c0Schristos
177e2b1b9c0Schristos void
dns_name_invalidate(dns_name_t * name)178e2b1b9c0Schristos dns_name_invalidate(dns_name_t *name) {
179e2b1b9c0Schristos /*
180e2b1b9c0Schristos * Make 'name' invalid.
181e2b1b9c0Schristos */
182e2b1b9c0Schristos
183e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
184e2b1b9c0Schristos
185e2b1b9c0Schristos name->magic = 0;
186e2b1b9c0Schristos name->ndata = NULL;
187e2b1b9c0Schristos name->length = 0;
188e2b1b9c0Schristos name->labels = 0;
189e2b1b9c0Schristos name->attributes = 0;
190e2b1b9c0Schristos name->offsets = NULL;
191e2b1b9c0Schristos name->buffer = NULL;
192e2b1b9c0Schristos ISC_LINK_INIT(name, link);
193e2b1b9c0Schristos }
194e2b1b9c0Schristos
195f2e20987Schristos bool
dns_name_isvalid(const dns_name_t * name)196e2b1b9c0Schristos dns_name_isvalid(const dns_name_t *name) {
197e2b1b9c0Schristos unsigned char *ndata, *offsets;
198e2b1b9c0Schristos unsigned int offset, count, length, nlabels;
199e2b1b9c0Schristos
2009742fdb4Schristos if (!VALID_NAME(name)) {
201f2e20987Schristos return (false);
2029742fdb4Schristos }
203e2b1b9c0Schristos
2049742fdb4Schristos if (name->length > 255U || name->labels > 127U) {
205f2e20987Schristos return (false);
2069742fdb4Schristos }
207e2b1b9c0Schristos
208e2b1b9c0Schristos ndata = name->ndata;
209e2b1b9c0Schristos length = name->length;
210e2b1b9c0Schristos offsets = name->offsets;
211e2b1b9c0Schristos offset = 0;
212e2b1b9c0Schristos nlabels = 0;
213e2b1b9c0Schristos
214e2b1b9c0Schristos while (offset != length) {
215e2b1b9c0Schristos count = *ndata;
2169742fdb4Schristos if (count > 63U) {
217f2e20987Schristos return (false);
2189742fdb4Schristos }
2199742fdb4Schristos if (offsets != NULL && offsets[nlabels] != offset) {
220f2e20987Schristos return (false);
2219742fdb4Schristos }
222e2b1b9c0Schristos
223e2b1b9c0Schristos nlabels++;
224e2b1b9c0Schristos offset += count + 1;
225e2b1b9c0Schristos ndata += count + 1;
2269742fdb4Schristos if (offset > length) {
227f2e20987Schristos return (false);
228e2b1b9c0Schristos }
229e2b1b9c0Schristos
2309742fdb4Schristos if (count == 0) {
2319742fdb4Schristos break;
2329742fdb4Schristos }
2339742fdb4Schristos }
2349742fdb4Schristos
2359742fdb4Schristos if (nlabels != name->labels || offset != name->length) {
236f2e20987Schristos return (false);
2379742fdb4Schristos }
238e2b1b9c0Schristos
239f2e20987Schristos return (true);
240e2b1b9c0Schristos }
241e2b1b9c0Schristos
242e2b1b9c0Schristos void
dns_name_setbuffer(dns_name_t * name,isc_buffer_t * buffer)243e2b1b9c0Schristos dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
244e2b1b9c0Schristos /*
245e2b1b9c0Schristos * Dedicate a buffer for use with 'name'.
246e2b1b9c0Schristos */
247e2b1b9c0Schristos
248e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2499742fdb4Schristos REQUIRE((buffer != NULL && name->buffer == NULL) || (buffer == NULL));
250e2b1b9c0Schristos
251e2b1b9c0Schristos name->buffer = buffer;
252e2b1b9c0Schristos }
253e2b1b9c0Schristos
254f2e20987Schristos bool
dns_name_hasbuffer(const dns_name_t * name)255e2b1b9c0Schristos dns_name_hasbuffer(const dns_name_t *name) {
256e2b1b9c0Schristos /*
257e2b1b9c0Schristos * Does 'name' have a dedicated buffer?
258e2b1b9c0Schristos */
259e2b1b9c0Schristos
260e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
261e2b1b9c0Schristos
2629742fdb4Schristos if (name->buffer != NULL) {
263f2e20987Schristos return (true);
2649742fdb4Schristos }
265e2b1b9c0Schristos
266f2e20987Schristos return (false);
267e2b1b9c0Schristos }
268e2b1b9c0Schristos
269f2e20987Schristos bool
dns_name_isabsolute(const dns_name_t * name)270e2b1b9c0Schristos dns_name_isabsolute(const dns_name_t *name) {
271e2b1b9c0Schristos /*
272e2b1b9c0Schristos * Does 'name' end in the root label?
273e2b1b9c0Schristos */
274e2b1b9c0Schristos
275e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
276e2b1b9c0Schristos
2779742fdb4Schristos if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
278f2e20987Schristos return (true);
2799742fdb4Schristos }
280f2e20987Schristos return (false);
281e2b1b9c0Schristos }
282e2b1b9c0Schristos
283e2b1b9c0Schristos #define hyphenchar(c) ((c) == 0x2d)
284e2b1b9c0Schristos #define asterchar(c) ((c) == 0x2a)
2859742fdb4Schristos #define alphachar(c) \
2869742fdb4Schristos (((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a))
287e2b1b9c0Schristos #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
288e2b1b9c0Schristos #define borderchar(c) (alphachar(c) || digitchar(c))
289e2b1b9c0Schristos #define middlechar(c) (borderchar(c) || hyphenchar(c))
290e2b1b9c0Schristos #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
291e2b1b9c0Schristos
292f2e20987Schristos bool
dns_name_ismailbox(const dns_name_t * name)293e2b1b9c0Schristos dns_name_ismailbox(const dns_name_t *name) {
294e2b1b9c0Schristos unsigned char *ndata, ch;
295e2b1b9c0Schristos unsigned int n;
296f2e20987Schristos bool first;
297e2b1b9c0Schristos
298e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
299e2b1b9c0Schristos REQUIRE(name->labels > 0);
300e2b1b9c0Schristos REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
301e2b1b9c0Schristos
302e2b1b9c0Schristos /*
303e2b1b9c0Schristos * Root label.
304e2b1b9c0Schristos */
3059742fdb4Schristos if (name->length == 1) {
306f2e20987Schristos return (true);
3079742fdb4Schristos }
308e2b1b9c0Schristos
309e2b1b9c0Schristos ndata = name->ndata;
310e2b1b9c0Schristos n = *ndata++;
311e2b1b9c0Schristos INSIST(n <= 63);
312e2b1b9c0Schristos while (n--) {
313e2b1b9c0Schristos ch = *ndata++;
3149742fdb4Schristos if (!domainchar(ch)) {
315f2e20987Schristos return (false);
316e2b1b9c0Schristos }
3179742fdb4Schristos }
318e2b1b9c0Schristos
3199742fdb4Schristos if (ndata == name->ndata + name->length) {
320f2e20987Schristos return (false);
3219742fdb4Schristos }
322e2b1b9c0Schristos
323e2b1b9c0Schristos /*
3240377c12bSchristos * RFC952/RFC1123 hostname.
325e2b1b9c0Schristos */
326e2b1b9c0Schristos while (ndata < (name->ndata + name->length)) {
327e2b1b9c0Schristos n = *ndata++;
328e2b1b9c0Schristos INSIST(n <= 63);
329f2e20987Schristos first = true;
330e2b1b9c0Schristos while (n--) {
331e2b1b9c0Schristos ch = *ndata++;
332e2b1b9c0Schristos if (first || n == 0) {
3339742fdb4Schristos if (!borderchar(ch)) {
334f2e20987Schristos return (false);
3359742fdb4Schristos }
336e2b1b9c0Schristos } else {
3379742fdb4Schristos if (!middlechar(ch)) {
338f2e20987Schristos return (false);
339e2b1b9c0Schristos }
3409742fdb4Schristos }
341f2e20987Schristos first = false;
342e2b1b9c0Schristos }
343e2b1b9c0Schristos }
344f2e20987Schristos return (true);
345e2b1b9c0Schristos }
346e2b1b9c0Schristos
347f2e20987Schristos bool
dns_name_ishostname(const dns_name_t * name,bool wildcard)348f2e20987Schristos dns_name_ishostname(const dns_name_t *name, bool wildcard) {
349e2b1b9c0Schristos unsigned char *ndata, ch;
350e2b1b9c0Schristos unsigned int n;
351f2e20987Schristos bool first;
352e2b1b9c0Schristos
353e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
354e2b1b9c0Schristos REQUIRE(name->labels > 0);
355e2b1b9c0Schristos REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
356e2b1b9c0Schristos
357e2b1b9c0Schristos /*
358e2b1b9c0Schristos * Root label.
359e2b1b9c0Schristos */
3609742fdb4Schristos if (name->length == 1) {
361f2e20987Schristos return (true);
3629742fdb4Schristos }
363e2b1b9c0Schristos
364e2b1b9c0Schristos /*
365e2b1b9c0Schristos * Skip wildcard if this is a ownername.
366e2b1b9c0Schristos */
367e2b1b9c0Schristos ndata = name->ndata;
3689742fdb4Schristos if (wildcard && ndata[0] == 1 && ndata[1] == '*') {
369e2b1b9c0Schristos ndata += 2;
3709742fdb4Schristos }
371e2b1b9c0Schristos
372e2b1b9c0Schristos /*
373e2b1b9c0Schristos * RFC292/RFC1123 hostname.
374e2b1b9c0Schristos */
375e2b1b9c0Schristos while (ndata < (name->ndata + name->length)) {
376e2b1b9c0Schristos n = *ndata++;
377e2b1b9c0Schristos INSIST(n <= 63);
378f2e20987Schristos first = true;
379e2b1b9c0Schristos while (n--) {
380e2b1b9c0Schristos ch = *ndata++;
381e2b1b9c0Schristos if (first || n == 0) {
3829742fdb4Schristos if (!borderchar(ch)) {
383f2e20987Schristos return (false);
3849742fdb4Schristos }
385e2b1b9c0Schristos } else {
3869742fdb4Schristos if (!middlechar(ch)) {
387f2e20987Schristos return (false);
388e2b1b9c0Schristos }
3899742fdb4Schristos }
390f2e20987Schristos first = false;
391e2b1b9c0Schristos }
392e2b1b9c0Schristos }
393f2e20987Schristos return (true);
394e2b1b9c0Schristos }
395e2b1b9c0Schristos
396f2e20987Schristos bool
dns_name_iswildcard(const dns_name_t * name)397e2b1b9c0Schristos dns_name_iswildcard(const dns_name_t *name) {
398e2b1b9c0Schristos unsigned char *ndata;
399e2b1b9c0Schristos
400e2b1b9c0Schristos /*
401e2b1b9c0Schristos * Is 'name' a wildcard name?
402e2b1b9c0Schristos */
403e2b1b9c0Schristos
404e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
405e2b1b9c0Schristos REQUIRE(name->labels > 0);
406e2b1b9c0Schristos
407e2b1b9c0Schristos if (name->length >= 2) {
408e2b1b9c0Schristos ndata = name->ndata;
4099742fdb4Schristos if (ndata[0] == 1 && ndata[1] == '*') {
410f2e20987Schristos return (true);
411e2b1b9c0Schristos }
4129742fdb4Schristos }
413e2b1b9c0Schristos
414f2e20987Schristos return (false);
415e2b1b9c0Schristos }
416e2b1b9c0Schristos
417f2e20987Schristos bool
dns_name_internalwildcard(const dns_name_t * name)418e2b1b9c0Schristos dns_name_internalwildcard(const dns_name_t *name) {
419e2b1b9c0Schristos unsigned char *ndata;
420e2b1b9c0Schristos unsigned int count;
421e2b1b9c0Schristos unsigned int label;
422e2b1b9c0Schristos
423e2b1b9c0Schristos /*
424e2b1b9c0Schristos * Does 'name' contain a internal wildcard?
425e2b1b9c0Schristos */
426e2b1b9c0Schristos
427e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
428e2b1b9c0Schristos REQUIRE(name->labels > 0);
429e2b1b9c0Schristos
430e2b1b9c0Schristos /*
431e2b1b9c0Schristos * Skip first label.
432e2b1b9c0Schristos */
433e2b1b9c0Schristos ndata = name->ndata;
434e2b1b9c0Schristos count = *ndata++;
435e2b1b9c0Schristos INSIST(count <= 63);
436e2b1b9c0Schristos ndata += count;
437e2b1b9c0Schristos label = 1;
438e2b1b9c0Schristos /*
439e2b1b9c0Schristos * Check all but the last of the remaining labels.
440e2b1b9c0Schristos */
441e2b1b9c0Schristos while (label + 1 < name->labels) {
442e2b1b9c0Schristos count = *ndata++;
443e2b1b9c0Schristos INSIST(count <= 63);
4449742fdb4Schristos if (count == 1 && *ndata == '*') {
445f2e20987Schristos return (true);
4469742fdb4Schristos }
447e2b1b9c0Schristos ndata += count;
448e2b1b9c0Schristos label++;
449e2b1b9c0Schristos }
450f2e20987Schristos return (false);
451e2b1b9c0Schristos }
452e2b1b9c0Schristos
453e2b1b9c0Schristos unsigned int
dns_name_hash(const dns_name_t * name,bool case_sensitive)454f2e20987Schristos dns_name_hash(const dns_name_t *name, bool case_sensitive) {
455e2b1b9c0Schristos unsigned int length;
456e2b1b9c0Schristos
457e2b1b9c0Schristos /*
458e2b1b9c0Schristos * Provide a hash value for 'name'.
459e2b1b9c0Schristos */
460e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
461e2b1b9c0Schristos
4629ad14dd7Schristos if (name->labels == 0) {
463e2b1b9c0Schristos return (0);
4649ad14dd7Schristos }
465e2b1b9c0Schristos
466e2b1b9c0Schristos length = name->length;
4679ad14dd7Schristos if (length > 16) {
468e2b1b9c0Schristos length = 16;
4699ad14dd7Schristos }
470e2b1b9c0Schristos
47173584a28Schristos /* High bits are more random. */
47273584a28Schristos return (isc_hash32(name->ndata, length, case_sensitive));
473e2b1b9c0Schristos }
474e2b1b9c0Schristos
475e2b1b9c0Schristos unsigned int
dns_name_fullhash(const dns_name_t * name,bool case_sensitive)476f2e20987Schristos dns_name_fullhash(const dns_name_t *name, bool case_sensitive) {
477e2b1b9c0Schristos /*
478e2b1b9c0Schristos * Provide a hash value for 'name'.
479e2b1b9c0Schristos */
480e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
481e2b1b9c0Schristos
4829ad14dd7Schristos if (name->labels == 0) {
483e2b1b9c0Schristos return (0);
4849ad14dd7Schristos }
485e2b1b9c0Schristos
48673584a28Schristos /* High bits are more random. */
48773584a28Schristos return (isc_hash32(name->ndata, name->length, case_sensitive));
488e2b1b9c0Schristos }
489e2b1b9c0Schristos
490e2b1b9c0Schristos dns_namereln_t
dns_name_fullcompare(const dns_name_t * name1,const dns_name_t * name2,int * orderp,unsigned int * nlabelsp)491e2b1b9c0Schristos dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
4929742fdb4Schristos int *orderp, unsigned int *nlabelsp) {
493e2b1b9c0Schristos unsigned int l1, l2, l, count1, count2, count, nlabels;
494e2b1b9c0Schristos int cdiff, ldiff, chdiff;
495e2b1b9c0Schristos unsigned char *label1, *label2;
496e2b1b9c0Schristos unsigned char *offsets1, *offsets2;
497e2b1b9c0Schristos dns_offsets_t odata1, odata2;
498e2b1b9c0Schristos dns_namereln_t namereln = dns_namereln_none;
499e2b1b9c0Schristos
500e2b1b9c0Schristos /*
501e2b1b9c0Schristos * Determine the relative ordering under the DNSSEC order relation of
502e2b1b9c0Schristos * 'name1' and 'name2', and also determine the hierarchical
503e2b1b9c0Schristos * relationship of the names.
504e2b1b9c0Schristos *
505e2b1b9c0Schristos * Note: It makes no sense for one of the names to be relative and the
506e2b1b9c0Schristos * other absolute. If both names are relative, then to be meaningfully
507e2b1b9c0Schristos * compared the caller must ensure that they are both relative to the
508e2b1b9c0Schristos * same domain.
509e2b1b9c0Schristos */
510e2b1b9c0Schristos
511e2b1b9c0Schristos REQUIRE(VALID_NAME(name1));
512e2b1b9c0Schristos REQUIRE(VALID_NAME(name2));
513e2b1b9c0Schristos REQUIRE(orderp != NULL);
514e2b1b9c0Schristos REQUIRE(nlabelsp != NULL);
515e2b1b9c0Schristos /*
516e2b1b9c0Schristos * Either name1 is absolute and name2 is absolute, or neither is.
517e2b1b9c0Schristos */
518e2b1b9c0Schristos REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
519e2b1b9c0Schristos (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
520e2b1b9c0Schristos
521e2b1b9c0Schristos if (ISC_UNLIKELY(name1 == name2)) {
522e2b1b9c0Schristos *orderp = 0;
523e2b1b9c0Schristos *nlabelsp = name1->labels;
524e2b1b9c0Schristos return (dns_namereln_equal);
525e2b1b9c0Schristos }
526e2b1b9c0Schristos
527e2b1b9c0Schristos SETUP_OFFSETS(name1, offsets1, odata1);
528e2b1b9c0Schristos SETUP_OFFSETS(name2, offsets2, odata2);
529e2b1b9c0Schristos
530e2b1b9c0Schristos nlabels = 0;
531e2b1b9c0Schristos l1 = name1->labels;
532e2b1b9c0Schristos l2 = name2->labels;
533e2b1b9c0Schristos if (l2 > l1) {
534e2b1b9c0Schristos l = l1;
535e2b1b9c0Schristos ldiff = 0 - (l2 - l1);
536e2b1b9c0Schristos } else {
537e2b1b9c0Schristos l = l2;
538e2b1b9c0Schristos ldiff = l1 - l2;
539e2b1b9c0Schristos }
540e2b1b9c0Schristos
541e2b1b9c0Schristos offsets1 += l1;
542e2b1b9c0Schristos offsets2 += l2;
543e2b1b9c0Schristos
544e2b1b9c0Schristos while (ISC_LIKELY(l > 0)) {
545e2b1b9c0Schristos l--;
546e2b1b9c0Schristos offsets1--;
547e2b1b9c0Schristos offsets2--;
548e2b1b9c0Schristos label1 = &name1->ndata[*offsets1];
549e2b1b9c0Schristos label2 = &name2->ndata[*offsets2];
550e2b1b9c0Schristos count1 = *label1++;
551e2b1b9c0Schristos count2 = *label2++;
552e2b1b9c0Schristos
553e2b1b9c0Schristos /*
554e2b1b9c0Schristos * We dropped bitstring labels, and we don't support any
555e2b1b9c0Schristos * other extended label types.
556e2b1b9c0Schristos */
557e2b1b9c0Schristos INSIST(count1 <= 63 && count2 <= 63);
558e2b1b9c0Schristos
559e2b1b9c0Schristos cdiff = (int)count1 - (int)count2;
5609742fdb4Schristos if (cdiff < 0) {
561e2b1b9c0Schristos count = count1;
5629742fdb4Schristos } else {
563e2b1b9c0Schristos count = count2;
5649742fdb4Schristos }
565e2b1b9c0Schristos
566e2b1b9c0Schristos /* Loop unrolled for performance */
567e2b1b9c0Schristos while (ISC_LIKELY(count > 3)) {
568e2b1b9c0Schristos chdiff = (int)maptolower[label1[0]] -
569e2b1b9c0Schristos (int)maptolower[label2[0]];
570e2b1b9c0Schristos if (chdiff != 0) {
571e2b1b9c0Schristos *orderp = chdiff;
572e2b1b9c0Schristos goto done;
573e2b1b9c0Schristos }
574e2b1b9c0Schristos chdiff = (int)maptolower[label1[1]] -
575e2b1b9c0Schristos (int)maptolower[label2[1]];
576e2b1b9c0Schristos if (chdiff != 0) {
577e2b1b9c0Schristos *orderp = chdiff;
578e2b1b9c0Schristos goto done;
579e2b1b9c0Schristos }
580e2b1b9c0Schristos chdiff = (int)maptolower[label1[2]] -
581e2b1b9c0Schristos (int)maptolower[label2[2]];
582e2b1b9c0Schristos if (chdiff != 0) {
583e2b1b9c0Schristos *orderp = chdiff;
584e2b1b9c0Schristos goto done;
585e2b1b9c0Schristos }
586e2b1b9c0Schristos chdiff = (int)maptolower[label1[3]] -
587e2b1b9c0Schristos (int)maptolower[label2[3]];
588e2b1b9c0Schristos if (chdiff != 0) {
589e2b1b9c0Schristos *orderp = chdiff;
590e2b1b9c0Schristos goto done;
591e2b1b9c0Schristos }
592e2b1b9c0Schristos count -= 4;
593e2b1b9c0Schristos label1 += 4;
594e2b1b9c0Schristos label2 += 4;
595e2b1b9c0Schristos }
596e2b1b9c0Schristos while (ISC_LIKELY(count-- > 0)) {
597e2b1b9c0Schristos chdiff = (int)maptolower[*label1++] -
598e2b1b9c0Schristos (int)maptolower[*label2++];
599e2b1b9c0Schristos if (chdiff != 0) {
600e2b1b9c0Schristos *orderp = chdiff;
601e2b1b9c0Schristos goto done;
602e2b1b9c0Schristos }
603e2b1b9c0Schristos }
604e2b1b9c0Schristos if (cdiff != 0) {
605e2b1b9c0Schristos *orderp = cdiff;
606e2b1b9c0Schristos goto done;
607e2b1b9c0Schristos }
608e2b1b9c0Schristos nlabels++;
609e2b1b9c0Schristos }
610e2b1b9c0Schristos
611e2b1b9c0Schristos *orderp = ldiff;
6129742fdb4Schristos if (ldiff < 0) {
613e2b1b9c0Schristos namereln = dns_namereln_contains;
6149742fdb4Schristos } else if (ldiff > 0) {
615e2b1b9c0Schristos namereln = dns_namereln_subdomain;
6169742fdb4Schristos } else {
617e2b1b9c0Schristos namereln = dns_namereln_equal;
6189742fdb4Schristos }
619e2b1b9c0Schristos *nlabelsp = nlabels;
620e2b1b9c0Schristos return (namereln);
621e2b1b9c0Schristos
622e2b1b9c0Schristos done:
623e2b1b9c0Schristos *nlabelsp = nlabels;
6249742fdb4Schristos if (nlabels > 0) {
625e2b1b9c0Schristos namereln = dns_namereln_commonancestor;
6269742fdb4Schristos }
627e2b1b9c0Schristos
628e2b1b9c0Schristos return (namereln);
629e2b1b9c0Schristos }
630e2b1b9c0Schristos
631e2b1b9c0Schristos int
dns_name_compare(const dns_name_t * name1,const dns_name_t * name2)632e2b1b9c0Schristos dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
633e2b1b9c0Schristos int order;
634e2b1b9c0Schristos unsigned int nlabels;
635e2b1b9c0Schristos
636e2b1b9c0Schristos /*
637e2b1b9c0Schristos * Determine the relative ordering under the DNSSEC order relation of
638e2b1b9c0Schristos * 'name1' and 'name2'.
639e2b1b9c0Schristos *
640e2b1b9c0Schristos * Note: It makes no sense for one of the names to be relative and the
641e2b1b9c0Schristos * other absolute. If both names are relative, then to be meaningfully
642e2b1b9c0Schristos * compared the caller must ensure that they are both relative to the
643e2b1b9c0Schristos * same domain.
644e2b1b9c0Schristos */
645e2b1b9c0Schristos
646e2b1b9c0Schristos (void)dns_name_fullcompare(name1, name2, &order, &nlabels);
647e2b1b9c0Schristos
648e2b1b9c0Schristos return (order);
649e2b1b9c0Schristos }
650e2b1b9c0Schristos
651f2e20987Schristos bool
dns_name_equal(const dns_name_t * name1,const dns_name_t * name2)652e2b1b9c0Schristos dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
653e2b1b9c0Schristos unsigned int l, count;
654e2b1b9c0Schristos unsigned char c;
655e2b1b9c0Schristos unsigned char *label1, *label2;
656e2b1b9c0Schristos
657e2b1b9c0Schristos /*
658e2b1b9c0Schristos * Are 'name1' and 'name2' equal?
659e2b1b9c0Schristos *
660e2b1b9c0Schristos * Note: It makes no sense for one of the names to be relative and the
661e2b1b9c0Schristos * other absolute. If both names are relative, then to be meaningfully
662e2b1b9c0Schristos * compared the caller must ensure that they are both relative to the
663e2b1b9c0Schristos * same domain.
664e2b1b9c0Schristos */
665e2b1b9c0Schristos
666e2b1b9c0Schristos REQUIRE(VALID_NAME(name1));
667e2b1b9c0Schristos REQUIRE(VALID_NAME(name2));
668e2b1b9c0Schristos /*
669e2b1b9c0Schristos * Either name1 is absolute and name2 is absolute, or neither is.
670e2b1b9c0Schristos */
671e2b1b9c0Schristos REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
672e2b1b9c0Schristos (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
673e2b1b9c0Schristos
6749742fdb4Schristos if (ISC_UNLIKELY(name1 == name2)) {
675f2e20987Schristos return (true);
6769742fdb4Schristos }
677e2b1b9c0Schristos
6789742fdb4Schristos if (name1->length != name2->length) {
679f2e20987Schristos return (false);
6809742fdb4Schristos }
681e2b1b9c0Schristos
682e2b1b9c0Schristos l = name1->labels;
683e2b1b9c0Schristos
6849742fdb4Schristos if (l != name2->labels) {
685f2e20987Schristos return (false);
6869742fdb4Schristos }
687e2b1b9c0Schristos
688e2b1b9c0Schristos label1 = name1->ndata;
689e2b1b9c0Schristos label2 = name2->ndata;
690e2b1b9c0Schristos while (ISC_LIKELY(l-- > 0)) {
691e2b1b9c0Schristos count = *label1++;
6929742fdb4Schristos if (count != *label2++) {
693f2e20987Schristos return (false);
6949742fdb4Schristos }
695e2b1b9c0Schristos
696e2b1b9c0Schristos INSIST(count <= 63); /* no bitstring support */
697e2b1b9c0Schristos
698e2b1b9c0Schristos /* Loop unrolled for performance */
699e2b1b9c0Schristos while (ISC_LIKELY(count > 3)) {
700e2b1b9c0Schristos c = maptolower[label1[0]];
7019742fdb4Schristos if (c != maptolower[label2[0]]) {
702f2e20987Schristos return (false);
7039742fdb4Schristos }
704e2b1b9c0Schristos c = maptolower[label1[1]];
7059742fdb4Schristos if (c != maptolower[label2[1]]) {
706f2e20987Schristos return (false);
7079742fdb4Schristos }
708e2b1b9c0Schristos c = maptolower[label1[2]];
7099742fdb4Schristos if (c != maptolower[label2[2]]) {
710f2e20987Schristos return (false);
7119742fdb4Schristos }
712e2b1b9c0Schristos c = maptolower[label1[3]];
7139742fdb4Schristos if (c != maptolower[label2[3]]) {
714f2e20987Schristos return (false);
7159742fdb4Schristos }
716e2b1b9c0Schristos count -= 4;
717e2b1b9c0Schristos label1 += 4;
718e2b1b9c0Schristos label2 += 4;
719e2b1b9c0Schristos }
720e2b1b9c0Schristos while (ISC_LIKELY(count-- > 0)) {
721e2b1b9c0Schristos c = maptolower[*label1++];
7229742fdb4Schristos if (c != maptolower[*label2++]) {
723f2e20987Schristos return (false);
724e2b1b9c0Schristos }
725e2b1b9c0Schristos }
7269742fdb4Schristos }
727e2b1b9c0Schristos
728f2e20987Schristos return (true);
729e2b1b9c0Schristos }
730e2b1b9c0Schristos
731f2e20987Schristos bool
dns_name_caseequal(const dns_name_t * name1,const dns_name_t * name2)732e2b1b9c0Schristos dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
733e2b1b9c0Schristos /*
734e2b1b9c0Schristos * Are 'name1' and 'name2' equal?
735e2b1b9c0Schristos *
736e2b1b9c0Schristos * Note: It makes no sense for one of the names to be relative and the
737e2b1b9c0Schristos * other absolute. If both names are relative, then to be meaningfully
738e2b1b9c0Schristos * compared the caller must ensure that they are both relative to the
739e2b1b9c0Schristos * same domain.
740e2b1b9c0Schristos */
741e2b1b9c0Schristos
742e2b1b9c0Schristos REQUIRE(VALID_NAME(name1));
743e2b1b9c0Schristos REQUIRE(VALID_NAME(name2));
744e2b1b9c0Schristos /*
745e2b1b9c0Schristos * Either name1 is absolute and name2 is absolute, or neither is.
746e2b1b9c0Schristos */
747e2b1b9c0Schristos REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
748e2b1b9c0Schristos (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
749e2b1b9c0Schristos
7509742fdb4Schristos if (name1->length != name2->length) {
751f2e20987Schristos return (false);
7529742fdb4Schristos }
753e2b1b9c0Schristos
7549742fdb4Schristos if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) {
755f2e20987Schristos return (false);
7569742fdb4Schristos }
757e2b1b9c0Schristos
758f2e20987Schristos return (true);
759e2b1b9c0Schristos }
760e2b1b9c0Schristos
761e2b1b9c0Schristos int
dns_name_rdatacompare(const dns_name_t * name1,const dns_name_t * name2)762e2b1b9c0Schristos dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
763e2b1b9c0Schristos unsigned int l1, l2, l, count1, count2, count;
764e2b1b9c0Schristos unsigned char c1, c2;
765e2b1b9c0Schristos unsigned char *label1, *label2;
766e2b1b9c0Schristos
767e2b1b9c0Schristos /*
768e2b1b9c0Schristos * Compare two absolute names as rdata.
769e2b1b9c0Schristos */
770e2b1b9c0Schristos
771e2b1b9c0Schristos REQUIRE(VALID_NAME(name1));
772e2b1b9c0Schristos REQUIRE(name1->labels > 0);
773e2b1b9c0Schristos REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
774e2b1b9c0Schristos REQUIRE(VALID_NAME(name2));
775e2b1b9c0Schristos REQUIRE(name2->labels > 0);
776e2b1b9c0Schristos REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
777e2b1b9c0Schristos
778e2b1b9c0Schristos l1 = name1->labels;
779e2b1b9c0Schristos l2 = name2->labels;
780e2b1b9c0Schristos
781e2b1b9c0Schristos l = (l1 < l2) ? l1 : l2;
782e2b1b9c0Schristos
783e2b1b9c0Schristos label1 = name1->ndata;
784e2b1b9c0Schristos label2 = name2->ndata;
785e2b1b9c0Schristos while (l > 0) {
786e2b1b9c0Schristos l--;
787e2b1b9c0Schristos count1 = *label1++;
788e2b1b9c0Schristos count2 = *label2++;
789e2b1b9c0Schristos
790e2b1b9c0Schristos /* no bitstring support */
791e2b1b9c0Schristos INSIST(count1 <= 63 && count2 <= 63);
792e2b1b9c0Schristos
7939742fdb4Schristos if (count1 != count2) {
794e2b1b9c0Schristos return ((count1 < count2) ? -1 : 1);
7959742fdb4Schristos }
796e2b1b9c0Schristos count = count1;
797e2b1b9c0Schristos while (count > 0) {
798e2b1b9c0Schristos count--;
799e2b1b9c0Schristos c1 = maptolower[*label1++];
800e2b1b9c0Schristos c2 = maptolower[*label2++];
8019742fdb4Schristos if (c1 < c2) {
802e2b1b9c0Schristos return (-1);
8039742fdb4Schristos } else if (c1 > c2) {
804e2b1b9c0Schristos return (1);
805e2b1b9c0Schristos }
806e2b1b9c0Schristos }
8079742fdb4Schristos }
808e2b1b9c0Schristos
809e2b1b9c0Schristos /*
810e2b1b9c0Schristos * If one name had more labels than the other, their common
811e2b1b9c0Schristos * prefix must have been different because the shorter name
812e2b1b9c0Schristos * ended with the root label and the longer one can't have
813e2b1b9c0Schristos * a root label in the middle of it. Therefore, if we get
814e2b1b9c0Schristos * to this point, the lengths must be equal.
815e2b1b9c0Schristos */
816e2b1b9c0Schristos INSIST(l1 == l2);
817e2b1b9c0Schristos
818e2b1b9c0Schristos return (0);
819e2b1b9c0Schristos }
820e2b1b9c0Schristos
821f2e20987Schristos bool
dns_name_issubdomain(const dns_name_t * name1,const dns_name_t * name2)822e2b1b9c0Schristos dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
823e2b1b9c0Schristos int order;
824e2b1b9c0Schristos unsigned int nlabels;
825e2b1b9c0Schristos dns_namereln_t namereln;
826e2b1b9c0Schristos
827e2b1b9c0Schristos /*
828e2b1b9c0Schristos * Is 'name1' a subdomain of 'name2'?
829e2b1b9c0Schristos *
830e2b1b9c0Schristos * Note: It makes no sense for one of the names to be relative and the
831e2b1b9c0Schristos * other absolute. If both names are relative, then to be meaningfully
832e2b1b9c0Schristos * compared the caller must ensure that they are both relative to the
833e2b1b9c0Schristos * same domain.
834e2b1b9c0Schristos */
835e2b1b9c0Schristos
836e2b1b9c0Schristos namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
837e2b1b9c0Schristos if (namereln == dns_namereln_subdomain ||
838*4ac1c27eSchristos namereln == dns_namereln_equal)
839*4ac1c27eSchristos {
840f2e20987Schristos return (true);
8419742fdb4Schristos }
842e2b1b9c0Schristos
843f2e20987Schristos return (false);
844e2b1b9c0Schristos }
845e2b1b9c0Schristos
846f2e20987Schristos bool
dns_name_matcheswildcard(const dns_name_t * name,const dns_name_t * wname)847e2b1b9c0Schristos dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
848e2b1b9c0Schristos int order;
849e2b1b9c0Schristos unsigned int nlabels, labels;
850e2b1b9c0Schristos dns_name_t tname;
851e2b1b9c0Schristos
852e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
853e2b1b9c0Schristos REQUIRE(name->labels > 0);
854e2b1b9c0Schristos REQUIRE(VALID_NAME(wname));
855e2b1b9c0Schristos labels = wname->labels;
856e2b1b9c0Schristos REQUIRE(labels > 0);
857e2b1b9c0Schristos REQUIRE(dns_name_iswildcard(wname));
858e2b1b9c0Schristos
859e2b1b9c0Schristos DNS_NAME_INIT(&tname, NULL);
860e2b1b9c0Schristos dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
861e2b1b9c0Schristos if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
862e2b1b9c0Schristos dns_namereln_subdomain)
8639742fdb4Schristos {
864f2e20987Schristos return (true);
8659742fdb4Schristos }
866f2e20987Schristos return (false);
867e2b1b9c0Schristos }
868e2b1b9c0Schristos
869e2b1b9c0Schristos unsigned int
dns_name_countlabels(const dns_name_t * name)870e2b1b9c0Schristos dns_name_countlabels(const dns_name_t *name) {
871e2b1b9c0Schristos /*
872e2b1b9c0Schristos * How many labels does 'name' have?
873e2b1b9c0Schristos */
874e2b1b9c0Schristos
875e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
876e2b1b9c0Schristos
877e2b1b9c0Schristos ENSURE(name->labels <= 128);
878e2b1b9c0Schristos
879e2b1b9c0Schristos return (name->labels);
880e2b1b9c0Schristos }
881e2b1b9c0Schristos
882e2b1b9c0Schristos void
dns_name_getlabel(const dns_name_t * name,unsigned int n,dns_label_t * label)883e2b1b9c0Schristos dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
884e2b1b9c0Schristos unsigned char *offsets;
885e2b1b9c0Schristos dns_offsets_t odata;
886e2b1b9c0Schristos
887e2b1b9c0Schristos /*
888e2b1b9c0Schristos * Make 'label' refer to the 'n'th least significant label of 'name'.
889e2b1b9c0Schristos */
890e2b1b9c0Schristos
891e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
892e2b1b9c0Schristos REQUIRE(name->labels > 0);
893e2b1b9c0Schristos REQUIRE(n < name->labels);
894e2b1b9c0Schristos REQUIRE(label != NULL);
895e2b1b9c0Schristos
896e2b1b9c0Schristos SETUP_OFFSETS(name, offsets, odata);
897e2b1b9c0Schristos
898e2b1b9c0Schristos label->base = &name->ndata[offsets[n]];
8999742fdb4Schristos if (n == name->labels - 1) {
900e2b1b9c0Schristos label->length = name->length - offsets[n];
9019742fdb4Schristos } else {
902e2b1b9c0Schristos label->length = offsets[n + 1] - offsets[n];
903e2b1b9c0Schristos }
9049742fdb4Schristos }
905e2b1b9c0Schristos
906e2b1b9c0Schristos void
dns_name_getlabelsequence(const dns_name_t * source,unsigned int first,unsigned int n,dns_name_t * target)9079742fdb4Schristos dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
9089742fdb4Schristos unsigned int n, dns_name_t *target) {
909e2b1b9c0Schristos unsigned char *p, l;
910e2b1b9c0Schristos unsigned int firstoffset, endoffset;
911e2b1b9c0Schristos unsigned int i;
912e2b1b9c0Schristos
913e2b1b9c0Schristos /*
914e2b1b9c0Schristos * Make 'target' refer to the 'n' labels including and following
915e2b1b9c0Schristos * 'first' in 'source'.
916e2b1b9c0Schristos */
917e2b1b9c0Schristos
918e2b1b9c0Schristos REQUIRE(VALID_NAME(source));
919e2b1b9c0Schristos REQUIRE(VALID_NAME(target));
920e2b1b9c0Schristos REQUIRE(first <= source->labels);
921e2b1b9c0Schristos REQUIRE(n <= source->labels - first); /* note first+n could overflow */
922e2b1b9c0Schristos REQUIRE(BINDABLE(target));
923e2b1b9c0Schristos
924e2b1b9c0Schristos p = source->ndata;
925e2b1b9c0Schristos if (ISC_UNLIKELY(first == source->labels)) {
926e2b1b9c0Schristos firstoffset = source->length;
927e2b1b9c0Schristos } else {
928e2b1b9c0Schristos for (i = 0; i < first; i++) {
929e2b1b9c0Schristos l = *p;
930e2b1b9c0Schristos p += l + 1;
931e2b1b9c0Schristos }
932e2b1b9c0Schristos firstoffset = (unsigned int)(p - source->ndata);
933e2b1b9c0Schristos }
934e2b1b9c0Schristos
9359742fdb4Schristos if (ISC_LIKELY(first + n == source->labels)) {
936e2b1b9c0Schristos endoffset = source->length;
9379742fdb4Schristos } else {
938e2b1b9c0Schristos for (i = 0; i < n; i++) {
939e2b1b9c0Schristos l = *p;
940e2b1b9c0Schristos p += l + 1;
941e2b1b9c0Schristos }
942e2b1b9c0Schristos endoffset = (unsigned int)(p - source->ndata);
943e2b1b9c0Schristos }
944e2b1b9c0Schristos
945e2b1b9c0Schristos target->ndata = &source->ndata[firstoffset];
946e2b1b9c0Schristos target->length = endoffset - firstoffset;
947e2b1b9c0Schristos
948e2b1b9c0Schristos if (first + n == source->labels && n > 0 &&
949e2b1b9c0Schristos (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
9509742fdb4Schristos {
951e2b1b9c0Schristos target->attributes |= DNS_NAMEATTR_ABSOLUTE;
9529742fdb4Schristos } else {
953e2b1b9c0Schristos target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
9549742fdb4Schristos }
955e2b1b9c0Schristos
956e2b1b9c0Schristos target->labels = n;
957e2b1b9c0Schristos
958e2b1b9c0Schristos /*
959e2b1b9c0Schristos * If source and target are the same, and we're making target
960e2b1b9c0Schristos * a prefix of source, the offsets table is correct already
961e2b1b9c0Schristos * so we don't need to call set_offsets().
962e2b1b9c0Schristos */
9639742fdb4Schristos if (target->offsets != NULL && (target != source || first != 0)) {
964e2b1b9c0Schristos set_offsets(target, target->offsets, NULL);
965e2b1b9c0Schristos }
9669742fdb4Schristos }
967e2b1b9c0Schristos
968e2b1b9c0Schristos void
dns_name_clone(const dns_name_t * source,dns_name_t * target)969e2b1b9c0Schristos dns_name_clone(const dns_name_t *source, dns_name_t *target) {
970e2b1b9c0Schristos /*
971e2b1b9c0Schristos * Make 'target' refer to the same name as 'source'.
972e2b1b9c0Schristos */
973e2b1b9c0Schristos
974e2b1b9c0Schristos REQUIRE(VALID_NAME(source));
975e2b1b9c0Schristos REQUIRE(VALID_NAME(target));
976e2b1b9c0Schristos REQUIRE(BINDABLE(target));
977e2b1b9c0Schristos
978e2b1b9c0Schristos target->ndata = source->ndata;
979e2b1b9c0Schristos target->length = source->length;
980e2b1b9c0Schristos target->labels = source->labels;
981e2b1b9c0Schristos target->attributes = source->attributes &
9829742fdb4Schristos (unsigned int)~(DNS_NAMEATTR_READONLY |
9839742fdb4Schristos DNS_NAMEATTR_DYNAMIC |
984e2b1b9c0Schristos DNS_NAMEATTR_DYNOFFSETS);
985e2b1b9c0Schristos if (target->offsets != NULL && source->labels > 0) {
9869742fdb4Schristos if (source->offsets != NULL) {
987e2b1b9c0Schristos memmove(target->offsets, source->offsets,
988e2b1b9c0Schristos source->labels);
9899742fdb4Schristos } else {
990e2b1b9c0Schristos set_offsets(target, target->offsets, NULL);
991e2b1b9c0Schristos }
992e2b1b9c0Schristos }
9939742fdb4Schristos }
994e2b1b9c0Schristos
995e2b1b9c0Schristos void
dns_name_fromregion(dns_name_t * name,const isc_region_t * r)996e2b1b9c0Schristos dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
997e2b1b9c0Schristos unsigned char *offsets;
998e2b1b9c0Schristos dns_offsets_t odata;
999e2b1b9c0Schristos unsigned int len;
1000e2b1b9c0Schristos isc_region_t r2;
1001e2b1b9c0Schristos
1002e2b1b9c0Schristos /*
1003e2b1b9c0Schristos * Make 'name' refer to region 'r'.
1004e2b1b9c0Schristos */
1005e2b1b9c0Schristos
1006e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1007e2b1b9c0Schristos REQUIRE(r != NULL);
1008e2b1b9c0Schristos REQUIRE(BINDABLE(name));
1009e2b1b9c0Schristos
1010e2b1b9c0Schristos INIT_OFFSETS(name, offsets, odata);
1011e2b1b9c0Schristos
1012e2b1b9c0Schristos if (name->buffer != NULL) {
1013e2b1b9c0Schristos isc_buffer_clear(name->buffer);
1014e2b1b9c0Schristos isc_buffer_availableregion(name->buffer, &r2);
1015e2b1b9c0Schristos len = (r->length < r2.length) ? r->length : r2.length;
10169742fdb4Schristos if (len > DNS_NAME_MAXWIRE) {
1017e2b1b9c0Schristos len = DNS_NAME_MAXWIRE;
10189742fdb4Schristos }
10199742fdb4Schristos if (len != 0) {
1020e2b1b9c0Schristos memmove(r2.base, r->base, len);
10219742fdb4Schristos }
1022e2b1b9c0Schristos name->ndata = r2.base;
1023e2b1b9c0Schristos name->length = len;
1024e2b1b9c0Schristos } else {
1025e2b1b9c0Schristos name->ndata = r->base;
10269742fdb4Schristos name->length = (r->length <= DNS_NAME_MAXWIRE)
10279742fdb4Schristos ? r->length
10289742fdb4Schristos : DNS_NAME_MAXWIRE;
1029e2b1b9c0Schristos }
1030e2b1b9c0Schristos
10319742fdb4Schristos if (r->length > 0) {
1032e2b1b9c0Schristos set_offsets(name, offsets, name);
10339742fdb4Schristos } else {
1034e2b1b9c0Schristos name->labels = 0;
1035e2b1b9c0Schristos name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1036e2b1b9c0Schristos }
1037e2b1b9c0Schristos
10389742fdb4Schristos if (name->buffer != NULL) {
1039e2b1b9c0Schristos isc_buffer_add(name->buffer, name->length);
1040e2b1b9c0Schristos }
10419742fdb4Schristos }
1042e2b1b9c0Schristos
1043e2b1b9c0Schristos void
dns_name_toregion(const dns_name_t * name,isc_region_t * r)1044e2b1b9c0Schristos dns_name_toregion(const dns_name_t *name, isc_region_t *r) {
1045e2b1b9c0Schristos /*
1046e2b1b9c0Schristos * Make 'r' refer to 'name'.
1047e2b1b9c0Schristos */
1048e2b1b9c0Schristos
1049e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1050e2b1b9c0Schristos REQUIRE(r != NULL);
1051e2b1b9c0Schristos
1052e2b1b9c0Schristos DNS_NAME_TOREGION(name, r);
1053e2b1b9c0Schristos }
1054e2b1b9c0Schristos
1055e2b1b9c0Schristos isc_result_t
dns_name_fromtext(dns_name_t * name,isc_buffer_t * source,const dns_name_t * origin,unsigned int options,isc_buffer_t * target)1056e2b1b9c0Schristos dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
1057e2b1b9c0Schristos const dns_name_t *origin, unsigned int options,
10589742fdb4Schristos isc_buffer_t *target) {
1059e2b1b9c0Schristos unsigned char *ndata, *label = NULL;
1060e2b1b9c0Schristos char *tdata;
1061e2b1b9c0Schristos char c;
1062e2b1b9c0Schristos ft_state state;
1063e2b1b9c0Schristos unsigned int value = 0, count = 0;
1064e2b1b9c0Schristos unsigned int n1 = 0, n2 = 0;
1065e2b1b9c0Schristos unsigned int tlen, nrem, nused, digits = 0, labels, tused;
1066f2e20987Schristos bool done;
1067e2b1b9c0Schristos unsigned char *offsets;
1068e2b1b9c0Schristos dns_offsets_t odata;
1069f2e20987Schristos bool downcase;
1070e2b1b9c0Schristos
1071e2b1b9c0Schristos /*
1072e2b1b9c0Schristos * Convert the textual representation of a DNS name at source
1073e2b1b9c0Schristos * into uncompressed wire form stored in target.
1074e2b1b9c0Schristos *
1075e2b1b9c0Schristos * Notes:
1076e2b1b9c0Schristos * Relative domain names will have 'origin' appended to them
1077e2b1b9c0Schristos * unless 'origin' is NULL, in which case relative domain names
1078e2b1b9c0Schristos * will remain relative.
1079e2b1b9c0Schristos */
1080e2b1b9c0Schristos
1081e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1082e2b1b9c0Schristos REQUIRE(ISC_BUFFER_VALID(source));
1083e2b1b9c0Schristos REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1084e2b1b9c0Schristos (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1085e2b1b9c0Schristos
1086f2e20987Schristos downcase = ((options & DNS_NAME_DOWNCASE) != 0);
1087e2b1b9c0Schristos
1088e2b1b9c0Schristos if (target == NULL && name->buffer != NULL) {
1089e2b1b9c0Schristos target = name->buffer;
1090e2b1b9c0Schristos isc_buffer_clear(target);
1091e2b1b9c0Schristos }
1092e2b1b9c0Schristos
1093e2b1b9c0Schristos REQUIRE(BINDABLE(name));
1094e2b1b9c0Schristos
1095e2b1b9c0Schristos INIT_OFFSETS(name, offsets, odata);
1096e2b1b9c0Schristos offsets[0] = 0;
1097e2b1b9c0Schristos
1098e2b1b9c0Schristos /*
1099e2b1b9c0Schristos * Make 'name' empty in case of failure.
1100e2b1b9c0Schristos */
1101e2b1b9c0Schristos MAKE_EMPTY(name);
1102e2b1b9c0Schristos
1103e2b1b9c0Schristos /*
1104e2b1b9c0Schristos * Set up the state machine.
1105e2b1b9c0Schristos */
1106e2b1b9c0Schristos tdata = (char *)source->base + source->current;
1107e2b1b9c0Schristos tlen = isc_buffer_remaininglength(source);
1108e2b1b9c0Schristos tused = 0;
1109e2b1b9c0Schristos ndata = isc_buffer_used(target);
1110e2b1b9c0Schristos nrem = isc_buffer_availablelength(target);
11119742fdb4Schristos if (nrem > 255) {
1112e2b1b9c0Schristos nrem = 255;
11139742fdb4Schristos }
1114e2b1b9c0Schristos nused = 0;
1115e2b1b9c0Schristos labels = 0;
1116f2e20987Schristos done = false;
1117e2b1b9c0Schristos state = ft_init;
1118e2b1b9c0Schristos
1119e2b1b9c0Schristos while (nrem > 0 && tlen > 0 && !done) {
1120e2b1b9c0Schristos c = *tdata++;
1121e2b1b9c0Schristos tlen--;
1122e2b1b9c0Schristos tused++;
1123e2b1b9c0Schristos
1124e2b1b9c0Schristos switch (state) {
1125e2b1b9c0Schristos case ft_init:
1126e2b1b9c0Schristos /*
1127e2b1b9c0Schristos * Is this the root name?
1128e2b1b9c0Schristos */
1129e2b1b9c0Schristos if (c == '.') {
11309742fdb4Schristos if (tlen != 0) {
1131e2b1b9c0Schristos return (DNS_R_EMPTYLABEL);
11329742fdb4Schristos }
1133e2b1b9c0Schristos labels++;
1134e2b1b9c0Schristos *ndata++ = 0;
1135e2b1b9c0Schristos nrem--;
1136e2b1b9c0Schristos nused++;
1137f2e20987Schristos done = true;
1138e2b1b9c0Schristos break;
1139e2b1b9c0Schristos }
1140e2b1b9c0Schristos if (c == '@' && tlen == 0) {
1141e2b1b9c0Schristos state = ft_at;
1142e2b1b9c0Schristos break;
1143e2b1b9c0Schristos }
1144e2b1b9c0Schristos
1145c0b5d9fbSchristos FALLTHROUGH;
1146e2b1b9c0Schristos case ft_start:
1147e2b1b9c0Schristos label = ndata;
1148e2b1b9c0Schristos ndata++;
1149e2b1b9c0Schristos nrem--;
1150e2b1b9c0Schristos nused++;
1151e2b1b9c0Schristos count = 0;
1152e2b1b9c0Schristos if (c == '\\') {
1153e2b1b9c0Schristos state = ft_initialescape;
1154e2b1b9c0Schristos break;
1155e2b1b9c0Schristos }
1156e2b1b9c0Schristos state = ft_ordinary;
11579742fdb4Schristos if (nrem == 0) {
1158e2b1b9c0Schristos return (ISC_R_NOSPACE);
11599742fdb4Schristos }
1160c0b5d9fbSchristos FALLTHROUGH;
1161e2b1b9c0Schristos case ft_ordinary:
1162e2b1b9c0Schristos if (c == '.') {
11639742fdb4Schristos if (count == 0) {
1164e2b1b9c0Schristos return (DNS_R_EMPTYLABEL);
11659742fdb4Schristos }
1166e2b1b9c0Schristos *label = count;
1167e2b1b9c0Schristos labels++;
1168e2b1b9c0Schristos INSIST(labels <= 127);
1169e2b1b9c0Schristos offsets[labels] = nused;
1170e2b1b9c0Schristos if (tlen == 0) {
1171e2b1b9c0Schristos labels++;
1172e2b1b9c0Schristos *ndata++ = 0;
1173e2b1b9c0Schristos nrem--;
1174e2b1b9c0Schristos nused++;
1175f2e20987Schristos done = true;
1176e2b1b9c0Schristos }
1177e2b1b9c0Schristos state = ft_start;
1178e2b1b9c0Schristos } else if (c == '\\') {
1179e2b1b9c0Schristos state = ft_escape;
1180e2b1b9c0Schristos } else {
11819742fdb4Schristos if (count >= 63) {
1182e2b1b9c0Schristos return (DNS_R_LABELTOOLONG);
11839742fdb4Schristos }
1184e2b1b9c0Schristos count++;
1185e2b1b9c0Schristos CONVERTTOASCII(c);
11869742fdb4Schristos if (downcase) {
1187e2b1b9c0Schristos c = maptolower[c & 0xff];
11889742fdb4Schristos }
1189e2b1b9c0Schristos *ndata++ = c;
1190e2b1b9c0Schristos nrem--;
1191e2b1b9c0Schristos nused++;
1192e2b1b9c0Schristos }
1193e2b1b9c0Schristos break;
1194e2b1b9c0Schristos case ft_initialescape:
1195e2b1b9c0Schristos if (c == '[') {
1196e2b1b9c0Schristos /*
1197e2b1b9c0Schristos * This looks like a bitstring label, which
1198e2b1b9c0Schristos * was deprecated. Intentionally drop it.
1199e2b1b9c0Schristos */
1200e2b1b9c0Schristos return (DNS_R_BADLABELTYPE);
1201e2b1b9c0Schristos }
1202e2b1b9c0Schristos state = ft_escape;
1203e2b1b9c0Schristos POST(state);
1204c0b5d9fbSchristos FALLTHROUGH;
1205e2b1b9c0Schristos case ft_escape:
1206fadf0758Schristos if (!isdigit((unsigned char)c)) {
12079742fdb4Schristos if (count >= 63) {
1208e2b1b9c0Schristos return (DNS_R_LABELTOOLONG);
12099742fdb4Schristos }
1210e2b1b9c0Schristos count++;
1211e2b1b9c0Schristos CONVERTTOASCII(c);
12129742fdb4Schristos if (downcase) {
1213e2b1b9c0Schristos c = maptolower[c & 0xff];
12149742fdb4Schristos }
1215e2b1b9c0Schristos *ndata++ = c;
1216e2b1b9c0Schristos nrem--;
1217e2b1b9c0Schristos nused++;
1218e2b1b9c0Schristos state = ft_ordinary;
1219e2b1b9c0Schristos break;
1220e2b1b9c0Schristos }
1221e2b1b9c0Schristos digits = 0;
1222e2b1b9c0Schristos value = 0;
1223e2b1b9c0Schristos state = ft_escdecimal;
1224c0b5d9fbSchristos FALLTHROUGH;
1225e2b1b9c0Schristos case ft_escdecimal:
1226fadf0758Schristos if (!isdigit((unsigned char)c)) {
1227e2b1b9c0Schristos return (DNS_R_BADESCAPE);
12289742fdb4Schristos }
1229e2b1b9c0Schristos value *= 10;
1230e2b1b9c0Schristos value += digitvalue[c & 0xff];
1231e2b1b9c0Schristos digits++;
1232e2b1b9c0Schristos if (digits == 3) {
12339742fdb4Schristos if (value > 255) {
1234e2b1b9c0Schristos return (DNS_R_BADESCAPE);
12359742fdb4Schristos }
12369742fdb4Schristos if (count >= 63) {
1237e2b1b9c0Schristos return (DNS_R_LABELTOOLONG);
12389742fdb4Schristos }
1239e2b1b9c0Schristos count++;
12409742fdb4Schristos if (downcase) {
1241e2b1b9c0Schristos value = maptolower[value];
12429742fdb4Schristos }
1243e2b1b9c0Schristos *ndata++ = value;
1244e2b1b9c0Schristos nrem--;
1245e2b1b9c0Schristos nused++;
1246e2b1b9c0Schristos state = ft_ordinary;
1247e2b1b9c0Schristos }
1248e2b1b9c0Schristos break;
1249e2b1b9c0Schristos default:
12509742fdb4Schristos FATAL_ERROR(__FILE__, __LINE__, "Unexpected state %d",
12519742fdb4Schristos state);
1252e2b1b9c0Schristos /* Does not return. */
1253e2b1b9c0Schristos }
1254e2b1b9c0Schristos }
1255e2b1b9c0Schristos
1256e2b1b9c0Schristos if (!done) {
12579742fdb4Schristos if (nrem == 0) {
1258e2b1b9c0Schristos return (ISC_R_NOSPACE);
12599742fdb4Schristos }
1260e2b1b9c0Schristos INSIST(tlen == 0);
12619742fdb4Schristos if (state != ft_ordinary && state != ft_at) {
1262e2b1b9c0Schristos return (ISC_R_UNEXPECTEDEND);
12639742fdb4Schristos }
1264e2b1b9c0Schristos if (state == ft_ordinary) {
1265e2b1b9c0Schristos INSIST(count != 0);
1266fadf0758Schristos INSIST(label != NULL);
1267e2b1b9c0Schristos *label = count;
1268e2b1b9c0Schristos labels++;
1269e2b1b9c0Schristos INSIST(labels <= 127);
1270e2b1b9c0Schristos offsets[labels] = nused;
1271e2b1b9c0Schristos }
1272e2b1b9c0Schristos if (origin != NULL) {
12739742fdb4Schristos if (nrem < origin->length) {
1274e2b1b9c0Schristos return (ISC_R_NOSPACE);
12759742fdb4Schristos }
1276e2b1b9c0Schristos label = origin->ndata;
1277e2b1b9c0Schristos n1 = origin->length;
1278e2b1b9c0Schristos nrem -= n1;
1279e2b1b9c0Schristos POST(nrem);
1280e2b1b9c0Schristos while (n1 > 0) {
1281e2b1b9c0Schristos n2 = *label++;
1282e2b1b9c0Schristos INSIST(n2 <= 63); /* no bitstring support */
1283e2b1b9c0Schristos *ndata++ = n2;
1284e2b1b9c0Schristos n1 -= n2 + 1;
1285e2b1b9c0Schristos nused += n2 + 1;
1286e2b1b9c0Schristos while (n2 > 0) {
1287e2b1b9c0Schristos c = *label++;
12889742fdb4Schristos if (downcase) {
1289e2b1b9c0Schristos c = maptolower[c & 0xff];
12909742fdb4Schristos }
1291e2b1b9c0Schristos *ndata++ = c;
1292e2b1b9c0Schristos n2--;
1293e2b1b9c0Schristos }
1294e2b1b9c0Schristos labels++;
1295e2b1b9c0Schristos if (n1 > 0) {
1296e2b1b9c0Schristos INSIST(labels <= 127);
1297e2b1b9c0Schristos offsets[labels] = nused;
1298e2b1b9c0Schristos }
1299e2b1b9c0Schristos }
13009742fdb4Schristos if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1301e2b1b9c0Schristos name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1302e2b1b9c0Schristos }
13039742fdb4Schristos }
13049742fdb4Schristos } else {
1305e2b1b9c0Schristos name->attributes |= DNS_NAMEATTR_ABSOLUTE;
13069742fdb4Schristos }
1307e2b1b9c0Schristos
1308e2b1b9c0Schristos name->ndata = (unsigned char *)target->base + target->used;
1309e2b1b9c0Schristos name->labels = labels;
1310e2b1b9c0Schristos name->length = nused;
1311e2b1b9c0Schristos
1312e2b1b9c0Schristos isc_buffer_forward(source, tused);
1313e2b1b9c0Schristos isc_buffer_add(target, name->length);
1314e2b1b9c0Schristos
1315e2b1b9c0Schristos return (ISC_R_SUCCESS);
1316e2b1b9c0Schristos }
1317e2b1b9c0Schristos
1318e2b1b9c0Schristos isc_result_t
dns_name_totext(const dns_name_t * name,bool omit_final_dot,isc_buffer_t * target)1319f2e20987Schristos dns_name_totext(const dns_name_t *name, bool omit_final_dot,
13209742fdb4Schristos isc_buffer_t *target) {
1321e2b1b9c0Schristos unsigned int options = DNS_NAME_MASTERFILE;
1322e2b1b9c0Schristos
13239742fdb4Schristos if (omit_final_dot) {
1324e2b1b9c0Schristos options |= DNS_NAME_OMITFINALDOT;
13259742fdb4Schristos }
1326e2b1b9c0Schristos return (dns_name_totext2(name, options, target));
1327e2b1b9c0Schristos }
1328e2b1b9c0Schristos
1329e2b1b9c0Schristos isc_result_t
dns_name_toprincipal(const dns_name_t * name,isc_buffer_t * target)1330e2b1b9c0Schristos dns_name_toprincipal(const dns_name_t *name, isc_buffer_t *target) {
1331e2b1b9c0Schristos return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
1332e2b1b9c0Schristos }
1333e2b1b9c0Schristos
1334e2b1b9c0Schristos isc_result_t
dns_name_totext2(const dns_name_t * name,unsigned int options,isc_buffer_t * target)1335e2b1b9c0Schristos dns_name_totext2(const dns_name_t *name, unsigned int options,
13369742fdb4Schristos isc_buffer_t *target) {
1337e2b1b9c0Schristos unsigned char *ndata;
1338e2b1b9c0Schristos char *tdata;
1339e2b1b9c0Schristos unsigned int nlen, tlen;
1340e2b1b9c0Schristos unsigned char c;
1341e2b1b9c0Schristos unsigned int trem, count;
1342e2b1b9c0Schristos unsigned int labels;
1343f2e20987Schristos bool saw_root = false;
13448b4c8a26Schristos unsigned int oused;
1345f2e20987Schristos bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0);
1346e2b1b9c0Schristos
1347e2b1b9c0Schristos /*
1348e2b1b9c0Schristos * This function assumes the name is in proper uncompressed
1349e2b1b9c0Schristos * wire format.
1350e2b1b9c0Schristos */
1351e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1352e2b1b9c0Schristos REQUIRE(ISC_BUFFER_VALID(target));
1353e2b1b9c0Schristos
13548b4c8a26Schristos oused = target->used;
13558b4c8a26Schristos
1356e2b1b9c0Schristos ndata = name->ndata;
1357e2b1b9c0Schristos nlen = name->length;
1358e2b1b9c0Schristos labels = name->labels;
1359e2b1b9c0Schristos tdata = isc_buffer_used(target);
1360e2b1b9c0Schristos tlen = isc_buffer_availablelength(target);
1361e2b1b9c0Schristos
1362e2b1b9c0Schristos trem = tlen;
1363e2b1b9c0Schristos
1364e2b1b9c0Schristos if (labels == 0 && nlen == 0) {
1365e2b1b9c0Schristos /*
1366e2b1b9c0Schristos * Special handling for an empty name.
1367e2b1b9c0Schristos */
13689742fdb4Schristos if (trem == 0) {
1369e2b1b9c0Schristos return (ISC_R_NOSPACE);
13709742fdb4Schristos }
1371e2b1b9c0Schristos
1372e2b1b9c0Schristos /*
1373e2b1b9c0Schristos * The names of these booleans are misleading in this case.
1374e2b1b9c0Schristos * This empty name is not necessarily from the root node of
1375e2b1b9c0Schristos * the DNS root zone, nor is a final dot going to be included.
1376e2b1b9c0Schristos * They need to be set this way, though, to keep the "@"
1377e2b1b9c0Schristos * from being trounced.
1378e2b1b9c0Schristos */
1379f2e20987Schristos saw_root = true;
1380f2e20987Schristos omit_final_dot = false;
1381e2b1b9c0Schristos *tdata++ = '@';
1382e2b1b9c0Schristos trem--;
1383e2b1b9c0Schristos
1384e2b1b9c0Schristos /*
1385e2b1b9c0Schristos * Skip the while() loop.
1386e2b1b9c0Schristos */
1387e2b1b9c0Schristos nlen = 0;
1388e2b1b9c0Schristos } else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1389e2b1b9c0Schristos /*
1390e2b1b9c0Schristos * Special handling for the root label.
1391e2b1b9c0Schristos */
13929742fdb4Schristos if (trem == 0) {
1393e2b1b9c0Schristos return (ISC_R_NOSPACE);
13949742fdb4Schristos }
1395e2b1b9c0Schristos
1396f2e20987Schristos saw_root = true;
1397f2e20987Schristos omit_final_dot = false;
1398e2b1b9c0Schristos *tdata++ = '.';
1399e2b1b9c0Schristos trem--;
1400e2b1b9c0Schristos
1401e2b1b9c0Schristos /*
1402e2b1b9c0Schristos * Skip the while() loop.
1403e2b1b9c0Schristos */
1404e2b1b9c0Schristos nlen = 0;
1405e2b1b9c0Schristos }
1406e2b1b9c0Schristos
1407e2b1b9c0Schristos while (labels > 0 && nlen > 0 && trem > 0) {
1408e2b1b9c0Schristos labels--;
1409e2b1b9c0Schristos count = *ndata++;
1410e2b1b9c0Schristos nlen--;
1411e2b1b9c0Schristos if (count == 0) {
1412f2e20987Schristos saw_root = true;
1413e2b1b9c0Schristos break;
1414e2b1b9c0Schristos }
1415e2b1b9c0Schristos if (count < 64) {
1416e2b1b9c0Schristos INSIST(nlen >= count);
1417e2b1b9c0Schristos while (count > 0) {
1418e2b1b9c0Schristos c = *ndata;
1419e2b1b9c0Schristos switch (c) {
1420e2b1b9c0Schristos /* Special modifiers in zone files. */
1421e2b1b9c0Schristos case 0x40: /* '@' */
1422e2b1b9c0Schristos case 0x24: /* '$' */
14239742fdb4Schristos if ((options & DNS_NAME_MASTERFILE) ==
1424*4ac1c27eSchristos 0)
1425*4ac1c27eSchristos {
1426e2b1b9c0Schristos goto no_escape;
14279742fdb4Schristos }
1428c0b5d9fbSchristos FALLTHROUGH;
1429e2b1b9c0Schristos case 0x22: /* '"' */
1430e2b1b9c0Schristos case 0x28: /* '(' */
1431e2b1b9c0Schristos case 0x29: /* ')' */
1432e2b1b9c0Schristos case 0x2E: /* '.' */
1433e2b1b9c0Schristos case 0x3B: /* ';' */
1434e2b1b9c0Schristos case 0x5C: /* '\\' */
14359742fdb4Schristos if (trem < 2) {
1436e2b1b9c0Schristos return (ISC_R_NOSPACE);
14379742fdb4Schristos }
1438e2b1b9c0Schristos *tdata++ = '\\';
1439e2b1b9c0Schristos CONVERTFROMASCII(c);
1440e2b1b9c0Schristos *tdata++ = c;
1441e2b1b9c0Schristos ndata++;
1442e2b1b9c0Schristos trem -= 2;
1443e2b1b9c0Schristos nlen--;
1444e2b1b9c0Schristos break;
1445e2b1b9c0Schristos no_escape:
1446e2b1b9c0Schristos default:
1447e2b1b9c0Schristos if (c > 0x20 && c < 0x7f) {
14489742fdb4Schristos if (trem == 0) {
1449e2b1b9c0Schristos return (ISC_R_NOSPACE);
14509742fdb4Schristos }
1451e2b1b9c0Schristos CONVERTFROMASCII(c);
1452e2b1b9c0Schristos *tdata++ = c;
1453e2b1b9c0Schristos ndata++;
1454e2b1b9c0Schristos trem--;
1455e2b1b9c0Schristos nlen--;
1456e2b1b9c0Schristos } else {
14579742fdb4Schristos if (trem < 4) {
1458e2b1b9c0Schristos return (ISC_R_NOSPACE);
14599742fdb4Schristos }
1460e2b1b9c0Schristos *tdata++ = 0x5c;
1461e2b1b9c0Schristos *tdata++ = 0x30 +
1462e2b1b9c0Schristos ((c / 100) % 10);
1463e2b1b9c0Schristos *tdata++ = 0x30 +
1464e2b1b9c0Schristos ((c / 10) % 10);
1465e2b1b9c0Schristos *tdata++ = 0x30 + (c % 10);
1466e2b1b9c0Schristos trem -= 4;
1467e2b1b9c0Schristos ndata++;
1468e2b1b9c0Schristos nlen--;
1469e2b1b9c0Schristos }
1470e2b1b9c0Schristos }
1471e2b1b9c0Schristos count--;
1472e2b1b9c0Schristos }
1473e2b1b9c0Schristos } else {
1474e2b1b9c0Schristos FATAL_ERROR(__FILE__, __LINE__,
1475e2b1b9c0Schristos "Unexpected label type %02x", count);
1476c0b5d9fbSchristos UNREACHABLE();
1477e2b1b9c0Schristos }
1478e2b1b9c0Schristos
1479e2b1b9c0Schristos /*
1480e2b1b9c0Schristos * The following assumes names are absolute. If not, we
1481e2b1b9c0Schristos * fix things up later. Note that this means that in some
1482e2b1b9c0Schristos * cases one more byte of text buffer is required than is
1483e2b1b9c0Schristos * needed in the final output.
1484e2b1b9c0Schristos */
14859742fdb4Schristos if (trem == 0) {
1486e2b1b9c0Schristos return (ISC_R_NOSPACE);
14879742fdb4Schristos }
1488e2b1b9c0Schristos *tdata++ = '.';
1489e2b1b9c0Schristos trem--;
1490e2b1b9c0Schristos }
1491e2b1b9c0Schristos
14929742fdb4Schristos if (nlen != 0 && trem == 0) {
1493e2b1b9c0Schristos return (ISC_R_NOSPACE);
14949742fdb4Schristos }
1495e2b1b9c0Schristos
1496e2b1b9c0Schristos if (!saw_root || omit_final_dot) {
1497e2b1b9c0Schristos trem++;
1498e2b1b9c0Schristos tdata--;
1499e2b1b9c0Schristos }
1500e2b1b9c0Schristos if (trem > 0) {
1501e2b1b9c0Schristos *tdata = 0;
1502e2b1b9c0Schristos }
1503e2b1b9c0Schristos isc_buffer_add(target, tlen - trem);
1504e2b1b9c0Schristos
15059742fdb4Schristos if (totext_filter_proc != NULL) {
15069742fdb4Schristos return ((totext_filter_proc)(target, oused));
15079742fdb4Schristos }
1508e2b1b9c0Schristos
1509e2b1b9c0Schristos return (ISC_R_SUCCESS);
1510e2b1b9c0Schristos }
1511e2b1b9c0Schristos
1512e2b1b9c0Schristos isc_result_t
dns_name_tofilenametext(const dns_name_t * name,bool omit_final_dot,isc_buffer_t * target)1513f2e20987Schristos dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot,
15149742fdb4Schristos isc_buffer_t *target) {
1515e2b1b9c0Schristos unsigned char *ndata;
1516e2b1b9c0Schristos char *tdata;
1517e2b1b9c0Schristos unsigned int nlen, tlen;
1518e2b1b9c0Schristos unsigned char c;
1519e2b1b9c0Schristos unsigned int trem, count;
1520e2b1b9c0Schristos unsigned int labels;
1521e2b1b9c0Schristos
1522e2b1b9c0Schristos /*
1523e2b1b9c0Schristos * This function assumes the name is in proper uncompressed
1524e2b1b9c0Schristos * wire format.
1525e2b1b9c0Schristos */
1526e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1527e2b1b9c0Schristos REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
1528e2b1b9c0Schristos REQUIRE(ISC_BUFFER_VALID(target));
1529e2b1b9c0Schristos
1530e2b1b9c0Schristos ndata = name->ndata;
1531e2b1b9c0Schristos nlen = name->length;
1532e2b1b9c0Schristos labels = name->labels;
1533e2b1b9c0Schristos tdata = isc_buffer_used(target);
1534e2b1b9c0Schristos tlen = isc_buffer_availablelength(target);
1535e2b1b9c0Schristos
1536e2b1b9c0Schristos trem = tlen;
1537e2b1b9c0Schristos
1538e2b1b9c0Schristos if (nlen == 1 && labels == 1 && *ndata == '\0') {
1539e2b1b9c0Schristos /*
1540e2b1b9c0Schristos * Special handling for the root label.
1541e2b1b9c0Schristos */
15429742fdb4Schristos if (trem == 0) {
1543e2b1b9c0Schristos return (ISC_R_NOSPACE);
15449742fdb4Schristos }
1545e2b1b9c0Schristos
1546f2e20987Schristos omit_final_dot = false;
1547e2b1b9c0Schristos *tdata++ = '.';
1548e2b1b9c0Schristos trem--;
1549e2b1b9c0Schristos
1550e2b1b9c0Schristos /*
1551e2b1b9c0Schristos * Skip the while() loop.
1552e2b1b9c0Schristos */
1553e2b1b9c0Schristos nlen = 0;
1554e2b1b9c0Schristos }
1555e2b1b9c0Schristos
1556e2b1b9c0Schristos while (labels > 0 && nlen > 0 && trem > 0) {
1557e2b1b9c0Schristos labels--;
1558e2b1b9c0Schristos count = *ndata++;
1559e2b1b9c0Schristos nlen--;
15609742fdb4Schristos if (count == 0) {
1561e2b1b9c0Schristos break;
15629742fdb4Schristos }
1563e2b1b9c0Schristos if (count < 64) {
1564e2b1b9c0Schristos INSIST(nlen >= count);
1565e2b1b9c0Schristos while (count > 0) {
1566e2b1b9c0Schristos c = *ndata;
1567e2b1b9c0Schristos if ((c >= 0x30 && c <= 0x39) || /* digit */
1568e2b1b9c0Schristos (c >= 0x41 && c <= 0x5A) || /* uppercase */
1569e2b1b9c0Schristos (c >= 0x61 && c <= 0x7A) || /* lowercase */
1570e2b1b9c0Schristos c == 0x2D || /* hyphen */
1571e2b1b9c0Schristos c == 0x5F) /* underscore */
1572e2b1b9c0Schristos {
15739742fdb4Schristos if (trem == 0) {
1574e2b1b9c0Schristos return (ISC_R_NOSPACE);
15759742fdb4Schristos }
1576e2b1b9c0Schristos /* downcase */
15779742fdb4Schristos if (c >= 0x41 && c <= 0x5A) {
1578e2b1b9c0Schristos c += 0x20;
15799742fdb4Schristos }
1580e2b1b9c0Schristos CONVERTFROMASCII(c);
1581e2b1b9c0Schristos *tdata++ = c;
1582e2b1b9c0Schristos ndata++;
1583e2b1b9c0Schristos trem--;
1584e2b1b9c0Schristos nlen--;
1585e2b1b9c0Schristos } else {
15869742fdb4Schristos if (trem < 4) {
1587e2b1b9c0Schristos return (ISC_R_NOSPACE);
15889742fdb4Schristos }
1589e2b1b9c0Schristos snprintf(tdata, trem, "%%%02X", c);
1590e2b1b9c0Schristos tdata += 3;
1591e2b1b9c0Schristos trem -= 3;
1592e2b1b9c0Schristos ndata++;
1593e2b1b9c0Schristos nlen--;
1594e2b1b9c0Schristos }
1595e2b1b9c0Schristos count--;
1596e2b1b9c0Schristos }
1597e2b1b9c0Schristos } else {
1598e2b1b9c0Schristos FATAL_ERROR(__FILE__, __LINE__,
1599e2b1b9c0Schristos "Unexpected label type %02x", count);
1600c0b5d9fbSchristos UNREACHABLE();
1601e2b1b9c0Schristos }
1602e2b1b9c0Schristos
1603e2b1b9c0Schristos /*
1604e2b1b9c0Schristos * The following assumes names are absolute. If not, we
1605e2b1b9c0Schristos * fix things up later. Note that this means that in some
1606e2b1b9c0Schristos * cases one more byte of text buffer is required than is
1607e2b1b9c0Schristos * needed in the final output.
1608e2b1b9c0Schristos */
16099742fdb4Schristos if (trem == 0) {
1610e2b1b9c0Schristos return (ISC_R_NOSPACE);
16119742fdb4Schristos }
1612e2b1b9c0Schristos *tdata++ = '.';
1613e2b1b9c0Schristos trem--;
1614e2b1b9c0Schristos }
1615e2b1b9c0Schristos
16169742fdb4Schristos if (nlen != 0 && trem == 0) {
1617e2b1b9c0Schristos return (ISC_R_NOSPACE);
16189742fdb4Schristos }
1619e2b1b9c0Schristos
16209742fdb4Schristos if (omit_final_dot) {
1621e2b1b9c0Schristos trem++;
16229742fdb4Schristos }
1623e2b1b9c0Schristos
1624e2b1b9c0Schristos isc_buffer_add(target, tlen - trem);
1625e2b1b9c0Schristos
1626e2b1b9c0Schristos return (ISC_R_SUCCESS);
1627e2b1b9c0Schristos }
1628e2b1b9c0Schristos
1629e2b1b9c0Schristos isc_result_t
dns_name_downcase(const dns_name_t * source,dns_name_t * name,isc_buffer_t * target)1630e2b1b9c0Schristos dns_name_downcase(const dns_name_t *source, dns_name_t *name,
16319742fdb4Schristos isc_buffer_t *target) {
1632e2b1b9c0Schristos unsigned char *sndata, *ndata;
1633e2b1b9c0Schristos unsigned int nlen, count, labels;
1634e2b1b9c0Schristos isc_buffer_t buffer;
1635e2b1b9c0Schristos
1636e2b1b9c0Schristos /*
1637e2b1b9c0Schristos * Downcase 'source'.
1638e2b1b9c0Schristos */
1639e2b1b9c0Schristos
1640e2b1b9c0Schristos REQUIRE(VALID_NAME(source));
1641e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1642e2b1b9c0Schristos if (source == name) {
1643e2b1b9c0Schristos REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1644e2b1b9c0Schristos isc_buffer_init(&buffer, source->ndata, source->length);
1645e2b1b9c0Schristos target = &buffer;
1646e2b1b9c0Schristos ndata = source->ndata;
1647e2b1b9c0Schristos } else {
1648e2b1b9c0Schristos REQUIRE(BINDABLE(name));
1649e2b1b9c0Schristos REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1650e2b1b9c0Schristos (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1651e2b1b9c0Schristos if (target == NULL) {
1652e2b1b9c0Schristos target = name->buffer;
1653e2b1b9c0Schristos isc_buffer_clear(name->buffer);
1654e2b1b9c0Schristos }
1655e2b1b9c0Schristos ndata = (unsigned char *)target->base + target->used;
1656e2b1b9c0Schristos name->ndata = ndata;
1657e2b1b9c0Schristos }
1658e2b1b9c0Schristos
1659e2b1b9c0Schristos sndata = source->ndata;
1660e2b1b9c0Schristos nlen = source->length;
1661e2b1b9c0Schristos labels = source->labels;
1662e2b1b9c0Schristos
1663e2b1b9c0Schristos if (nlen > (target->length - target->used)) {
1664e2b1b9c0Schristos MAKE_EMPTY(name);
1665e2b1b9c0Schristos return (ISC_R_NOSPACE);
1666e2b1b9c0Schristos }
1667e2b1b9c0Schristos
1668e2b1b9c0Schristos while (labels > 0 && nlen > 0) {
1669e2b1b9c0Schristos labels--;
1670e2b1b9c0Schristos count = *sndata++;
1671e2b1b9c0Schristos *ndata++ = count;
1672e2b1b9c0Schristos nlen--;
1673e2b1b9c0Schristos if (count < 64) {
1674e2b1b9c0Schristos INSIST(nlen >= count);
1675e2b1b9c0Schristos while (count > 0) {
1676e2b1b9c0Schristos *ndata++ = maptolower[(*sndata++)];
1677e2b1b9c0Schristos nlen--;
1678e2b1b9c0Schristos count--;
1679e2b1b9c0Schristos }
1680e2b1b9c0Schristos } else {
1681e2b1b9c0Schristos FATAL_ERROR(__FILE__, __LINE__,
1682e2b1b9c0Schristos "Unexpected label type %02x", count);
1683e2b1b9c0Schristos /* Does not return. */
1684e2b1b9c0Schristos }
1685e2b1b9c0Schristos }
1686e2b1b9c0Schristos
1687e2b1b9c0Schristos if (source != name) {
1688e2b1b9c0Schristos name->labels = source->labels;
1689e2b1b9c0Schristos name->length = source->length;
16909742fdb4Schristos if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1691e2b1b9c0Schristos name->attributes = DNS_NAMEATTR_ABSOLUTE;
16929742fdb4Schristos } else {
1693e2b1b9c0Schristos name->attributes = 0;
16949742fdb4Schristos }
16959742fdb4Schristos if (name->labels > 0 && name->offsets != NULL) {
1696e2b1b9c0Schristos set_offsets(name, name->offsets, NULL);
1697e2b1b9c0Schristos }
16989742fdb4Schristos }
1699e2b1b9c0Schristos
1700e2b1b9c0Schristos isc_buffer_add(target, name->length);
1701e2b1b9c0Schristos
1702e2b1b9c0Schristos return (ISC_R_SUCCESS);
1703e2b1b9c0Schristos }
1704e2b1b9c0Schristos
1705e2b1b9c0Schristos static void
set_offsets(const dns_name_t * name,unsigned char * offsets,dns_name_t * set_name)1706e2b1b9c0Schristos set_offsets(const dns_name_t *name, unsigned char *offsets,
17079742fdb4Schristos dns_name_t *set_name) {
1708e2b1b9c0Schristos unsigned int offset, count, length, nlabels;
1709e2b1b9c0Schristos unsigned char *ndata;
1710f2e20987Schristos bool absolute;
1711e2b1b9c0Schristos
1712e2b1b9c0Schristos ndata = name->ndata;
1713e2b1b9c0Schristos length = name->length;
1714e2b1b9c0Schristos offset = 0;
1715e2b1b9c0Schristos nlabels = 0;
1716f2e20987Schristos absolute = false;
1717e2b1b9c0Schristos while (ISC_LIKELY(offset != length)) {
1718e2b1b9c0Schristos INSIST(nlabels < 128);
1719e2b1b9c0Schristos offsets[nlabels++] = offset;
1720e2b1b9c0Schristos count = *ndata;
1721e2b1b9c0Schristos INSIST(count <= 63);
1722e2b1b9c0Schristos offset += count + 1;
1723e2b1b9c0Schristos ndata += count + 1;
1724e2b1b9c0Schristos INSIST(offset <= length);
1725e2b1b9c0Schristos if (ISC_UNLIKELY(count == 0)) {
1726f2e20987Schristos absolute = true;
1727e2b1b9c0Schristos break;
1728e2b1b9c0Schristos }
1729e2b1b9c0Schristos }
1730e2b1b9c0Schristos if (set_name != NULL) {
1731e2b1b9c0Schristos INSIST(set_name == name);
1732e2b1b9c0Schristos
1733e2b1b9c0Schristos set_name->labels = nlabels;
1734e2b1b9c0Schristos set_name->length = offset;
17359742fdb4Schristos if (absolute) {
1736e2b1b9c0Schristos set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
17379742fdb4Schristos } else {
1738e2b1b9c0Schristos set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1739e2b1b9c0Schristos }
17409742fdb4Schristos }
1741e2b1b9c0Schristos INSIST(nlabels == name->labels);
1742e2b1b9c0Schristos INSIST(offset == name->length);
1743e2b1b9c0Schristos }
1744e2b1b9c0Schristos
1745e2b1b9c0Schristos isc_result_t
dns_name_fromwire(dns_name_t * name,isc_buffer_t * source,dns_decompress_t * dctx,unsigned int options,isc_buffer_t * target)1746e2b1b9c0Schristos dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1747e2b1b9c0Schristos dns_decompress_t *dctx, unsigned int options,
17489742fdb4Schristos isc_buffer_t *target) {
1749e2b1b9c0Schristos unsigned char *cdata, *ndata;
1750e2b1b9c0Schristos unsigned int cused; /* Bytes of compressed name data used */
1751e2b1b9c0Schristos unsigned int nused, labels, n, nmax;
1752e2b1b9c0Schristos unsigned int current, new_current, biggest_pointer;
1753f2e20987Schristos bool done;
1754e2b1b9c0Schristos fw_state state = fw_start;
1755e2b1b9c0Schristos unsigned int c;
1756e2b1b9c0Schristos unsigned char *offsets;
1757e2b1b9c0Schristos dns_offsets_t odata;
1758f2e20987Schristos bool downcase;
1759f2e20987Schristos bool seen_pointer;
1760e2b1b9c0Schristos
1761e2b1b9c0Schristos /*
1762e2b1b9c0Schristos * Copy the possibly-compressed name at source into target,
1763e2b1b9c0Schristos * decompressing it. Loop prevention is performed by checking
1764e2b1b9c0Schristos * the new pointer against biggest_pointer.
1765e2b1b9c0Schristos */
1766e2b1b9c0Schristos
1767e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1768e2b1b9c0Schristos REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1769e2b1b9c0Schristos (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1770e2b1b9c0Schristos
1771f2e20987Schristos downcase = ((options & DNS_NAME_DOWNCASE) != 0);
1772e2b1b9c0Schristos
1773e2b1b9c0Schristos if (target == NULL && name->buffer != NULL) {
1774e2b1b9c0Schristos target = name->buffer;
1775e2b1b9c0Schristos isc_buffer_clear(target);
1776e2b1b9c0Schristos }
1777e2b1b9c0Schristos
1778e2b1b9c0Schristos REQUIRE(dctx != NULL);
1779e2b1b9c0Schristos REQUIRE(BINDABLE(name));
1780e2b1b9c0Schristos
1781e2b1b9c0Schristos INIT_OFFSETS(name, offsets, odata);
1782e2b1b9c0Schristos
1783e2b1b9c0Schristos /*
1784e2b1b9c0Schristos * Make 'name' empty in case of failure.
1785e2b1b9c0Schristos */
1786e2b1b9c0Schristos MAKE_EMPTY(name);
1787e2b1b9c0Schristos
1788e2b1b9c0Schristos /*
1789e2b1b9c0Schristos * Initialize things to make the compiler happy; they're not required.
1790e2b1b9c0Schristos */
1791e2b1b9c0Schristos n = 0;
1792e2b1b9c0Schristos new_current = 0;
1793e2b1b9c0Schristos
1794e2b1b9c0Schristos /*
1795e2b1b9c0Schristos * Set up.
1796e2b1b9c0Schristos */
1797e2b1b9c0Schristos labels = 0;
1798f2e20987Schristos done = false;
1799e2b1b9c0Schristos
1800e2b1b9c0Schristos ndata = isc_buffer_used(target);
1801e2b1b9c0Schristos nused = 0;
1802f2e20987Schristos seen_pointer = false;
1803e2b1b9c0Schristos
1804e2b1b9c0Schristos /*
1805e2b1b9c0Schristos * Find the maximum number of uncompressed target name
1806e2b1b9c0Schristos * bytes we are willing to generate. This is the smaller
1807e2b1b9c0Schristos * of the available target buffer length and the
1808e2b1b9c0Schristos * maximum legal domain name length (255).
1809e2b1b9c0Schristos */
1810e2b1b9c0Schristos nmax = isc_buffer_availablelength(target);
18119742fdb4Schristos if (nmax > DNS_NAME_MAXWIRE) {
1812e2b1b9c0Schristos nmax = DNS_NAME_MAXWIRE;
18139742fdb4Schristos }
1814e2b1b9c0Schristos
1815e2b1b9c0Schristos cdata = isc_buffer_current(source);
1816e2b1b9c0Schristos cused = 0;
1817e2b1b9c0Schristos
1818e2b1b9c0Schristos current = source->current;
1819e2b1b9c0Schristos biggest_pointer = current;
1820e2b1b9c0Schristos
1821e2b1b9c0Schristos /*
1822e2b1b9c0Schristos * Note: The following code is not optimized for speed, but
1823e2b1b9c0Schristos * rather for correctness. Speed will be addressed in the future.
1824e2b1b9c0Schristos */
1825e2b1b9c0Schristos
1826e2b1b9c0Schristos while (current < source->active && !done) {
1827e2b1b9c0Schristos c = *cdata++;
1828e2b1b9c0Schristos current++;
18299742fdb4Schristos if (!seen_pointer) {
1830e2b1b9c0Schristos cused++;
18319742fdb4Schristos }
1832e2b1b9c0Schristos
1833e2b1b9c0Schristos switch (state) {
1834e2b1b9c0Schristos case fw_start:
1835e2b1b9c0Schristos if (c < 64) {
1836e2b1b9c0Schristos offsets[labels] = nused;
1837e2b1b9c0Schristos labels++;
18389742fdb4Schristos if (nused + c + 1 > nmax) {
1839e2b1b9c0Schristos goto full;
18409742fdb4Schristos }
1841e2b1b9c0Schristos nused += c + 1;
1842e2b1b9c0Schristos *ndata++ = c;
18439742fdb4Schristos if (c == 0) {
1844f2e20987Schristos done = true;
18459742fdb4Schristos }
1846e2b1b9c0Schristos n = c;
1847e2b1b9c0Schristos state = fw_ordinary;
1848e2b1b9c0Schristos } else if (c >= 128 && c < 192) {
1849e2b1b9c0Schristos /*
1850e2b1b9c0Schristos * 14 bit local compression pointer.
1851e2b1b9c0Schristos * Local compression is no longer an
1852e2b1b9c0Schristos * IETF draft.
1853e2b1b9c0Schristos */
1854e2b1b9c0Schristos return (DNS_R_BADLABELTYPE);
1855e2b1b9c0Schristos } else if (c >= 192) {
1856e2b1b9c0Schristos /*
1857e2b1b9c0Schristos * Ordinary 14-bit pointer.
1858e2b1b9c0Schristos */
18599742fdb4Schristos if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1860*4ac1c27eSchristos 0)
1861*4ac1c27eSchristos {
1862e2b1b9c0Schristos return (DNS_R_DISALLOWED);
1863f2e20987Schristos }
1864e2b1b9c0Schristos new_current = c & 0x3F;
1865e2b1b9c0Schristos state = fw_newcurrent;
18669742fdb4Schristos } else {
1867e2b1b9c0Schristos return (DNS_R_BADLABELTYPE);
18689742fdb4Schristos }
1869e2b1b9c0Schristos break;
1870e2b1b9c0Schristos case fw_ordinary:
18719742fdb4Schristos if (downcase) {
1872e2b1b9c0Schristos c = maptolower[c];
18739742fdb4Schristos }
1874e2b1b9c0Schristos *ndata++ = c;
1875e2b1b9c0Schristos n--;
18769742fdb4Schristos if (n == 0) {
1877e2b1b9c0Schristos state = fw_start;
18789742fdb4Schristos }
1879e2b1b9c0Schristos break;
1880e2b1b9c0Schristos case fw_newcurrent:
1881e2b1b9c0Schristos new_current *= 256;
1882e2b1b9c0Schristos new_current += c;
18839742fdb4Schristos if (new_current >= biggest_pointer) {
1884e2b1b9c0Schristos return (DNS_R_BADPOINTER);
18859742fdb4Schristos }
1886e2b1b9c0Schristos biggest_pointer = new_current;
1887e2b1b9c0Schristos current = new_current;
1888e2b1b9c0Schristos cdata = (unsigned char *)source->base + current;
1889f2e20987Schristos seen_pointer = true;
1890e2b1b9c0Schristos state = fw_start;
1891e2b1b9c0Schristos break;
1892e2b1b9c0Schristos default:
18939742fdb4Schristos FATAL_ERROR(__FILE__, __LINE__, "Unknown state %d",
18949742fdb4Schristos state);
1895e2b1b9c0Schristos /* Does not return. */
1896e2b1b9c0Schristos }
1897e2b1b9c0Schristos }
1898e2b1b9c0Schristos
18999742fdb4Schristos if (!done) {
1900e2b1b9c0Schristos return (ISC_R_UNEXPECTEDEND);
19019742fdb4Schristos }
1902e2b1b9c0Schristos
1903e2b1b9c0Schristos name->ndata = (unsigned char *)target->base + target->used;
1904e2b1b9c0Schristos name->labels = labels;
1905e2b1b9c0Schristos name->length = nused;
1906e2b1b9c0Schristos name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1907e2b1b9c0Schristos
1908e2b1b9c0Schristos isc_buffer_forward(source, cused);
1909e2b1b9c0Schristos isc_buffer_add(target, name->length);
1910e2b1b9c0Schristos
1911e2b1b9c0Schristos return (ISC_R_SUCCESS);
1912e2b1b9c0Schristos
1913e2b1b9c0Schristos full:
19149742fdb4Schristos if (nmax == DNS_NAME_MAXWIRE) {
1915e2b1b9c0Schristos /*
1916e2b1b9c0Schristos * The name did not fit even though we had a buffer
1917e2b1b9c0Schristos * big enough to fit a maximum-length name.
1918e2b1b9c0Schristos */
1919e2b1b9c0Schristos return (DNS_R_NAMETOOLONG);
19209742fdb4Schristos } else {
1921e2b1b9c0Schristos /*
1922e2b1b9c0Schristos * The name might fit if only the caller could give us a
1923e2b1b9c0Schristos * big enough buffer.
1924e2b1b9c0Schristos */
1925e2b1b9c0Schristos return (ISC_R_NOSPACE);
1926e2b1b9c0Schristos }
19279742fdb4Schristos }
1928e2b1b9c0Schristos
1929e2b1b9c0Schristos isc_result_t
dns_name_towire(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target)1930e2b1b9c0Schristos dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
19319742fdb4Schristos isc_buffer_t *target) {
1932e2b1b9c0Schristos return (dns_name_towire2(name, cctx, target, NULL));
1933e2b1b9c0Schristos }
1934e2b1b9c0Schristos
1935e2b1b9c0Schristos isc_result_t
dns_name_towire2(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target,uint16_t * comp_offsetp)1936e2b1b9c0Schristos dns_name_towire2(const dns_name_t *name, dns_compress_t *cctx,
19379742fdb4Schristos isc_buffer_t *target, uint16_t *comp_offsetp) {
1938e2b1b9c0Schristos unsigned int methods;
1939f2e20987Schristos uint16_t offset;
1940e2b1b9c0Schristos dns_name_t gp; /* Global compression prefix */
1941f2e20987Schristos bool gf; /* Global compression target found */
1942f2e20987Schristos uint16_t go; /* Global compression offset */
1943e2b1b9c0Schristos dns_offsets_t clo;
1944e2b1b9c0Schristos dns_name_t clname;
1945e2b1b9c0Schristos
1946e2b1b9c0Schristos /*
1947e2b1b9c0Schristos * Convert 'name' into wire format, compressing it as specified by the
1948e2b1b9c0Schristos * compression context 'cctx', and storing the result in 'target'.
1949e2b1b9c0Schristos */
1950e2b1b9c0Schristos
1951e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
1952e2b1b9c0Schristos REQUIRE(cctx != NULL);
1953e2b1b9c0Schristos REQUIRE(ISC_BUFFER_VALID(target));
1954e2b1b9c0Schristos
1955e2b1b9c0Schristos /*
1956e2b1b9c0Schristos * If this exact name was already rendered before, and the
1957e2b1b9c0Schristos * offset of the previously rendered name is passed to us, write
1958e2b1b9c0Schristos * a compression pointer directly.
1959e2b1b9c0Schristos */
1960e2b1b9c0Schristos methods = dns_compress_getmethods(cctx);
1961e2b1b9c0Schristos if (comp_offsetp != NULL && *comp_offsetp < 0x4000 &&
1962e2b1b9c0Schristos (name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
19639742fdb4Schristos (methods & DNS_COMPRESS_GLOBAL14) != 0)
19649742fdb4Schristos {
19659742fdb4Schristos if (ISC_UNLIKELY(target->length - target->used < 2)) {
1966e2b1b9c0Schristos return (ISC_R_NOSPACE);
19679742fdb4Schristos }
1968e2b1b9c0Schristos offset = *comp_offsetp;
1969e2b1b9c0Schristos offset |= 0xc000;
1970e2b1b9c0Schristos isc_buffer_putuint16(target, offset);
1971e2b1b9c0Schristos return (ISC_R_SUCCESS);
1972e2b1b9c0Schristos }
1973e2b1b9c0Schristos
1974e2b1b9c0Schristos /*
1975e2b1b9c0Schristos * If 'name' doesn't have an offsets table, make a clone which
1976e2b1b9c0Schristos * has one.
1977e2b1b9c0Schristos */
1978e2b1b9c0Schristos if (name->offsets == NULL) {
1979e2b1b9c0Schristos DNS_NAME_INIT(&clname, clo);
1980e2b1b9c0Schristos dns_name_clone(name, &clname);
1981e2b1b9c0Schristos name = &clname;
1982e2b1b9c0Schristos }
1983e2b1b9c0Schristos DNS_NAME_INIT(&gp, NULL);
1984e2b1b9c0Schristos
1985e2b1b9c0Schristos offset = target->used; /*XXX*/
1986e2b1b9c0Schristos
1987e2b1b9c0Schristos if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1988e2b1b9c0Schristos (methods & DNS_COMPRESS_GLOBAL14) != 0)
19899742fdb4Schristos {
1990e2b1b9c0Schristos gf = dns_compress_findglobal(cctx, name, &gp, &go);
19919742fdb4Schristos } else {
1992f2e20987Schristos gf = false;
19939742fdb4Schristos }
1994e2b1b9c0Schristos
1995e2b1b9c0Schristos /*
1996e2b1b9c0Schristos * If the offset is too high for 14 bit global compression, we're
1997e2b1b9c0Schristos * out of luck.
1998e2b1b9c0Schristos */
19999742fdb4Schristos if (gf && ISC_UNLIKELY(go >= 0x4000)) {
2000f2e20987Schristos gf = false;
20019742fdb4Schristos }
2002e2b1b9c0Schristos
2003e2b1b9c0Schristos /*
2004e2b1b9c0Schristos * Will the compression pointer reduce the message size?
2005e2b1b9c0Schristos */
20069742fdb4Schristos if (gf && (gp.length + 2) >= name->length) {
2007f2e20987Schristos gf = false;
20089742fdb4Schristos }
2009e2b1b9c0Schristos
2010e2b1b9c0Schristos if (gf) {
20119742fdb4Schristos if (ISC_UNLIKELY(target->length - target->used < gp.length)) {
2012e2b1b9c0Schristos return (ISC_R_NOSPACE);
20139742fdb4Schristos }
2014e2b1b9c0Schristos if (gp.length != 0) {
2015e2b1b9c0Schristos unsigned char *base = target->base;
2016e2b1b9c0Schristos (void)memmove(base + target->used, gp.ndata,
2017e2b1b9c0Schristos (size_t)gp.length);
2018e2b1b9c0Schristos }
2019e2b1b9c0Schristos isc_buffer_add(target, gp.length);
20209742fdb4Schristos if (ISC_UNLIKELY(target->length - target->used < 2)) {
2021e2b1b9c0Schristos return (ISC_R_NOSPACE);
20229742fdb4Schristos }
2023e2b1b9c0Schristos isc_buffer_putuint16(target, go | 0xc000);
2024e2b1b9c0Schristos if (gp.length != 0) {
2025e2b1b9c0Schristos dns_compress_add(cctx, name, &gp, offset);
20269742fdb4Schristos if (comp_offsetp != NULL) {
2027e2b1b9c0Schristos *comp_offsetp = offset;
20289742fdb4Schristos }
2029e2b1b9c0Schristos } else if (comp_offsetp != NULL) {
2030e2b1b9c0Schristos *comp_offsetp = go;
2031e2b1b9c0Schristos }
2032e2b1b9c0Schristos } else {
2033e2b1b9c0Schristos if (ISC_UNLIKELY(target->length - target->used < name->length))
20349742fdb4Schristos {
2035e2b1b9c0Schristos return (ISC_R_NOSPACE);
20369742fdb4Schristos }
2037e2b1b9c0Schristos if (name->length != 0) {
2038e2b1b9c0Schristos unsigned char *base = target->base;
2039e2b1b9c0Schristos (void)memmove(base + target->used, name->ndata,
2040e2b1b9c0Schristos (size_t)name->length);
2041e2b1b9c0Schristos }
2042e2b1b9c0Schristos isc_buffer_add(target, name->length);
2043e2b1b9c0Schristos dns_compress_add(cctx, name, name, offset);
20449742fdb4Schristos if (comp_offsetp != NULL) {
2045e2b1b9c0Schristos *comp_offsetp = offset;
2046e2b1b9c0Schristos }
20479742fdb4Schristos }
2048e2b1b9c0Schristos
2049e2b1b9c0Schristos return (ISC_R_SUCCESS);
2050e2b1b9c0Schristos }
2051e2b1b9c0Schristos
2052e2b1b9c0Schristos isc_result_t
dns_name_concatenate(const dns_name_t * prefix,const dns_name_t * suffix,dns_name_t * name,isc_buffer_t * target)2053e2b1b9c0Schristos dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix,
20549742fdb4Schristos dns_name_t *name, isc_buffer_t *target) {
2055e2b1b9c0Schristos unsigned char *ndata, *offsets;
2056e2b1b9c0Schristos unsigned int nrem, labels, prefix_length, length;
2057f2e20987Schristos bool copy_prefix = true;
2058f2e20987Schristos bool copy_suffix = true;
2059f2e20987Schristos bool absolute = false;
2060e2b1b9c0Schristos dns_name_t tmp_name;
2061e2b1b9c0Schristos dns_offsets_t odata;
2062e2b1b9c0Schristos
2063e2b1b9c0Schristos /*
2064e2b1b9c0Schristos * Concatenate 'prefix' and 'suffix'.
2065e2b1b9c0Schristos */
2066e2b1b9c0Schristos
2067e2b1b9c0Schristos REQUIRE(prefix == NULL || VALID_NAME(prefix));
2068e2b1b9c0Schristos REQUIRE(suffix == NULL || VALID_NAME(suffix));
2069e2b1b9c0Schristos REQUIRE(name == NULL || VALID_NAME(name));
2070e2b1b9c0Schristos REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
20719742fdb4Schristos (target == NULL && name != NULL &&
20729742fdb4Schristos ISC_BUFFER_VALID(name->buffer)));
20739742fdb4Schristos if (prefix == NULL || prefix->labels == 0) {
2074f2e20987Schristos copy_prefix = false;
20759742fdb4Schristos }
20769742fdb4Schristos if (suffix == NULL || suffix->labels == 0) {
2077f2e20987Schristos copy_suffix = false;
20789742fdb4Schristos }
20799742fdb4Schristos if (copy_prefix && (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2080f2e20987Schristos absolute = true;
2081e2b1b9c0Schristos REQUIRE(!copy_suffix);
2082e2b1b9c0Schristos }
2083e2b1b9c0Schristos if (name == NULL) {
2084e2b1b9c0Schristos DNS_NAME_INIT(&tmp_name, odata);
2085e2b1b9c0Schristos name = &tmp_name;
2086e2b1b9c0Schristos }
2087e2b1b9c0Schristos if (target == NULL) {
2088e2b1b9c0Schristos INSIST(name->buffer != NULL);
2089e2b1b9c0Schristos target = name->buffer;
2090e2b1b9c0Schristos isc_buffer_clear(name->buffer);
2091e2b1b9c0Schristos }
2092e2b1b9c0Schristos
2093e2b1b9c0Schristos REQUIRE(BINDABLE(name));
2094e2b1b9c0Schristos
2095e2b1b9c0Schristos /*
2096e2b1b9c0Schristos * Set up.
2097e2b1b9c0Schristos */
2098e2b1b9c0Schristos nrem = target->length - target->used;
2099e2b1b9c0Schristos ndata = (unsigned char *)target->base + target->used;
21009742fdb4Schristos if (nrem > DNS_NAME_MAXWIRE) {
2101e2b1b9c0Schristos nrem = DNS_NAME_MAXWIRE;
21029742fdb4Schristos }
2103e2b1b9c0Schristos length = 0;
2104e2b1b9c0Schristos prefix_length = 0;
2105e2b1b9c0Schristos labels = 0;
2106e2b1b9c0Schristos if (copy_prefix) {
2107e2b1b9c0Schristos prefix_length = prefix->length;
2108e2b1b9c0Schristos length += prefix_length;
2109e2b1b9c0Schristos labels += prefix->labels;
2110e2b1b9c0Schristos }
2111e2b1b9c0Schristos if (copy_suffix) {
2112e2b1b9c0Schristos length += suffix->length;
2113e2b1b9c0Schristos labels += suffix->labels;
2114e2b1b9c0Schristos }
2115e2b1b9c0Schristos if (length > DNS_NAME_MAXWIRE) {
2116e2b1b9c0Schristos MAKE_EMPTY(name);
2117e2b1b9c0Schristos return (DNS_R_NAMETOOLONG);
2118e2b1b9c0Schristos }
2119e2b1b9c0Schristos if (length > nrem) {
2120e2b1b9c0Schristos MAKE_EMPTY(name);
2121e2b1b9c0Schristos return (ISC_R_NOSPACE);
2122e2b1b9c0Schristos }
2123e2b1b9c0Schristos
2124e2b1b9c0Schristos if (copy_suffix) {
21259742fdb4Schristos if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2126f2e20987Schristos absolute = true;
21279742fdb4Schristos }
2128e2b1b9c0Schristos memmove(ndata + prefix_length, suffix->ndata, suffix->length);
2129e2b1b9c0Schristos }
2130e2b1b9c0Schristos
2131e2b1b9c0Schristos /*
2132e2b1b9c0Schristos * If 'prefix' and 'name' are the same object, and the object has
2133e2b1b9c0Schristos * a dedicated buffer, and we're using it, then we don't have to
2134e2b1b9c0Schristos * copy anything.
2135e2b1b9c0Schristos */
21369742fdb4Schristos if (copy_prefix && (prefix != name || prefix->buffer != target)) {
2137e2b1b9c0Schristos memmove(ndata, prefix->ndata, prefix_length);
21389742fdb4Schristos }
2139e2b1b9c0Schristos
2140e2b1b9c0Schristos name->ndata = ndata;
2141e2b1b9c0Schristos name->labels = labels;
2142e2b1b9c0Schristos name->length = length;
21439742fdb4Schristos if (absolute) {
2144e2b1b9c0Schristos name->attributes = DNS_NAMEATTR_ABSOLUTE;
21459742fdb4Schristos } else {
2146e2b1b9c0Schristos name->attributes = 0;
21479742fdb4Schristos }
2148e2b1b9c0Schristos
2149e2b1b9c0Schristos if (name->labels > 0 && name->offsets != NULL) {
2150e2b1b9c0Schristos INIT_OFFSETS(name, offsets, odata);
2151e2b1b9c0Schristos set_offsets(name, offsets, NULL);
2152e2b1b9c0Schristos }
2153e2b1b9c0Schristos
2154e2b1b9c0Schristos isc_buffer_add(target, name->length);
2155e2b1b9c0Schristos
2156e2b1b9c0Schristos return (ISC_R_SUCCESS);
2157e2b1b9c0Schristos }
2158e2b1b9c0Schristos
2159e2b1b9c0Schristos void
dns_name_split(const dns_name_t * name,unsigned int suffixlabels,dns_name_t * prefix,dns_name_t * suffix)2160e2b1b9c0Schristos dns_name_split(const dns_name_t *name, unsigned int suffixlabels,
2161e2b1b9c0Schristos dns_name_t *prefix, dns_name_t *suffix)
2162e2b1b9c0Schristos
2163e2b1b9c0Schristos {
2164e2b1b9c0Schristos unsigned int splitlabel;
2165e2b1b9c0Schristos
2166e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2167e2b1b9c0Schristos REQUIRE(suffixlabels > 0);
2168e2b1b9c0Schristos REQUIRE(suffixlabels <= name->labels);
2169e2b1b9c0Schristos REQUIRE(prefix != NULL || suffix != NULL);
21709742fdb4Schristos REQUIRE(prefix == NULL || (VALID_NAME(prefix) && BINDABLE(prefix)));
21719742fdb4Schristos REQUIRE(suffix == NULL || (VALID_NAME(suffix) && BINDABLE(suffix)));
2172e2b1b9c0Schristos
2173e2b1b9c0Schristos splitlabel = name->labels - suffixlabels;
2174e2b1b9c0Schristos
21759742fdb4Schristos if (prefix != NULL) {
2176e2b1b9c0Schristos dns_name_getlabelsequence(name, 0, splitlabel, prefix);
21779742fdb4Schristos }
2178e2b1b9c0Schristos
21799742fdb4Schristos if (suffix != NULL) {
21809742fdb4Schristos dns_name_getlabelsequence(name, splitlabel, suffixlabels,
21819742fdb4Schristos suffix);
21829742fdb4Schristos }
2183e2b1b9c0Schristos
2184e2b1b9c0Schristos return;
2185e2b1b9c0Schristos }
2186e2b1b9c0Schristos
21879742fdb4Schristos void
dns_name_dup(const dns_name_t * source,isc_mem_t * mctx,dns_name_t * target)21889742fdb4Schristos dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
2189e2b1b9c0Schristos /*
2190e2b1b9c0Schristos * Make 'target' a dynamically allocated copy of 'source'.
2191e2b1b9c0Schristos */
2192e2b1b9c0Schristos
2193e2b1b9c0Schristos REQUIRE(VALID_NAME(source));
2194e2b1b9c0Schristos REQUIRE(source->length > 0);
2195e2b1b9c0Schristos REQUIRE(VALID_NAME(target));
2196e2b1b9c0Schristos REQUIRE(BINDABLE(target));
2197e2b1b9c0Schristos
2198e2b1b9c0Schristos /*
2199e2b1b9c0Schristos * Make 'target' empty in case of failure.
2200e2b1b9c0Schristos */
2201e2b1b9c0Schristos MAKE_EMPTY(target);
2202e2b1b9c0Schristos
2203e2b1b9c0Schristos target->ndata = isc_mem_get(mctx, source->length);
2204e2b1b9c0Schristos
2205e2b1b9c0Schristos memmove(target->ndata, source->ndata, source->length);
2206e2b1b9c0Schristos
2207e2b1b9c0Schristos target->length = source->length;
2208e2b1b9c0Schristos target->labels = source->labels;
2209e2b1b9c0Schristos target->attributes = DNS_NAMEATTR_DYNAMIC;
22109742fdb4Schristos if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2211e2b1b9c0Schristos target->attributes |= DNS_NAMEATTR_ABSOLUTE;
22129742fdb4Schristos }
2213e2b1b9c0Schristos if (target->offsets != NULL) {
22149742fdb4Schristos if (source->offsets != NULL) {
2215e2b1b9c0Schristos memmove(target->offsets, source->offsets,
2216e2b1b9c0Schristos source->labels);
22179742fdb4Schristos } else {
2218e2b1b9c0Schristos set_offsets(target, target->offsets, NULL);
2219e2b1b9c0Schristos }
22209742fdb4Schristos }
2221e2b1b9c0Schristos }
2222e2b1b9c0Schristos
2223e2b1b9c0Schristos isc_result_t
dns_name_dupwithoffsets(const dns_name_t * source,isc_mem_t * mctx,dns_name_t * target)2224e2b1b9c0Schristos dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
22259742fdb4Schristos dns_name_t *target) {
2226e2b1b9c0Schristos /*
2227e2b1b9c0Schristos * Make 'target' a read-only dynamically allocated copy of 'source'.
2228e2b1b9c0Schristos * 'target' will also have a dynamically allocated offsets table.
2229e2b1b9c0Schristos */
2230e2b1b9c0Schristos
2231e2b1b9c0Schristos REQUIRE(VALID_NAME(source));
2232e2b1b9c0Schristos REQUIRE(source->length > 0);
2233e2b1b9c0Schristos REQUIRE(VALID_NAME(target));
2234e2b1b9c0Schristos REQUIRE(BINDABLE(target));
2235e2b1b9c0Schristos REQUIRE(target->offsets == NULL);
2236e2b1b9c0Schristos
2237e2b1b9c0Schristos /*
2238e2b1b9c0Schristos * Make 'target' empty in case of failure.
2239e2b1b9c0Schristos */
2240e2b1b9c0Schristos MAKE_EMPTY(target);
2241e2b1b9c0Schristos
2242e2b1b9c0Schristos target->ndata = isc_mem_get(mctx, source->length + source->labels);
2243e2b1b9c0Schristos
2244e2b1b9c0Schristos memmove(target->ndata, source->ndata, source->length);
2245e2b1b9c0Schristos
2246e2b1b9c0Schristos target->length = source->length;
2247e2b1b9c0Schristos target->labels = source->labels;
2248e2b1b9c0Schristos target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
2249e2b1b9c0Schristos DNS_NAMEATTR_READONLY;
22509742fdb4Schristos if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2251e2b1b9c0Schristos target->attributes |= DNS_NAMEATTR_ABSOLUTE;
22529742fdb4Schristos }
2253e2b1b9c0Schristos target->offsets = target->ndata + source->length;
22549742fdb4Schristos if (source->offsets != NULL) {
2255e2b1b9c0Schristos memmove(target->offsets, source->offsets, source->labels);
22569742fdb4Schristos } else {
2257e2b1b9c0Schristos set_offsets(target, target->offsets, NULL);
22589742fdb4Schristos }
2259e2b1b9c0Schristos
2260e2b1b9c0Schristos return (ISC_R_SUCCESS);
2261e2b1b9c0Schristos }
2262e2b1b9c0Schristos
2263e2b1b9c0Schristos void
dns_name_free(dns_name_t * name,isc_mem_t * mctx)2264e2b1b9c0Schristos dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
2265e2b1b9c0Schristos size_t size;
2266e2b1b9c0Schristos
2267e2b1b9c0Schristos /*
2268e2b1b9c0Schristos * Free 'name'.
2269e2b1b9c0Schristos */
2270e2b1b9c0Schristos
2271e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2272e2b1b9c0Schristos REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
2273e2b1b9c0Schristos
2274e2b1b9c0Schristos size = name->length;
22759742fdb4Schristos if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0) {
2276e2b1b9c0Schristos size += name->labels;
22779742fdb4Schristos }
2278e2b1b9c0Schristos isc_mem_put(mctx, name->ndata, size);
2279e2b1b9c0Schristos dns_name_invalidate(name);
2280e2b1b9c0Schristos }
2281e2b1b9c0Schristos
2282e2b1b9c0Schristos isc_result_t
dns_name_digest(const dns_name_t * name,dns_digestfunc_t digest,void * arg)2283e2b1b9c0Schristos dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) {
2284e2b1b9c0Schristos dns_name_t downname;
2285e2b1b9c0Schristos unsigned char data[256];
2286e2b1b9c0Schristos isc_buffer_t buffer;
2287e2b1b9c0Schristos isc_result_t result;
2288e2b1b9c0Schristos isc_region_t r;
2289e2b1b9c0Schristos
2290e2b1b9c0Schristos /*
2291e2b1b9c0Schristos * Send 'name' in DNSSEC canonical form to 'digest'.
2292e2b1b9c0Schristos */
2293e2b1b9c0Schristos
2294e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2295e2b1b9c0Schristos REQUIRE(digest != NULL);
2296e2b1b9c0Schristos
2297e2b1b9c0Schristos DNS_NAME_INIT(&downname, NULL);
2298e2b1b9c0Schristos
2299e2b1b9c0Schristos isc_buffer_init(&buffer, data, sizeof(data));
2300e2b1b9c0Schristos
2301e2b1b9c0Schristos result = dns_name_downcase(name, &downname, &buffer);
23029742fdb4Schristos if (result != ISC_R_SUCCESS) {
2303e2b1b9c0Schristos return (result);
23049742fdb4Schristos }
2305e2b1b9c0Schristos
2306e2b1b9c0Schristos isc_buffer_usedregion(&buffer, &r);
2307e2b1b9c0Schristos
2308e2b1b9c0Schristos return ((digest)(arg, &r));
2309e2b1b9c0Schristos }
2310e2b1b9c0Schristos
2311f2e20987Schristos bool
dns_name_dynamic(const dns_name_t * name)2312e2b1b9c0Schristos dns_name_dynamic(const dns_name_t *name) {
2313e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2314e2b1b9c0Schristos
2315e2b1b9c0Schristos /*
2316e2b1b9c0Schristos * Returns whether there is dynamic memory associated with this name.
2317e2b1b9c0Schristos */
2318e2b1b9c0Schristos
23199742fdb4Schristos return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ? true : false);
2320e2b1b9c0Schristos }
2321e2b1b9c0Schristos
2322e2b1b9c0Schristos isc_result_t
dns_name_print(const dns_name_t * name,FILE * stream)2323e2b1b9c0Schristos dns_name_print(const dns_name_t *name, FILE *stream) {
2324e2b1b9c0Schristos isc_result_t result;
2325e2b1b9c0Schristos isc_buffer_t b;
2326e2b1b9c0Schristos isc_region_t r;
2327e2b1b9c0Schristos char t[1024];
2328e2b1b9c0Schristos
2329e2b1b9c0Schristos /*
2330e2b1b9c0Schristos * Print 'name' on 'stream'.
2331e2b1b9c0Schristos */
2332e2b1b9c0Schristos
2333e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2334e2b1b9c0Schristos
2335e2b1b9c0Schristos isc_buffer_init(&b, t, sizeof(t));
2336f2e20987Schristos result = dns_name_totext(name, false, &b);
23379742fdb4Schristos if (result != ISC_R_SUCCESS) {
2338e2b1b9c0Schristos return (result);
23399742fdb4Schristos }
2340e2b1b9c0Schristos isc_buffer_usedregion(&b, &r);
2341e2b1b9c0Schristos fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
2342e2b1b9c0Schristos
2343e2b1b9c0Schristos return (ISC_R_SUCCESS);
2344e2b1b9c0Schristos }
2345e2b1b9c0Schristos
2346e2b1b9c0Schristos isc_result_t
dns_name_settotextfilter(dns_name_totextfilter_t * proc)23479742fdb4Schristos dns_name_settotextfilter(dns_name_totextfilter_t *proc) {
2348e2b1b9c0Schristos /*
2349e2b1b9c0Schristos * If we already have been here set / clear as appropriate.
2350e2b1b9c0Schristos */
23519742fdb4Schristos if (totext_filter_proc != NULL && proc != NULL) {
23529742fdb4Schristos if (totext_filter_proc == proc) {
2353e2b1b9c0Schristos return (ISC_R_SUCCESS);
2354e2b1b9c0Schristos }
23559742fdb4Schristos }
23569742fdb4Schristos if (proc == NULL && totext_filter_proc != NULL) {
23579742fdb4Schristos totext_filter_proc = NULL;
23589742fdb4Schristos return (ISC_R_SUCCESS);
2359e2b1b9c0Schristos }
2360e2b1b9c0Schristos
23619742fdb4Schristos totext_filter_proc = proc;
23629742fdb4Schristos
23639742fdb4Schristos return (ISC_R_SUCCESS);
2364e2b1b9c0Schristos }
2365e2b1b9c0Schristos
2366e2b1b9c0Schristos void
dns_name_format(const dns_name_t * name,char * cp,unsigned int size)2367e2b1b9c0Schristos dns_name_format(const dns_name_t *name, char *cp, unsigned int size) {
2368e2b1b9c0Schristos isc_result_t result;
2369e2b1b9c0Schristos isc_buffer_t buf;
2370e2b1b9c0Schristos
2371e2b1b9c0Schristos REQUIRE(size > 0);
2372e2b1b9c0Schristos
2373e2b1b9c0Schristos /*
2374e2b1b9c0Schristos * Leave room for null termination after buffer.
2375e2b1b9c0Schristos */
2376e2b1b9c0Schristos isc_buffer_init(&buf, cp, size - 1);
2377f2e20987Schristos result = dns_name_totext(name, true, &buf);
2378e2b1b9c0Schristos if (result == ISC_R_SUCCESS) {
237955ba2b39Schristos isc_buffer_putuint8(&buf, (uint8_t)'\0');
238055ba2b39Schristos } else {
2381e2b1b9c0Schristos snprintf(cp, size, "<unknown>");
2382e2b1b9c0Schristos }
238355ba2b39Schristos }
2384e2b1b9c0Schristos
2385e2b1b9c0Schristos /*
2386e2b1b9c0Schristos * dns_name_tostring() -- similar to dns_name_format() but allocates its own
2387e2b1b9c0Schristos * memory.
2388e2b1b9c0Schristos */
2389e2b1b9c0Schristos isc_result_t
dns_name_tostring(const dns_name_t * name,char ** target,isc_mem_t * mctx)2390e2b1b9c0Schristos dns_name_tostring(const dns_name_t *name, char **target, isc_mem_t *mctx) {
2391e2b1b9c0Schristos isc_result_t result;
2392e2b1b9c0Schristos isc_buffer_t buf;
2393e2b1b9c0Schristos isc_region_t reg;
2394e2b1b9c0Schristos char *p, txt[DNS_NAME_FORMATSIZE];
2395e2b1b9c0Schristos
2396e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2397e2b1b9c0Schristos REQUIRE(target != NULL && *target == NULL);
2398e2b1b9c0Schristos
2399e2b1b9c0Schristos isc_buffer_init(&buf, txt, sizeof(txt));
2400f2e20987Schristos result = dns_name_totext(name, false, &buf);
24019742fdb4Schristos if (result != ISC_R_SUCCESS) {
2402e2b1b9c0Schristos return (result);
24039742fdb4Schristos }
2404e2b1b9c0Schristos
2405e2b1b9c0Schristos isc_buffer_usedregion(&buf, ®);
2406e2b1b9c0Schristos p = isc_mem_allocate(mctx, reg.length + 1);
2407e2b1b9c0Schristos memmove(p, (char *)reg.base, (int)reg.length);
2408e2b1b9c0Schristos p[reg.length] = '\0';
2409e2b1b9c0Schristos
2410e2b1b9c0Schristos *target = p;
2411e2b1b9c0Schristos return (ISC_R_SUCCESS);
2412e2b1b9c0Schristos }
2413e2b1b9c0Schristos
2414e2b1b9c0Schristos /*
2415e2b1b9c0Schristos * dns_name_fromstring() -- convert directly from a string to a name,
2416e2b1b9c0Schristos * allocating memory as needed
2417e2b1b9c0Schristos */
2418e2b1b9c0Schristos isc_result_t
dns_name_fromstring(dns_name_t * target,const char * src,unsigned int options,isc_mem_t * mctx)2419e2b1b9c0Schristos dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options,
24209742fdb4Schristos isc_mem_t *mctx) {
2421e2b1b9c0Schristos return (dns_name_fromstring2(target, src, dns_rootname, options, mctx));
2422e2b1b9c0Schristos }
2423e2b1b9c0Schristos
2424e2b1b9c0Schristos isc_result_t
dns_name_fromstring2(dns_name_t * target,const char * src,const dns_name_t * origin,unsigned int options,isc_mem_t * mctx)2425e2b1b9c0Schristos dns_name_fromstring2(dns_name_t *target, const char *src,
2426e2b1b9c0Schristos const dns_name_t *origin, unsigned int options,
24279742fdb4Schristos isc_mem_t *mctx) {
2428e2b1b9c0Schristos isc_result_t result;
2429e2b1b9c0Schristos isc_buffer_t buf;
2430e2b1b9c0Schristos dns_fixedname_t fn;
2431e2b1b9c0Schristos dns_name_t *name;
2432e2b1b9c0Schristos
2433e2b1b9c0Schristos REQUIRE(src != NULL);
2434e2b1b9c0Schristos
2435e2b1b9c0Schristos isc_buffer_constinit(&buf, src, strlen(src));
2436e2b1b9c0Schristos isc_buffer_add(&buf, strlen(src));
24379742fdb4Schristos if (BINDABLE(target) && target->buffer != NULL) {
2438e2b1b9c0Schristos name = target;
24399742fdb4Schristos } else {
2440e2b1b9c0Schristos name = dns_fixedname_initname(&fn);
2441e2b1b9c0Schristos }
2442e2b1b9c0Schristos
2443e2b1b9c0Schristos result = dns_name_fromtext(name, &buf, origin, options, NULL);
24449742fdb4Schristos if (result != ISC_R_SUCCESS) {
2445e2b1b9c0Schristos return (result);
2446e2b1b9c0Schristos }
2447e2b1b9c0Schristos
24489742fdb4Schristos if (name != target) {
24499742fdb4Schristos result = dns_name_dupwithoffsets(name, mctx, target);
24509742fdb4Schristos }
24519742fdb4Schristos return (result);
24529742fdb4Schristos }
24539742fdb4Schristos
24549742fdb4Schristos static isc_result_t
name_copy(const dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)24558b4c8a26Schristos name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
2456fadf0758Schristos unsigned char *ndata = NULL;
2457e2b1b9c0Schristos
2458e2b1b9c0Schristos /*
2459e2b1b9c0Schristos * Make dest a copy of source.
2460e2b1b9c0Schristos */
2461e2b1b9c0Schristos
2462e2b1b9c0Schristos REQUIRE(BINDABLE(dest));
2463e2b1b9c0Schristos
2464e2b1b9c0Schristos /*
2465e2b1b9c0Schristos * Set up.
2466e2b1b9c0Schristos */
24678b4c8a26Schristos if (target->length - target->used < source->length) {
2468e2b1b9c0Schristos return (ISC_R_NOSPACE);
24698b4c8a26Schristos }
2470e2b1b9c0Schristos
2471e2b1b9c0Schristos ndata = (unsigned char *)target->base + target->used;
2472e2b1b9c0Schristos dest->ndata = target->base;
2473e2b1b9c0Schristos
24748b4c8a26Schristos if (source->length != 0) {
2475e2b1b9c0Schristos memmove(ndata, source->ndata, source->length);
24768b4c8a26Schristos }
2477e2b1b9c0Schristos
2478e2b1b9c0Schristos dest->ndata = ndata;
2479e2b1b9c0Schristos dest->labels = source->labels;
2480e2b1b9c0Schristos dest->length = source->length;
24818b4c8a26Schristos if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2482e2b1b9c0Schristos dest->attributes = DNS_NAMEATTR_ABSOLUTE;
24838b4c8a26Schristos } else {
2484e2b1b9c0Schristos dest->attributes = 0;
24858b4c8a26Schristos }
2486e2b1b9c0Schristos
2487e2b1b9c0Schristos if (dest->labels > 0 && dest->offsets != NULL) {
2488fadf0758Schristos if (source->offsets != NULL && source->labels != 0) {
2489e2b1b9c0Schristos memmove(dest->offsets, source->offsets, source->labels);
24908b4c8a26Schristos } else {
2491e2b1b9c0Schristos set_offsets(dest, dest->offsets, NULL);
2492e2b1b9c0Schristos }
24938b4c8a26Schristos }
2494e2b1b9c0Schristos
2495e2b1b9c0Schristos isc_buffer_add(target, dest->length);
2496e2b1b9c0Schristos
2497e2b1b9c0Schristos return (ISC_R_SUCCESS);
2498e2b1b9c0Schristos }
2499e2b1b9c0Schristos
25008b4c8a26Schristos isc_result_t
dns_name_copy(const dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)25019742fdb4Schristos dns_name_copy(const dns_name_t *source, dns_name_t *dest,
25029742fdb4Schristos isc_buffer_t *target) {
25038b4c8a26Schristos REQUIRE(VALID_NAME(source));
25048b4c8a26Schristos REQUIRE(VALID_NAME(dest));
25058b4c8a26Schristos REQUIRE(target != NULL);
25068b4c8a26Schristos
25078b4c8a26Schristos return (name_copy(source, dest, target));
25088b4c8a26Schristos }
25098b4c8a26Schristos
25108b4c8a26Schristos void
dns_name_copynf(const dns_name_t * source,dns_name_t * dest)25119742fdb4Schristos dns_name_copynf(const dns_name_t *source, dns_name_t *dest) {
25128b4c8a26Schristos REQUIRE(VALID_NAME(source));
25138b4c8a26Schristos REQUIRE(VALID_NAME(dest));
25148b4c8a26Schristos REQUIRE(dest->buffer != NULL);
25158b4c8a26Schristos
25168b4c8a26Schristos isc_buffer_clear(dest->buffer);
25178b4c8a26Schristos RUNTIME_CHECK(name_copy(source, dest, dest->buffer) == ISC_R_SUCCESS);
25188b4c8a26Schristos }
25198b4c8a26Schristos
2520e2b1b9c0Schristos /*
2521e2b1b9c0Schristos * Service Discovery Prefixes RFC 6763.
2522e2b1b9c0Schristos */
2523e2b1b9c0Schristos static unsigned char b_dns_sd_udp_data[] = "\001b\007_dns-sd\004_udp";
2524e2b1b9c0Schristos static unsigned char b_dns_sd_udp_offsets[] = { 0, 2, 10 };
2525e2b1b9c0Schristos static unsigned char db_dns_sd_udp_data[] = "\002db\007_dns-sd\004_udp";
2526e2b1b9c0Schristos static unsigned char db_dns_sd_udp_offsets[] = { 0, 3, 11 };
2527e2b1b9c0Schristos static unsigned char r_dns_sd_udp_data[] = "\001r\007_dns-sd\004_udp";
2528e2b1b9c0Schristos static unsigned char r_dns_sd_udp_offsets[] = { 0, 2, 10 };
2529e2b1b9c0Schristos static unsigned char dr_dns_sd_udp_data[] = "\002dr\007_dns-sd\004_udp";
2530e2b1b9c0Schristos static unsigned char dr_dns_sd_udp_offsets[] = { 0, 3, 11 };
2531e2b1b9c0Schristos static unsigned char lb_dns_sd_udp_data[] = "\002lb\007_dns-sd\004_udp";
2532e2b1b9c0Schristos static unsigned char lb_dns_sd_udp_offsets[] = { 0, 3, 11 };
2533e2b1b9c0Schristos
2534e2b1b9c0Schristos static dns_name_t const dns_sd[] = {
2535e2b1b9c0Schristos DNS_NAME_INITNONABSOLUTE(b_dns_sd_udp_data, b_dns_sd_udp_offsets),
2536e2b1b9c0Schristos DNS_NAME_INITNONABSOLUTE(db_dns_sd_udp_data, db_dns_sd_udp_offsets),
2537e2b1b9c0Schristos DNS_NAME_INITNONABSOLUTE(r_dns_sd_udp_data, r_dns_sd_udp_offsets),
2538e2b1b9c0Schristos DNS_NAME_INITNONABSOLUTE(dr_dns_sd_udp_data, dr_dns_sd_udp_offsets),
2539e2b1b9c0Schristos DNS_NAME_INITNONABSOLUTE(lb_dns_sd_udp_data, lb_dns_sd_udp_offsets)
2540e2b1b9c0Schristos };
2541e2b1b9c0Schristos
2542f2e20987Schristos bool
dns_name_isdnssd(const dns_name_t * name)2543e2b1b9c0Schristos dns_name_isdnssd(const dns_name_t *name) {
2544e2b1b9c0Schristos size_t i;
2545e2b1b9c0Schristos dns_name_t prefix;
2546e2b1b9c0Schristos
2547e2b1b9c0Schristos if (dns_name_countlabels(name) > 3U) {
2548e2b1b9c0Schristos dns_name_init(&prefix, NULL);
2549e2b1b9c0Schristos dns_name_getlabelsequence(name, 0, 3, &prefix);
25509742fdb4Schristos for (i = 0; i < (sizeof(dns_sd) / sizeof(dns_sd[0])); i++) {
25519742fdb4Schristos if (dns_name_equal(&prefix, &dns_sd[i])) {
2552f2e20987Schristos return (true);
2553e2b1b9c0Schristos }
25549742fdb4Schristos }
25559742fdb4Schristos }
2556e2b1b9c0Schristos
2557f2e20987Schristos return (false);
2558e2b1b9c0Schristos }
2559e2b1b9c0Schristos
2560e2b1b9c0Schristos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
2561e2b1b9c0Schristos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
2562e2b1b9c0Schristos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
2563e2b1b9c0Schristos
2564e2b1b9c0Schristos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
2565e2b1b9c0Schristos
2566e2b1b9c0Schristos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
2567e2b1b9c0Schristos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
2568e2b1b9c0Schristos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
2569e2b1b9c0Schristos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
2570e2b1b9c0Schristos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
2571e2b1b9c0Schristos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
2572e2b1b9c0Schristos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
2573e2b1b9c0Schristos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
2574e2b1b9c0Schristos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
2575e2b1b9c0Schristos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
2576e2b1b9c0Schristos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
2577e2b1b9c0Schristos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
2578e2b1b9c0Schristos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
2579e2b1b9c0Schristos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
2580e2b1b9c0Schristos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
2581e2b1b9c0Schristos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
2582e2b1b9c0Schristos
2583e2b1b9c0Schristos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
2584e2b1b9c0Schristos
2585e2b1b9c0Schristos static dns_name_t const rfc1918names[] = {
2586e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
2587e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
2588e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
2589e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
2590e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
2591e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
2592e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
2593e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
2594e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
2595e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
2596e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
2597e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
2598e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
2599e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
2600e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
2601e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
2602e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
2603e2b1b9c0Schristos DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
2604e2b1b9c0Schristos };
2605e2b1b9c0Schristos
2606f2e20987Schristos bool
dns_name_isrfc1918(const dns_name_t * name)2607e2b1b9c0Schristos dns_name_isrfc1918(const dns_name_t *name) {
2608e2b1b9c0Schristos size_t i;
2609e2b1b9c0Schristos
26109742fdb4Schristos for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
26119742fdb4Schristos if (dns_name_issubdomain(name, &rfc1918names[i])) {
2612f2e20987Schristos return (true);
26139742fdb4Schristos }
26149742fdb4Schristos }
2615f2e20987Schristos return (false);
2616e2b1b9c0Schristos }
2617e2b1b9c0Schristos
2618e2b1b9c0Schristos static unsigned char ulaoffsets[] = { 0, 2, 4, 8, 13 };
2619e2b1b9c0Schristos static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA";
2620e2b1b9c0Schristos static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA";
2621e2b1b9c0Schristos
26229742fdb4Schristos static dns_name_t const ulanames[] = { DNS_NAME_INITABSOLUTE(ip6fc, ulaoffsets),
26239742fdb4Schristos DNS_NAME_INITABSOLUTE(ip6fd,
26249742fdb4Schristos ulaoffsets) };
2625e2b1b9c0Schristos
2626f2e20987Schristos bool
dns_name_isula(const dns_name_t * name)2627e2b1b9c0Schristos dns_name_isula(const dns_name_t *name) {
2628e2b1b9c0Schristos size_t i;
2629e2b1b9c0Schristos
26309742fdb4Schristos for (i = 0; i < (sizeof(ulanames) / sizeof(*ulanames)); i++) {
26319742fdb4Schristos if (dns_name_issubdomain(name, &ulanames[i])) {
2632f2e20987Schristos return (true);
26339742fdb4Schristos }
26349742fdb4Schristos }
2635f2e20987Schristos return (false);
2636e2b1b9c0Schristos }
2637e2b1b9c0Schristos
2638e2b1b9c0Schristos /*
2639e2b1b9c0Schristos * Use a simple table as we don't want all the locale stuff
2640e2b1b9c0Schristos * associated with ishexdigit().
2641e2b1b9c0Schristos */
26429742fdb4Schristos const char ishex[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2643e2b1b9c0Schristos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2644e2b1b9c0Schristos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2645e2b1b9c0Schristos 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2646e2b1b9c0Schristos 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2647e2b1b9c0Schristos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2648e2b1b9c0Schristos 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26499742fdb4Schristos 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2650e2b1b9c0Schristos
2651f2e20987Schristos bool
dns_name_istat(const dns_name_t * name)2652e2b1b9c0Schristos dns_name_istat(const dns_name_t *name) {
2653e2b1b9c0Schristos unsigned char len;
2654e2b1b9c0Schristos const unsigned char *ndata;
2655e2b1b9c0Schristos
2656e2b1b9c0Schristos REQUIRE(VALID_NAME(name));
2657e2b1b9c0Schristos
26589742fdb4Schristos if (name->labels < 1) {
2659f2e20987Schristos return (false);
26609742fdb4Schristos }
2661e2b1b9c0Schristos
2662e2b1b9c0Schristos ndata = name->ndata;
2663e2b1b9c0Schristos len = ndata[0];
2664e2b1b9c0Schristos INSIST(len <= name->length);
2665e2b1b9c0Schristos ndata++;
2666e2b1b9c0Schristos
2667e2b1b9c0Schristos /*
2668e2b1b9c0Schristos * Is there at least one trust anchor reported and is the
2669f2e20987Schristos * label length consistent with a trust-anchor-telemetry label.
2670e2b1b9c0Schristos */
2671e2b1b9c0Schristos if ((len < 8) || (len - 3) % 5 != 0) {
2672f2e20987Schristos return (false);
2673e2b1b9c0Schristos }
2674e2b1b9c0Schristos
26759742fdb4Schristos if (ndata[0] != '_' || maptolower[ndata[1]] != 't' ||
26769742fdb4Schristos maptolower[ndata[2]] != 'a')
26779742fdb4Schristos {
2678f2e20987Schristos return (false);
2679e2b1b9c0Schristos }
2680e2b1b9c0Schristos ndata += 3;
2681e2b1b9c0Schristos len -= 3;
2682e2b1b9c0Schristos
2683e2b1b9c0Schristos while (len > 0) {
2684e2b1b9c0Schristos INSIST(len >= 5);
2685e2b1b9c0Schristos if (ndata[0] != '-' || !ishex[ndata[1]] || !ishex[ndata[2]] ||
26869742fdb4Schristos !ishex[ndata[3]] || !ishex[ndata[4]])
26879742fdb4Schristos {
2688f2e20987Schristos return (false);
2689e2b1b9c0Schristos }
2690e2b1b9c0Schristos ndata += 5;
2691e2b1b9c0Schristos len -= 5;
2692e2b1b9c0Schristos }
2693f2e20987Schristos return (true);
2694e2b1b9c0Schristos }
2695