15185a700Sflorian /*
25185a700Sflorian * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
35185a700Sflorian *
45185a700Sflorian * Permission to use, copy, modify, and/or distribute this software for any
55185a700Sflorian * purpose with or without fee is hereby granted, provided that the above
65185a700Sflorian * copyright notice and this permission notice appear in all copies.
75185a700Sflorian *
85185a700Sflorian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
95185a700Sflorian * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
105185a700Sflorian * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
115185a700Sflorian * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
125185a700Sflorian * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
135185a700Sflorian * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
145185a700Sflorian * PERFORMANCE OF THIS SOFTWARE.
155185a700Sflorian */
165185a700Sflorian
17*1fb015a8Sflorian /* $Id: name.c,v 1.14 2020/09/14 08:40:43 florian Exp $ */
185185a700Sflorian
195185a700Sflorian /*! \file */
205185a700Sflorian #include <ctype.h>
215185a700Sflorian #include <stdlib.h>
225185a700Sflorian #include <isc/buffer.h>
235185a700Sflorian #include <isc/hash.h>
245185a700Sflorian
255185a700Sflorian #include <string.h>
265185a700Sflorian #include <isc/util.h>
275185a700Sflorian
285185a700Sflorian #include <dns/compress.h>
295185a700Sflorian #include <dns/fixedname.h>
305185a700Sflorian #include <dns/name.h>
315185a700Sflorian #include <dns/result.h>
325185a700Sflorian
335185a700Sflorian typedef enum {
345185a700Sflorian ft_init = 0,
355185a700Sflorian ft_start,
365185a700Sflorian ft_ordinary,
375185a700Sflorian ft_initialescape,
385185a700Sflorian ft_escape,
395185a700Sflorian ft_escdecimal,
405185a700Sflorian ft_at
415185a700Sflorian } ft_state;
425185a700Sflorian
435185a700Sflorian typedef enum {
445185a700Sflorian fw_start = 0,
455185a700Sflorian fw_ordinary,
465185a700Sflorian fw_newcurrent
475185a700Sflorian } fw_state;
485185a700Sflorian
495185a700Sflorian static char digitvalue[256] = {
505185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
515185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
525185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
535185a700Sflorian 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
545185a700Sflorian -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
555185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
565185a700Sflorian -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
575185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
585185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
595185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
605185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
615185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
625185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
635185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
645185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
655185a700Sflorian -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
665185a700Sflorian };
675185a700Sflorian
685185a700Sflorian static unsigned char maptolower[] = {
695185a700Sflorian 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
705185a700Sflorian 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
715185a700Sflorian 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
725185a700Sflorian 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
735185a700Sflorian 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
745185a700Sflorian 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
755185a700Sflorian 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
765185a700Sflorian 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
775185a700Sflorian 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
785185a700Sflorian 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
795185a700Sflorian 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
805185a700Sflorian 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
815185a700Sflorian 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
825185a700Sflorian 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
835185a700Sflorian 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
845185a700Sflorian 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
855185a700Sflorian 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
865185a700Sflorian 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
875185a700Sflorian 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
885185a700Sflorian 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
895185a700Sflorian 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
905185a700Sflorian 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
915185a700Sflorian 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
925185a700Sflorian 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
935185a700Sflorian 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
945185a700Sflorian 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
955185a700Sflorian 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
965185a700Sflorian 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
975185a700Sflorian 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
985185a700Sflorian 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
995185a700Sflorian 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
1005185a700Sflorian 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
1015185a700Sflorian };
1025185a700Sflorian
1035185a700Sflorian #define CONVERTTOASCII(c)
1045185a700Sflorian #define CONVERTFROMASCII(c)
1055185a700Sflorian
1065185a700Sflorian #define INIT_OFFSETS(name, var, default_offsets) \
1075185a700Sflorian if ((name)->offsets != NULL) \
1085185a700Sflorian var = (name)->offsets; \
1095185a700Sflorian else \
1105185a700Sflorian var = (default_offsets);
1115185a700Sflorian
1125185a700Sflorian #define SETUP_OFFSETS(name, var, default_offsets) \
1135185a700Sflorian if ((name)->offsets != NULL) \
1145185a700Sflorian var = (name)->offsets; \
1155185a700Sflorian else { \
1165185a700Sflorian var = (default_offsets); \
1175185a700Sflorian set_offsets(name, var, NULL); \
1185185a700Sflorian }
1195185a700Sflorian
1205185a700Sflorian /*%
1215185a700Sflorian * Note: If additional attributes are added that should not be set for
1225185a700Sflorian * empty names, MAKE_EMPTY() must be changed so it clears them.
1235185a700Sflorian */
1245185a700Sflorian #define MAKE_EMPTY(name) \
1255185a700Sflorian do { \
1265185a700Sflorian name->ndata = NULL; \
1275185a700Sflorian name->length = 0; \
1285185a700Sflorian name->labels = 0; \
1295185a700Sflorian name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
1305185a700Sflorian } while (0);
1315185a700Sflorian
1325185a700Sflorian /*%
1335185a700Sflorian * A name is "bindable" if it can be set to point to a new value, i.e.
1345185a700Sflorian * name->ndata and name->length may be changed.
1355185a700Sflorian */
1365185a700Sflorian #define BINDABLE(name) \
1375185a700Sflorian ((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
1385185a700Sflorian == 0)
1395185a700Sflorian
1405185a700Sflorian /*%
1415185a700Sflorian * Note that the name data must be a char array, not a string
1425185a700Sflorian * literal, to avoid compiler warnings about discarding
1435185a700Sflorian * the const attribute of a string.
1445185a700Sflorian */
1455185a700Sflorian static unsigned char root_ndata[] = { "" };
1465185a700Sflorian static unsigned char root_offsets[] = { 0 };
1475185a700Sflorian
1485185a700Sflorian static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets);
1495185a700Sflorian
1505185a700Sflorian /* XXXDCL make const? */
1515185a700Sflorian dns_name_t *dns_rootname = &root;
1525185a700Sflorian
1535185a700Sflorian static void
1545185a700Sflorian set_offsets(const dns_name_t *name, unsigned char *offsets,
1555185a700Sflorian dns_name_t *set_name);
1565185a700Sflorian
1575185a700Sflorian void
dns_name_init(dns_name_t * name,unsigned char * offsets)1585185a700Sflorian dns_name_init(dns_name_t *name, unsigned char *offsets) {
1595185a700Sflorian /*
1605185a700Sflorian * Initialize 'name'.
1615185a700Sflorian */
162f1dacf25Sflorian name->ndata = NULL;
163f1dacf25Sflorian name->length = 0;
164f1dacf25Sflorian name->labels = 0;
165f1dacf25Sflorian name->attributes = 0;
166f1dacf25Sflorian name->offsets = offsets;
167f1dacf25Sflorian name->buffer = NULL;
168f1dacf25Sflorian ISC_LINK_INIT(name, link);
169f1dacf25Sflorian ISC_LIST_INIT(name->list);
170f1dacf25Sflorian
1715185a700Sflorian }
1725185a700Sflorian
1735185a700Sflorian void
dns_name_reset(dns_name_t * name)1745185a700Sflorian dns_name_reset(dns_name_t *name) {
1755185a700Sflorian REQUIRE(BINDABLE(name));
1765185a700Sflorian
177f1dacf25Sflorian name->ndata = NULL;
178f1dacf25Sflorian name->length = 0;
179f1dacf25Sflorian name->labels = 0;
180f1dacf25Sflorian name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
181f1dacf25Sflorian if (name->buffer != NULL)
182f1dacf25Sflorian isc_buffer_clear(name->buffer);
1835185a700Sflorian }
1845185a700Sflorian
1855185a700Sflorian void
dns_name_invalidate(dns_name_t * name)1865185a700Sflorian dns_name_invalidate(dns_name_t *name) {
1875185a700Sflorian /*
1885185a700Sflorian * Make 'name' invalid.
1895185a700Sflorian */
1905185a700Sflorian
1915185a700Sflorian name->ndata = NULL;
1925185a700Sflorian name->length = 0;
1935185a700Sflorian name->labels = 0;
1945185a700Sflorian name->attributes = 0;
1955185a700Sflorian name->offsets = NULL;
1965185a700Sflorian name->buffer = NULL;
1975185a700Sflorian ISC_LINK_INIT(name, link);
1985185a700Sflorian }
1995185a700Sflorian
2005185a700Sflorian void
dns_name_setbuffer(dns_name_t * name,isc_buffer_t * buffer)2015185a700Sflorian dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
2025185a700Sflorian /*
2035185a700Sflorian * Dedicate a buffer for use with 'name'.
2045185a700Sflorian */
2055185a700Sflorian
2065185a700Sflorian REQUIRE((buffer != NULL && name->buffer == NULL) ||
2075185a700Sflorian (buffer == NULL));
2085185a700Sflorian
2095185a700Sflorian name->buffer = buffer;
2105185a700Sflorian }
2115185a700Sflorian
212*1fb015a8Sflorian int
dns_name_isabsolute(const dns_name_t * name)2135185a700Sflorian dns_name_isabsolute(const dns_name_t *name) {
2145185a700Sflorian
2155185a700Sflorian /*
2165185a700Sflorian * Does 'name' end in the root label?
2175185a700Sflorian */
2185185a700Sflorian
2195185a700Sflorian if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
220*1fb015a8Sflorian return (1);
221*1fb015a8Sflorian return (0);
2225185a700Sflorian }
2235185a700Sflorian
2245185a700Sflorian unsigned int
dns_name_hash(dns_name_t * name,int case_sensitive)225*1fb015a8Sflorian dns_name_hash(dns_name_t *name, int case_sensitive) {
2265185a700Sflorian unsigned int length;
2275185a700Sflorian
2285185a700Sflorian /*
2295185a700Sflorian * Provide a hash value for 'name'.
2305185a700Sflorian */
2315185a700Sflorian
2325185a700Sflorian if (name->labels == 0)
2335185a700Sflorian return (0);
2345185a700Sflorian
2355185a700Sflorian length = name->length;
2365185a700Sflorian if (length > 16)
2375185a700Sflorian length = 16;
2385185a700Sflorian
2395185a700Sflorian return (isc_hash_function_reverse(name->ndata, length,
2405185a700Sflorian case_sensitive, NULL));
2415185a700Sflorian }
2425185a700Sflorian
2435185a700Sflorian dns_namereln_t
dns_name_fullcompare(const dns_name_t * name1,const dns_name_t * name2,int * orderp,unsigned int * nlabelsp)2445185a700Sflorian dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
2455185a700Sflorian int *orderp, unsigned int *nlabelsp)
2465185a700Sflorian {
2475185a700Sflorian unsigned int l1, l2, l, count1, count2, count, nlabels;
2485185a700Sflorian int cdiff, ldiff, chdiff;
2495185a700Sflorian unsigned char *label1, *label2;
2505185a700Sflorian unsigned char *offsets1, *offsets2;
2515185a700Sflorian dns_offsets_t odata1, odata2;
2525185a700Sflorian dns_namereln_t namereln = dns_namereln_none;
2535185a700Sflorian
2545185a700Sflorian /*
2555185a700Sflorian * Determine the relative ordering under the DNSSEC order relation of
2565185a700Sflorian * 'name1' and 'name2', and also determine the hierarchical
2575185a700Sflorian * relationship of the names.
2585185a700Sflorian *
2595185a700Sflorian * Note: It makes no sense for one of the names to be relative and the
2605185a700Sflorian * other absolute. If both names are relative, then to be meaningfully
2615185a700Sflorian * compared the caller must ensure that they are both relative to the
2625185a700Sflorian * same domain.
2635185a700Sflorian */
2645185a700Sflorian
2655185a700Sflorian REQUIRE(orderp != NULL);
2665185a700Sflorian REQUIRE(nlabelsp != NULL);
2675185a700Sflorian /*
2685185a700Sflorian * Either name1 is absolute and name2 is absolute, or neither is.
2695185a700Sflorian */
2705185a700Sflorian REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
2715185a700Sflorian (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
2725185a700Sflorian
2735185a700Sflorian if (name1 == name2) {
2745185a700Sflorian *orderp = 0;
2755185a700Sflorian *nlabelsp = name1->labels;
2765185a700Sflorian return (dns_namereln_equal);
2775185a700Sflorian }
2785185a700Sflorian
2795185a700Sflorian SETUP_OFFSETS(name1, offsets1, odata1);
2805185a700Sflorian SETUP_OFFSETS(name2, offsets2, odata2);
2815185a700Sflorian
2825185a700Sflorian nlabels = 0;
2835185a700Sflorian l1 = name1->labels;
2845185a700Sflorian l2 = name2->labels;
2855185a700Sflorian if (l2 > l1) {
2865185a700Sflorian l = l1;
2875185a700Sflorian ldiff = 0 - (l2 - l1);
2885185a700Sflorian } else {
2895185a700Sflorian l = l2;
2905185a700Sflorian ldiff = l1 - l2;
2915185a700Sflorian }
2925185a700Sflorian
2935185a700Sflorian offsets1 += l1;
2945185a700Sflorian offsets2 += l2;
2955185a700Sflorian
2965185a700Sflorian while (l > 0) {
2975185a700Sflorian l--;
2985185a700Sflorian offsets1--;
2995185a700Sflorian offsets2--;
3005185a700Sflorian label1 = &name1->ndata[*offsets1];
3015185a700Sflorian label2 = &name2->ndata[*offsets2];
3025185a700Sflorian count1 = *label1++;
3035185a700Sflorian count2 = *label2++;
3045185a700Sflorian
3055185a700Sflorian /*
3065185a700Sflorian * We dropped bitstring labels, and we don't support any
3075185a700Sflorian * other extended label types.
3085185a700Sflorian */
3095185a700Sflorian INSIST(count1 <= 63 && count2 <= 63);
3105185a700Sflorian
3115185a700Sflorian cdiff = (int)count1 - (int)count2;
3125185a700Sflorian if (cdiff < 0)
3135185a700Sflorian count = count1;
3145185a700Sflorian else
3155185a700Sflorian count = count2;
3165185a700Sflorian
3175185a700Sflorian /* Loop unrolled for performance */
3185185a700Sflorian while (count > 3) {
3195185a700Sflorian chdiff = (int)maptolower[label1[0]] -
3205185a700Sflorian (int)maptolower[label2[0]];
3215185a700Sflorian if (chdiff != 0) {
3225185a700Sflorian *orderp = chdiff;
3235185a700Sflorian goto done;
3245185a700Sflorian }
3255185a700Sflorian chdiff = (int)maptolower[label1[1]] -
3265185a700Sflorian (int)maptolower[label2[1]];
3275185a700Sflorian if (chdiff != 0) {
3285185a700Sflorian *orderp = chdiff;
3295185a700Sflorian goto done;
3305185a700Sflorian }
3315185a700Sflorian chdiff = (int)maptolower[label1[2]] -
3325185a700Sflorian (int)maptolower[label2[2]];
3335185a700Sflorian if (chdiff != 0) {
3345185a700Sflorian *orderp = chdiff;
3355185a700Sflorian goto done;
3365185a700Sflorian }
3375185a700Sflorian chdiff = (int)maptolower[label1[3]] -
3385185a700Sflorian (int)maptolower[label2[3]];
3395185a700Sflorian if (chdiff != 0) {
3405185a700Sflorian *orderp = chdiff;
3415185a700Sflorian goto done;
3425185a700Sflorian }
3435185a700Sflorian count -= 4;
3445185a700Sflorian label1 += 4;
3455185a700Sflorian label2 += 4;
3465185a700Sflorian }
3475185a700Sflorian while (count-- > 0) {
3485185a700Sflorian chdiff = (int)maptolower[*label1++] -
3495185a700Sflorian (int)maptolower[*label2++];
3505185a700Sflorian if (chdiff != 0) {
3515185a700Sflorian *orderp = chdiff;
3525185a700Sflorian goto done;
3535185a700Sflorian }
3545185a700Sflorian }
3555185a700Sflorian if (cdiff != 0) {
3565185a700Sflorian *orderp = cdiff;
3575185a700Sflorian goto done;
3585185a700Sflorian }
3595185a700Sflorian nlabels++;
3605185a700Sflorian }
3615185a700Sflorian
3625185a700Sflorian *orderp = ldiff;
3635185a700Sflorian if (ldiff < 0)
3645185a700Sflorian namereln = dns_namereln_contains;
3655185a700Sflorian else if (ldiff > 0)
3665185a700Sflorian namereln = dns_namereln_subdomain;
3675185a700Sflorian else
3685185a700Sflorian namereln = dns_namereln_equal;
3695185a700Sflorian *nlabelsp = nlabels;
3705185a700Sflorian return (namereln);
3715185a700Sflorian
3725185a700Sflorian done:
3735185a700Sflorian *nlabelsp = nlabels;
3745185a700Sflorian if (nlabels > 0)
3755185a700Sflorian namereln = dns_namereln_commonancestor;
3765185a700Sflorian
3775185a700Sflorian return (namereln);
3785185a700Sflorian }
3795185a700Sflorian
3805185a700Sflorian int
dns_name_compare(const dns_name_t * name1,const dns_name_t * name2)3815185a700Sflorian dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
3825185a700Sflorian int order;
3835185a700Sflorian unsigned int nlabels;
3845185a700Sflorian
3855185a700Sflorian /*
3865185a700Sflorian * Determine the relative ordering under the DNSSEC order relation of
3875185a700Sflorian * 'name1' and 'name2'.
3885185a700Sflorian *
3895185a700Sflorian * Note: It makes no sense for one of the names to be relative and the
3905185a700Sflorian * other absolute. If both names are relative, then to be meaningfully
3915185a700Sflorian * compared the caller must ensure that they are both relative to the
3925185a700Sflorian * same domain.
3935185a700Sflorian */
3945185a700Sflorian
3955185a700Sflorian (void)dns_name_fullcompare(name1, name2, &order, &nlabels);
3965185a700Sflorian
3975185a700Sflorian return (order);
3985185a700Sflorian }
3995185a700Sflorian
400*1fb015a8Sflorian int
dns_name_equal(const dns_name_t * name1,const dns_name_t * name2)4015185a700Sflorian dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
4025185a700Sflorian unsigned int l, count;
4035185a700Sflorian unsigned char c;
4045185a700Sflorian unsigned char *label1, *label2;
4055185a700Sflorian
4065185a700Sflorian /*
4075185a700Sflorian * Are 'name1' and 'name2' equal?
4085185a700Sflorian *
4095185a700Sflorian * Note: It makes no sense for one of the names to be relative and the
4105185a700Sflorian * other absolute. If both names are relative, then to be meaningfully
4115185a700Sflorian * compared the caller must ensure that they are both relative to the
4125185a700Sflorian * same domain.
4135185a700Sflorian */
4145185a700Sflorian
4155185a700Sflorian /*
4165185a700Sflorian * Either name1 is absolute and name2 is absolute, or neither is.
4175185a700Sflorian */
4185185a700Sflorian REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
4195185a700Sflorian (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
4205185a700Sflorian
4215185a700Sflorian if (name1 == name2)
422*1fb015a8Sflorian return (1);
4235185a700Sflorian
4245185a700Sflorian if (name1->length != name2->length)
425*1fb015a8Sflorian return (0);
4265185a700Sflorian
4275185a700Sflorian l = name1->labels;
4285185a700Sflorian
4295185a700Sflorian if (l != name2->labels)
430*1fb015a8Sflorian return (0);
4315185a700Sflorian
4325185a700Sflorian label1 = name1->ndata;
4335185a700Sflorian label2 = name2->ndata;
4345185a700Sflorian while (l-- > 0) {
4355185a700Sflorian count = *label1++;
4365185a700Sflorian if (count != *label2++)
437*1fb015a8Sflorian return (0);
4385185a700Sflorian
4395185a700Sflorian INSIST(count <= 63); /* no bitstring support */
4405185a700Sflorian
4415185a700Sflorian /* Loop unrolled for performance */
4425185a700Sflorian while (count > 3) {
4435185a700Sflorian c = maptolower[label1[0]];
4445185a700Sflorian if (c != maptolower[label2[0]])
445*1fb015a8Sflorian return (0);
4465185a700Sflorian c = maptolower[label1[1]];
4475185a700Sflorian if (c != maptolower[label2[1]])
448*1fb015a8Sflorian return (0);
4495185a700Sflorian c = maptolower[label1[2]];
4505185a700Sflorian if (c != maptolower[label2[2]])
451*1fb015a8Sflorian return (0);
4525185a700Sflorian c = maptolower[label1[3]];
4535185a700Sflorian if (c != maptolower[label2[3]])
454*1fb015a8Sflorian return (0);
4555185a700Sflorian count -= 4;
4565185a700Sflorian label1 += 4;
4575185a700Sflorian label2 += 4;
4585185a700Sflorian }
4595185a700Sflorian while (count-- > 0) {
4605185a700Sflorian c = maptolower[*label1++];
4615185a700Sflorian if (c != maptolower[*label2++])
462*1fb015a8Sflorian return (0);
4635185a700Sflorian }
4645185a700Sflorian }
4655185a700Sflorian
466*1fb015a8Sflorian return (1);
4675185a700Sflorian }
4685185a700Sflorian
469*1fb015a8Sflorian int
dns_name_caseequal(const dns_name_t * name1,const dns_name_t * name2)4705185a700Sflorian dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
4715185a700Sflorian
4725185a700Sflorian /*
4735185a700Sflorian * Are 'name1' and 'name2' equal?
4745185a700Sflorian *
4755185a700Sflorian * Note: It makes no sense for one of the names to be relative and the
4765185a700Sflorian * other absolute. If both names are relative, then to be meaningfully
4775185a700Sflorian * compared the caller must ensure that they are both relative to the
4785185a700Sflorian * same domain.
4795185a700Sflorian */
4805185a700Sflorian
4815185a700Sflorian /*
4825185a700Sflorian * Either name1 is absolute and name2 is absolute, or neither is.
4835185a700Sflorian */
4845185a700Sflorian REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
4855185a700Sflorian (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
4865185a700Sflorian
4875185a700Sflorian if (name1->length != name2->length)
488*1fb015a8Sflorian return (0);
4895185a700Sflorian
4905185a700Sflorian if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
491*1fb015a8Sflorian return (0);
4925185a700Sflorian
493*1fb015a8Sflorian return (1);
4945185a700Sflorian }
4955185a700Sflorian
496*1fb015a8Sflorian int
dns_name_issubdomain(const dns_name_t * name1,const dns_name_t * name2)4975185a700Sflorian dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
4985185a700Sflorian int order;
4995185a700Sflorian unsigned int nlabels;
5005185a700Sflorian dns_namereln_t namereln;
5015185a700Sflorian
5025185a700Sflorian /*
5035185a700Sflorian * Is 'name1' a subdomain of 'name2'?
5045185a700Sflorian *
5055185a700Sflorian * Note: It makes no sense for one of the names to be relative and the
5065185a700Sflorian * other absolute. If both names are relative, then to be meaningfully
5075185a700Sflorian * compared the caller must ensure that they are both relative to the
5085185a700Sflorian * same domain.
5095185a700Sflorian */
5105185a700Sflorian
5115185a700Sflorian namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
5125185a700Sflorian if (namereln == dns_namereln_subdomain ||
5135185a700Sflorian namereln == dns_namereln_equal)
514*1fb015a8Sflorian return (1);
5155185a700Sflorian
516*1fb015a8Sflorian return (0);
5175185a700Sflorian }
5185185a700Sflorian
5195185a700Sflorian unsigned int
dns_name_countlabels(const dns_name_t * name)5205185a700Sflorian dns_name_countlabels(const dns_name_t *name) {
5215185a700Sflorian /*
5225185a700Sflorian * How many labels does 'name' have?
5235185a700Sflorian */
5245185a700Sflorian
5255185a700Sflorian ENSURE(name->labels <= 128);
5265185a700Sflorian
5275185a700Sflorian return (name->labels);
5285185a700Sflorian }
5295185a700Sflorian
5305185a700Sflorian void
dns_name_getlabel(const dns_name_t * name,unsigned int n,dns_label_t * label)5315185a700Sflorian dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
5325185a700Sflorian unsigned char *offsets;
5335185a700Sflorian dns_offsets_t odata;
5345185a700Sflorian
5355185a700Sflorian /*
5365185a700Sflorian * Make 'label' refer to the 'n'th least significant label of 'name'.
5375185a700Sflorian */
5385185a700Sflorian
5395185a700Sflorian REQUIRE(name->labels > 0);
5405185a700Sflorian REQUIRE(n < name->labels);
5415185a700Sflorian REQUIRE(label != NULL);
5425185a700Sflorian
5435185a700Sflorian SETUP_OFFSETS(name, offsets, odata);
5445185a700Sflorian
5455185a700Sflorian label->base = &name->ndata[offsets[n]];
5465185a700Sflorian if (n == name->labels - 1)
5475185a700Sflorian label->length = name->length - offsets[n];
5485185a700Sflorian else
5495185a700Sflorian label->length = offsets[n + 1] - offsets[n];
5505185a700Sflorian }
5515185a700Sflorian
5525185a700Sflorian void
dns_name_getlabelsequence(const dns_name_t * source,unsigned int first,unsigned int n,dns_name_t * target)5535185a700Sflorian dns_name_getlabelsequence(const dns_name_t *source,
5545185a700Sflorian unsigned int first, unsigned int n,
5555185a700Sflorian dns_name_t *target)
5565185a700Sflorian {
5575185a700Sflorian unsigned char *offsets;
5585185a700Sflorian dns_offsets_t odata;
5595185a700Sflorian unsigned int firstoffset, endoffset;
5605185a700Sflorian
5615185a700Sflorian /*
5625185a700Sflorian * Make 'target' refer to the 'n' labels including and following
5635185a700Sflorian * 'first' in 'source'.
5645185a700Sflorian */
5655185a700Sflorian
5665185a700Sflorian REQUIRE(first <= source->labels);
5675185a700Sflorian REQUIRE(n <= source->labels - first); /* note first+n could overflow */
5685185a700Sflorian REQUIRE(BINDABLE(target));
5695185a700Sflorian
5705185a700Sflorian SETUP_OFFSETS(source, offsets, odata);
5715185a700Sflorian
5725185a700Sflorian if (first == source->labels)
5735185a700Sflorian firstoffset = source->length;
5745185a700Sflorian else
5755185a700Sflorian firstoffset = offsets[first];
5765185a700Sflorian
5775185a700Sflorian if (first + n == source->labels)
5785185a700Sflorian endoffset = source->length;
5795185a700Sflorian else
5805185a700Sflorian endoffset = offsets[first + n];
5815185a700Sflorian
5825185a700Sflorian target->ndata = &source->ndata[firstoffset];
5835185a700Sflorian target->length = endoffset - firstoffset;
5845185a700Sflorian
5855185a700Sflorian if (first + n == source->labels && n > 0 &&
5865185a700Sflorian (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
5875185a700Sflorian target->attributes |= DNS_NAMEATTR_ABSOLUTE;
5885185a700Sflorian else
5895185a700Sflorian target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
5905185a700Sflorian
5915185a700Sflorian target->labels = n;
5925185a700Sflorian
5935185a700Sflorian /*
5945185a700Sflorian * If source and target are the same, and we're making target
5955185a700Sflorian * a prefix of source, the offsets table is correct already
5965185a700Sflorian * so we don't need to call set_offsets().
5975185a700Sflorian */
5985185a700Sflorian if (target->offsets != NULL &&
5995185a700Sflorian (target != source || first != 0))
6005185a700Sflorian set_offsets(target, target->offsets, NULL);
6015185a700Sflorian }
6025185a700Sflorian
6035185a700Sflorian void
dns_name_clone(const dns_name_t * source,dns_name_t * target)6045185a700Sflorian dns_name_clone(const dns_name_t *source, dns_name_t *target) {
6055185a700Sflorian
6065185a700Sflorian /*
6075185a700Sflorian * Make 'target' refer to the same name as 'source'.
6085185a700Sflorian */
6095185a700Sflorian
6105185a700Sflorian REQUIRE(BINDABLE(target));
6115185a700Sflorian
6125185a700Sflorian target->ndata = source->ndata;
6135185a700Sflorian target->length = source->length;
6145185a700Sflorian target->labels = source->labels;
6155185a700Sflorian target->attributes = source->attributes &
6165185a700Sflorian (unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
6175185a700Sflorian DNS_NAMEATTR_DYNOFFSETS);
6185185a700Sflorian if (target->offsets != NULL && source->labels > 0) {
6195185a700Sflorian if (source->offsets != NULL)
6205185a700Sflorian memmove(target->offsets, source->offsets,
6215185a700Sflorian source->labels);
6225185a700Sflorian else
6235185a700Sflorian set_offsets(target, target->offsets, NULL);
6245185a700Sflorian }
6255185a700Sflorian }
6265185a700Sflorian
6275185a700Sflorian void
dns_name_fromregion(dns_name_t * name,const isc_region_t * r)6285185a700Sflorian dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
6295185a700Sflorian unsigned char *offsets;
6305185a700Sflorian dns_offsets_t odata;
6315185a700Sflorian unsigned int len;
6325185a700Sflorian isc_region_t r2;
6335185a700Sflorian
6345185a700Sflorian /*
6355185a700Sflorian * Make 'name' refer to region 'r'.
6365185a700Sflorian */
6375185a700Sflorian
6385185a700Sflorian REQUIRE(r != NULL);
6395185a700Sflorian REQUIRE(BINDABLE(name));
6405185a700Sflorian
6415185a700Sflorian INIT_OFFSETS(name, offsets, odata);
6425185a700Sflorian
6435185a700Sflorian if (name->buffer != NULL) {
6445185a700Sflorian isc_buffer_clear(name->buffer);
6455185a700Sflorian isc_buffer_availableregion(name->buffer, &r2);
6465185a700Sflorian len = (r->length < r2.length) ? r->length : r2.length;
6475185a700Sflorian if (len > DNS_NAME_MAXWIRE)
6485185a700Sflorian len = DNS_NAME_MAXWIRE;
6495185a700Sflorian if (len != 0)
6505185a700Sflorian memmove(r2.base, r->base, len);
6515185a700Sflorian name->ndata = r2.base;
6525185a700Sflorian name->length = len;
6535185a700Sflorian } else {
6545185a700Sflorian name->ndata = r->base;
6555185a700Sflorian name->length = (r->length <= DNS_NAME_MAXWIRE) ?
6565185a700Sflorian r->length : DNS_NAME_MAXWIRE;
6575185a700Sflorian }
6585185a700Sflorian
6595185a700Sflorian if (r->length > 0)
6605185a700Sflorian set_offsets(name, offsets, name);
6615185a700Sflorian else {
6625185a700Sflorian name->labels = 0;
6635185a700Sflorian name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
6645185a700Sflorian }
6655185a700Sflorian
6665185a700Sflorian if (name->buffer != NULL)
6675185a700Sflorian isc_buffer_add(name->buffer, name->length);
6685185a700Sflorian }
6695185a700Sflorian
6705185a700Sflorian void
dns_name_toregion(dns_name_t * name,isc_region_t * r)6715185a700Sflorian dns_name_toregion(dns_name_t *name, isc_region_t *r) {
6725185a700Sflorian /*
6735185a700Sflorian * Make 'r' refer to 'name'.
6745185a700Sflorian */
6755185a700Sflorian
6765185a700Sflorian REQUIRE(r != NULL);
6775185a700Sflorian
678f1dacf25Sflorian r->base = name->ndata;
679f1dacf25Sflorian r->length = name->length;
6805185a700Sflorian }
6815185a700Sflorian
6825185a700Sflorian 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)6835185a700Sflorian dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
6845185a700Sflorian const dns_name_t *origin, unsigned int options,
6855185a700Sflorian isc_buffer_t *target)
6865185a700Sflorian {
6875185a700Sflorian unsigned char *ndata, *label = NULL;
6885185a700Sflorian char *tdata;
6895185a700Sflorian char c;
6905185a700Sflorian ft_state state;
6915185a700Sflorian unsigned int value = 0, count = 0;
6925185a700Sflorian unsigned int n1 = 0, n2 = 0;
6935185a700Sflorian unsigned int tlen, nrem, nused, digits = 0, labels, tused;
694*1fb015a8Sflorian int done;
6955185a700Sflorian unsigned char *offsets;
6965185a700Sflorian dns_offsets_t odata;
697*1fb015a8Sflorian int downcase;
6985185a700Sflorian
6995185a700Sflorian /*
7005185a700Sflorian * Convert the textual representation of a DNS name at source
7015185a700Sflorian * into uncompressed wire form stored in target.
7025185a700Sflorian *
7035185a700Sflorian * Notes:
7045185a700Sflorian * Relative domain names will have 'origin' appended to them
7055185a700Sflorian * unless 'origin' is NULL, in which case relative domain names
7065185a700Sflorian * will remain relative.
7075185a700Sflorian */
7085185a700Sflorian
709*1fb015a8Sflorian downcase = (options & DNS_NAME_DOWNCASE) != 0;
7105185a700Sflorian
7115185a700Sflorian if (target == NULL && name->buffer != NULL) {
7125185a700Sflorian target = name->buffer;
7135185a700Sflorian isc_buffer_clear(target);
7145185a700Sflorian }
7155185a700Sflorian
7165185a700Sflorian REQUIRE(BINDABLE(name));
7175185a700Sflorian
7185185a700Sflorian INIT_OFFSETS(name, offsets, odata);
7195185a700Sflorian offsets[0] = 0;
7205185a700Sflorian
7215185a700Sflorian /*
7225185a700Sflorian * Make 'name' empty in case of failure.
7235185a700Sflorian */
7245185a700Sflorian MAKE_EMPTY(name);
7255185a700Sflorian
7265185a700Sflorian /*
7275185a700Sflorian * Set up the state machine.
7285185a700Sflorian */
7295185a700Sflorian tdata = (char *)source->base + source->current;
7305185a700Sflorian tlen = isc_buffer_remaininglength(source);
7315185a700Sflorian tused = 0;
7325185a700Sflorian ndata = isc_buffer_used(target);
7335185a700Sflorian nrem = isc_buffer_availablelength(target);
7345185a700Sflorian if (nrem > 255)
7355185a700Sflorian nrem = 255;
7365185a700Sflorian nused = 0;
7375185a700Sflorian labels = 0;
738*1fb015a8Sflorian done = 0;
7395185a700Sflorian state = ft_init;
7405185a700Sflorian
7415185a700Sflorian while (nrem > 0 && tlen > 0 && !done) {
7425185a700Sflorian c = *tdata++;
7435185a700Sflorian tlen--;
7445185a700Sflorian tused++;
7455185a700Sflorian
7465185a700Sflorian switch (state) {
7475185a700Sflorian case ft_init:
7485185a700Sflorian /*
7495185a700Sflorian * Is this the root name?
7505185a700Sflorian */
7515185a700Sflorian if (c == '.') {
7525185a700Sflorian if (tlen != 0)
7535185a700Sflorian return (DNS_R_EMPTYLABEL);
7545185a700Sflorian labels++;
7555185a700Sflorian *ndata++ = 0;
7565185a700Sflorian nrem--;
7575185a700Sflorian nused++;
758*1fb015a8Sflorian done = 1;
7595185a700Sflorian break;
7605185a700Sflorian }
7615185a700Sflorian if (c == '@' && tlen == 0) {
7625185a700Sflorian state = ft_at;
7635185a700Sflorian break;
7645185a700Sflorian }
7655185a700Sflorian
7665185a700Sflorian /* FALLTHROUGH */
7675185a700Sflorian case ft_start:
7685185a700Sflorian label = ndata;
7695185a700Sflorian ndata++;
7705185a700Sflorian nrem--;
7715185a700Sflorian nused++;
7725185a700Sflorian count = 0;
7735185a700Sflorian if (c == '\\') {
7745185a700Sflorian state = ft_initialescape;
7755185a700Sflorian break;
7765185a700Sflorian }
7775185a700Sflorian state = ft_ordinary;
7785185a700Sflorian if (nrem == 0)
7795185a700Sflorian return (ISC_R_NOSPACE);
7805185a700Sflorian /* FALLTHROUGH */
7815185a700Sflorian case ft_ordinary:
7825185a700Sflorian if (c == '.') {
7835185a700Sflorian if (count == 0)
7845185a700Sflorian return (DNS_R_EMPTYLABEL);
7855185a700Sflorian *label = count;
7865185a700Sflorian labels++;
7875185a700Sflorian INSIST(labels <= 127);
7885185a700Sflorian offsets[labels] = nused;
7895185a700Sflorian if (tlen == 0) {
7905185a700Sflorian labels++;
7915185a700Sflorian *ndata++ = 0;
7925185a700Sflorian nrem--;
7935185a700Sflorian nused++;
794*1fb015a8Sflorian done = 1;
7955185a700Sflorian }
7965185a700Sflorian state = ft_start;
7975185a700Sflorian } else if (c == '\\') {
7985185a700Sflorian state = ft_escape;
7995185a700Sflorian } else {
8005185a700Sflorian if (count >= 63)
8015185a700Sflorian return (DNS_R_LABELTOOLONG);
8025185a700Sflorian count++;
8035185a700Sflorian CONVERTTOASCII(c);
8045185a700Sflorian if (downcase)
8055185a700Sflorian c = maptolower[c & 0xff];
8065185a700Sflorian *ndata++ = c;
8075185a700Sflorian nrem--;
8085185a700Sflorian nused++;
8095185a700Sflorian }
8105185a700Sflorian break;
8115185a700Sflorian case ft_initialescape:
8125185a700Sflorian if (c == '[') {
8135185a700Sflorian /*
8145185a700Sflorian * This looks like a bitstring label, which
8155185a700Sflorian * was deprecated. Intentionally drop it.
8165185a700Sflorian */
8175185a700Sflorian return (DNS_R_BADLABELTYPE);
8185185a700Sflorian }
8195185a700Sflorian state = ft_escape;
8205185a700Sflorian POST(state);
8215185a700Sflorian /* FALLTHROUGH */
8225185a700Sflorian case ft_escape:
8235185a700Sflorian if (!isdigit(c & 0xff)) {
8245185a700Sflorian if (count >= 63)
8255185a700Sflorian return (DNS_R_LABELTOOLONG);
8265185a700Sflorian count++;
8275185a700Sflorian CONVERTTOASCII(c);
8285185a700Sflorian if (downcase)
8295185a700Sflorian c = maptolower[c & 0xff];
8305185a700Sflorian *ndata++ = c;
8315185a700Sflorian nrem--;
8325185a700Sflorian nused++;
8335185a700Sflorian state = ft_ordinary;
8345185a700Sflorian break;
8355185a700Sflorian }
8365185a700Sflorian digits = 0;
8375185a700Sflorian value = 0;
8385185a700Sflorian state = ft_escdecimal;
8395185a700Sflorian /* FALLTHROUGH */
8405185a700Sflorian case ft_escdecimal:
8415185a700Sflorian if (!isdigit(c & 0xff))
8425185a700Sflorian return (DNS_R_BADESCAPE);
8435185a700Sflorian value *= 10;
8445185a700Sflorian value += digitvalue[c & 0xff];
8455185a700Sflorian digits++;
8465185a700Sflorian if (digits == 3) {
8475185a700Sflorian if (value > 255)
8485185a700Sflorian return (DNS_R_BADESCAPE);
8495185a700Sflorian if (count >= 63)
8505185a700Sflorian return (DNS_R_LABELTOOLONG);
8515185a700Sflorian count++;
8525185a700Sflorian if (downcase)
8535185a700Sflorian value = maptolower[value];
8545185a700Sflorian *ndata++ = value;
8555185a700Sflorian nrem--;
8565185a700Sflorian nused++;
8575185a700Sflorian state = ft_ordinary;
8585185a700Sflorian }
8595185a700Sflorian break;
8605185a700Sflorian default:
8615185a700Sflorian FATAL_ERROR(__FILE__, __LINE__,
8625185a700Sflorian "Unexpected state %d", state);
8635185a700Sflorian /* Does not return. */
8645185a700Sflorian }
8655185a700Sflorian }
8665185a700Sflorian
8675185a700Sflorian if (!done) {
8685185a700Sflorian if (nrem == 0)
8695185a700Sflorian return (ISC_R_NOSPACE);
8705185a700Sflorian INSIST(tlen == 0);
8715185a700Sflorian if (state != ft_ordinary && state != ft_at)
8725185a700Sflorian return (ISC_R_UNEXPECTEDEND);
8735185a700Sflorian if (state == ft_ordinary) {
8745185a700Sflorian INSIST(count != 0);
8755185a700Sflorian *label = count;
8765185a700Sflorian labels++;
8775185a700Sflorian INSIST(labels <= 127);
8785185a700Sflorian offsets[labels] = nused;
8795185a700Sflorian }
8805185a700Sflorian if (origin != NULL) {
8815185a700Sflorian if (nrem < origin->length)
8825185a700Sflorian return (ISC_R_NOSPACE);
8835185a700Sflorian label = origin->ndata;
8845185a700Sflorian n1 = origin->length;
8855185a700Sflorian nrem -= n1;
8865185a700Sflorian POST(nrem);
8875185a700Sflorian while (n1 > 0) {
8885185a700Sflorian n2 = *label++;
8895185a700Sflorian INSIST(n2 <= 63); /* no bitstring support */
8905185a700Sflorian *ndata++ = n2;
8915185a700Sflorian n1 -= n2 + 1;
8925185a700Sflorian nused += n2 + 1;
8935185a700Sflorian while (n2 > 0) {
8945185a700Sflorian c = *label++;
8955185a700Sflorian if (downcase)
8965185a700Sflorian c = maptolower[c & 0xff];
8975185a700Sflorian *ndata++ = c;
8985185a700Sflorian n2--;
8995185a700Sflorian }
9005185a700Sflorian labels++;
9015185a700Sflorian if (n1 > 0) {
9025185a700Sflorian INSIST(labels <= 127);
9035185a700Sflorian offsets[labels] = nused;
9045185a700Sflorian }
9055185a700Sflorian }
9065185a700Sflorian if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
9075185a700Sflorian name->attributes |= DNS_NAMEATTR_ABSOLUTE;
9085185a700Sflorian }
9095185a700Sflorian } else
9105185a700Sflorian name->attributes |= DNS_NAMEATTR_ABSOLUTE;
9115185a700Sflorian
9125185a700Sflorian name->ndata = (unsigned char *)target->base + target->used;
9135185a700Sflorian name->labels = labels;
9145185a700Sflorian name->length = nused;
9155185a700Sflorian
9165185a700Sflorian isc_buffer_forward(source, tused);
9175185a700Sflorian isc_buffer_add(target, name->length);
9185185a700Sflorian
9195185a700Sflorian return (ISC_R_SUCCESS);
9205185a700Sflorian }
9215185a700Sflorian
9225185a700Sflorian isc_result_t
dns_name_totext(dns_name_t * name,int omit_final_dot,isc_buffer_t * target)923*1fb015a8Sflorian dns_name_totext(dns_name_t *name, int omit_final_dot,
9245185a700Sflorian isc_buffer_t *target)
9255185a700Sflorian {
9265185a700Sflorian unsigned int options = DNS_NAME_MASTERFILE;
9275185a700Sflorian
9285185a700Sflorian if (omit_final_dot)
9295185a700Sflorian options |= DNS_NAME_OMITFINALDOT;
9305185a700Sflorian return (dns_name_totext2(name, options, target));
9315185a700Sflorian }
9325185a700Sflorian
9335185a700Sflorian isc_result_t
dns_name_totext2(dns_name_t * name,unsigned int options,isc_buffer_t * target)9345185a700Sflorian dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
9355185a700Sflorian {
9365185a700Sflorian unsigned char *ndata;
9375185a700Sflorian char *tdata;
9385185a700Sflorian unsigned int nlen, tlen;
9395185a700Sflorian unsigned char c;
9405185a700Sflorian unsigned int trem, count;
9415185a700Sflorian unsigned int labels;
942*1fb015a8Sflorian int saw_root = 0;
943*1fb015a8Sflorian int omit_final_dot = options & DNS_NAME_OMITFINALDOT;
9445185a700Sflorian
9455185a700Sflorian /*
9465185a700Sflorian * This function assumes the name is in proper uncompressed
9475185a700Sflorian * wire format.
9485185a700Sflorian */
9495185a700Sflorian
9505185a700Sflorian ndata = name->ndata;
9515185a700Sflorian nlen = name->length;
9525185a700Sflorian labels = name->labels;
9535185a700Sflorian tdata = isc_buffer_used(target);
9545185a700Sflorian tlen = isc_buffer_availablelength(target);
9555185a700Sflorian
9565185a700Sflorian trem = tlen;
9575185a700Sflorian
9585185a700Sflorian if (labels == 0 && nlen == 0) {
9595185a700Sflorian /*
9605185a700Sflorian * Special handling for an empty name.
9615185a700Sflorian */
9625185a700Sflorian if (trem == 0)
9635185a700Sflorian return (ISC_R_NOSPACE);
9645185a700Sflorian
9655185a700Sflorian /*
9665185a700Sflorian * The names of these booleans are misleading in this case.
9675185a700Sflorian * This empty name is not necessarily from the root node of
9685185a700Sflorian * the DNS root zone, nor is a final dot going to be included.
9695185a700Sflorian * They need to be set this way, though, to keep the "@"
9705185a700Sflorian * from being trounced.
9715185a700Sflorian */
972*1fb015a8Sflorian saw_root = 1;
973*1fb015a8Sflorian omit_final_dot = 0;
9745185a700Sflorian *tdata++ = '@';
9755185a700Sflorian trem--;
9765185a700Sflorian
9775185a700Sflorian /*
9785185a700Sflorian * Skip the while() loop.
9795185a700Sflorian */
9805185a700Sflorian nlen = 0;
9815185a700Sflorian } else if (nlen == 1 && labels == 1 && *ndata == '\0') {
9825185a700Sflorian /*
9835185a700Sflorian * Special handling for the root label.
9845185a700Sflorian */
9855185a700Sflorian if (trem == 0)
9865185a700Sflorian return (ISC_R_NOSPACE);
9875185a700Sflorian
988*1fb015a8Sflorian saw_root = 1;
989*1fb015a8Sflorian omit_final_dot = 0;
9905185a700Sflorian *tdata++ = '.';
9915185a700Sflorian trem--;
9925185a700Sflorian
9935185a700Sflorian /*
9945185a700Sflorian * Skip the while() loop.
9955185a700Sflorian */
9965185a700Sflorian nlen = 0;
9975185a700Sflorian }
9985185a700Sflorian
9995185a700Sflorian while (labels > 0 && nlen > 0 && trem > 0) {
10005185a700Sflorian labels--;
10015185a700Sflorian count = *ndata++;
10025185a700Sflorian nlen--;
10035185a700Sflorian if (count == 0) {
1004*1fb015a8Sflorian saw_root = 1;
10055185a700Sflorian break;
10065185a700Sflorian }
10075185a700Sflorian if (count < 64) {
10085185a700Sflorian INSIST(nlen >= count);
10095185a700Sflorian while (count > 0) {
10105185a700Sflorian c = *ndata;
10115185a700Sflorian switch (c) {
10125185a700Sflorian /* Special modifiers in zone files. */
10135185a700Sflorian case 0x40: /* '@' */
10145185a700Sflorian case 0x24: /* '$' */
10155185a700Sflorian if ((options & DNS_NAME_MASTERFILE) == 0)
10165185a700Sflorian goto no_escape;
10175185a700Sflorian /* FALLTHROUGH */
10185185a700Sflorian case 0x22: /* '"' */
10195185a700Sflorian case 0x28: /* '(' */
10205185a700Sflorian case 0x29: /* ')' */
10215185a700Sflorian case 0x2E: /* '.' */
10225185a700Sflorian case 0x3B: /* ';' */
10235185a700Sflorian case 0x5C: /* '\\' */
10245185a700Sflorian if (trem < 2)
10255185a700Sflorian return (ISC_R_NOSPACE);
10265185a700Sflorian *tdata++ = '\\';
10275185a700Sflorian CONVERTFROMASCII(c);
10285185a700Sflorian *tdata++ = c;
10295185a700Sflorian ndata++;
10305185a700Sflorian trem -= 2;
10315185a700Sflorian nlen--;
10325185a700Sflorian break;
10335185a700Sflorian no_escape:
10345185a700Sflorian default:
10355185a700Sflorian if (c > 0x20 && c < 0x7f) {
10365185a700Sflorian if (trem == 0)
10375185a700Sflorian return (ISC_R_NOSPACE);
10385185a700Sflorian CONVERTFROMASCII(c);
10395185a700Sflorian *tdata++ = c;
10405185a700Sflorian ndata++;
10415185a700Sflorian trem--;
10425185a700Sflorian nlen--;
10435185a700Sflorian } else {
10445185a700Sflorian if (trem < 4)
10455185a700Sflorian return (ISC_R_NOSPACE);
10465185a700Sflorian *tdata++ = 0x5c;
10475185a700Sflorian *tdata++ = 0x30 +
10485185a700Sflorian ((c / 100) % 10);
10495185a700Sflorian *tdata++ = 0x30 +
10505185a700Sflorian ((c / 10) % 10);
10515185a700Sflorian *tdata++ = 0x30 + (c % 10);
10525185a700Sflorian trem -= 4;
10535185a700Sflorian ndata++;
10545185a700Sflorian nlen--;
10555185a700Sflorian }
10565185a700Sflorian }
10575185a700Sflorian count--;
10585185a700Sflorian }
10595185a700Sflorian } else {
10605185a700Sflorian FATAL_ERROR(__FILE__, __LINE__,
10615185a700Sflorian "Unexpected label type %02x", count);
10625185a700Sflorian /* NOTREACHED */
10635185a700Sflorian }
10645185a700Sflorian
10655185a700Sflorian /*
10665185a700Sflorian * The following assumes names are absolute. If not, we
10675185a700Sflorian * fix things up later. Note that this means that in some
10685185a700Sflorian * cases one more byte of text buffer is required than is
10695185a700Sflorian * needed in the final output.
10705185a700Sflorian */
10715185a700Sflorian if (trem == 0)
10725185a700Sflorian return (ISC_R_NOSPACE);
10735185a700Sflorian *tdata++ = '.';
10745185a700Sflorian trem--;
10755185a700Sflorian }
10765185a700Sflorian
10775185a700Sflorian if (nlen != 0 && trem == 0)
10785185a700Sflorian return (ISC_R_NOSPACE);
10795185a700Sflorian
10805185a700Sflorian if (!saw_root || omit_final_dot)
10815185a700Sflorian trem++;
10825185a700Sflorian
10835185a700Sflorian isc_buffer_add(target, tlen - trem);
10845185a700Sflorian
10855185a700Sflorian return (ISC_R_SUCCESS);
10865185a700Sflorian }
10875185a700Sflorian
10885185a700Sflorian isc_result_t
dns_name_downcase(dns_name_t * source,dns_name_t * name,isc_buffer_t * target)10895185a700Sflorian dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
10905185a700Sflorian unsigned char *sndata, *ndata;
10915185a700Sflorian unsigned int nlen, count, labels;
10925185a700Sflorian isc_buffer_t buffer;
10935185a700Sflorian
10945185a700Sflorian /*
10955185a700Sflorian * Downcase 'source'.
10965185a700Sflorian */
10975185a700Sflorian
10985185a700Sflorian if (source == name) {
10995185a700Sflorian REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
11005185a700Sflorian isc_buffer_init(&buffer, source->ndata, source->length);
11015185a700Sflorian target = &buffer;
11025185a700Sflorian ndata = source->ndata;
11035185a700Sflorian } else {
11045185a700Sflorian REQUIRE(BINDABLE(name));
11055185a700Sflorian if (target == NULL) {
11065185a700Sflorian target = name->buffer;
11075185a700Sflorian isc_buffer_clear(name->buffer);
11085185a700Sflorian }
11095185a700Sflorian ndata = (unsigned char *)target->base + target->used;
11105185a700Sflorian name->ndata = ndata;
11115185a700Sflorian }
11125185a700Sflorian
11135185a700Sflorian sndata = source->ndata;
11145185a700Sflorian nlen = source->length;
11155185a700Sflorian labels = source->labels;
11165185a700Sflorian
11175185a700Sflorian if (nlen > (target->length - target->used)) {
11185185a700Sflorian MAKE_EMPTY(name);
11195185a700Sflorian return (ISC_R_NOSPACE);
11205185a700Sflorian }
11215185a700Sflorian
11225185a700Sflorian while (labels > 0 && nlen > 0) {
11235185a700Sflorian labels--;
11245185a700Sflorian count = *sndata++;
11255185a700Sflorian *ndata++ = count;
11265185a700Sflorian nlen--;
11275185a700Sflorian if (count < 64) {
11285185a700Sflorian INSIST(nlen >= count);
11295185a700Sflorian while (count > 0) {
11305185a700Sflorian *ndata++ = maptolower[(*sndata++)];
11315185a700Sflorian nlen--;
11325185a700Sflorian count--;
11335185a700Sflorian }
11345185a700Sflorian } else {
11355185a700Sflorian FATAL_ERROR(__FILE__, __LINE__,
11365185a700Sflorian "Unexpected label type %02x", count);
11375185a700Sflorian /* Does not return. */
11385185a700Sflorian }
11395185a700Sflorian }
11405185a700Sflorian
11415185a700Sflorian if (source != name) {
11425185a700Sflorian name->labels = source->labels;
11435185a700Sflorian name->length = source->length;
11445185a700Sflorian if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
11455185a700Sflorian name->attributes = DNS_NAMEATTR_ABSOLUTE;
11465185a700Sflorian else
11475185a700Sflorian name->attributes = 0;
11485185a700Sflorian if (name->labels > 0 && name->offsets != NULL)
11495185a700Sflorian set_offsets(name, name->offsets, NULL);
11505185a700Sflorian }
11515185a700Sflorian
11525185a700Sflorian isc_buffer_add(target, name->length);
11535185a700Sflorian
11545185a700Sflorian return (ISC_R_SUCCESS);
11555185a700Sflorian }
11565185a700Sflorian
11575185a700Sflorian static void
set_offsets(const dns_name_t * name,unsigned char * offsets,dns_name_t * set_name)11585185a700Sflorian set_offsets(const dns_name_t *name, unsigned char *offsets,
11595185a700Sflorian dns_name_t *set_name)
11605185a700Sflorian {
11615185a700Sflorian unsigned int offset, count, length, nlabels;
11625185a700Sflorian unsigned char *ndata;
1163*1fb015a8Sflorian int absolute;
11645185a700Sflorian
11655185a700Sflorian ndata = name->ndata;
11665185a700Sflorian length = name->length;
11675185a700Sflorian offset = 0;
11685185a700Sflorian nlabels = 0;
1169*1fb015a8Sflorian absolute = 0;
11705185a700Sflorian while (offset != length) {
11715185a700Sflorian INSIST(nlabels < 128);
11725185a700Sflorian offsets[nlabels++] = offset;
11735185a700Sflorian count = *ndata++;
11745185a700Sflorian offset++;
11755185a700Sflorian INSIST(count <= 63);
11765185a700Sflorian offset += count;
11775185a700Sflorian ndata += count;
11785185a700Sflorian INSIST(offset <= length);
11795185a700Sflorian if (count == 0) {
1180*1fb015a8Sflorian absolute = 1;
11815185a700Sflorian break;
11825185a700Sflorian }
11835185a700Sflorian }
11845185a700Sflorian if (set_name != NULL) {
11855185a700Sflorian INSIST(set_name == name);
11865185a700Sflorian
11875185a700Sflorian set_name->labels = nlabels;
11885185a700Sflorian set_name->length = offset;
11895185a700Sflorian if (absolute)
11905185a700Sflorian set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
11915185a700Sflorian else
11925185a700Sflorian set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
11935185a700Sflorian }
11945185a700Sflorian INSIST(nlabels == name->labels);
11955185a700Sflorian INSIST(offset == name->length);
11965185a700Sflorian }
11975185a700Sflorian
11985185a700Sflorian 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)11995185a700Sflorian dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
12005185a700Sflorian dns_decompress_t *dctx, unsigned int options,
12015185a700Sflorian isc_buffer_t *target)
12025185a700Sflorian {
12035185a700Sflorian unsigned char *cdata, *ndata;
12045185a700Sflorian unsigned int cused; /* Bytes of compressed name data used */
12055185a700Sflorian unsigned int nused, labels, n, nmax;
12065185a700Sflorian unsigned int current, new_current, biggest_pointer;
1207*1fb015a8Sflorian int done;
12085185a700Sflorian fw_state state = fw_start;
12095185a700Sflorian unsigned int c;
12105185a700Sflorian unsigned char *offsets;
12115185a700Sflorian dns_offsets_t odata;
1212*1fb015a8Sflorian int downcase;
1213*1fb015a8Sflorian int seen_pointer;
12145185a700Sflorian
12155185a700Sflorian /*
12165185a700Sflorian * Copy the possibly-compressed name at source into target,
12175185a700Sflorian * decompressing it. Loop prevention is performed by checking
12185185a700Sflorian * the new pointer against biggest_pointer.
12195185a700Sflorian */
12205185a700Sflorian
1221*1fb015a8Sflorian downcase = (options & DNS_NAME_DOWNCASE) != 0;
12225185a700Sflorian
12235185a700Sflorian if (target == NULL && name->buffer != NULL) {
12245185a700Sflorian target = name->buffer;
12255185a700Sflorian isc_buffer_clear(target);
12265185a700Sflorian }
12275185a700Sflorian
12285185a700Sflorian REQUIRE(dctx != NULL);
12295185a700Sflorian REQUIRE(BINDABLE(name));
12305185a700Sflorian
12315185a700Sflorian INIT_OFFSETS(name, offsets, odata);
12325185a700Sflorian
12335185a700Sflorian /*
12345185a700Sflorian * Make 'name' empty in case of failure.
12355185a700Sflorian */
12365185a700Sflorian MAKE_EMPTY(name);
12375185a700Sflorian
12385185a700Sflorian /*
12395185a700Sflorian * Initialize things to make the compiler happy; they're not required.
12405185a700Sflorian */
12415185a700Sflorian n = 0;
12425185a700Sflorian new_current = 0;
12435185a700Sflorian
12445185a700Sflorian /*
12455185a700Sflorian * Set up.
12465185a700Sflorian */
12475185a700Sflorian labels = 0;
1248*1fb015a8Sflorian done = 0;
12495185a700Sflorian
12505185a700Sflorian ndata = isc_buffer_used(target);
12515185a700Sflorian nused = 0;
1252*1fb015a8Sflorian seen_pointer = 0;
12535185a700Sflorian
12545185a700Sflorian /*
12555185a700Sflorian * Find the maximum number of uncompressed target name
12565185a700Sflorian * bytes we are willing to generate. This is the smaller
12575185a700Sflorian * of the available target buffer length and the
12585185a700Sflorian * maximum legal domain name length (255).
12595185a700Sflorian */
12605185a700Sflorian nmax = isc_buffer_availablelength(target);
12615185a700Sflorian if (nmax > DNS_NAME_MAXWIRE)
12625185a700Sflorian nmax = DNS_NAME_MAXWIRE;
12635185a700Sflorian
12645185a700Sflorian cdata = isc_buffer_current(source);
12655185a700Sflorian cused = 0;
12665185a700Sflorian
12675185a700Sflorian current = source->current;
12685185a700Sflorian biggest_pointer = current;
12695185a700Sflorian
12705185a700Sflorian /*
12715185a700Sflorian * Note: The following code is not optimized for speed, but
12725185a700Sflorian * rather for correctness. Speed will be addressed in the future.
12735185a700Sflorian */
12745185a700Sflorian
12755185a700Sflorian while (current < source->active && !done) {
12765185a700Sflorian c = *cdata++;
12775185a700Sflorian current++;
12785185a700Sflorian if (!seen_pointer)
12795185a700Sflorian cused++;
12805185a700Sflorian
12815185a700Sflorian switch (state) {
12825185a700Sflorian case fw_start:
12835185a700Sflorian if (c < 64) {
12845185a700Sflorian offsets[labels] = nused;
12855185a700Sflorian labels++;
12865185a700Sflorian if (nused + c + 1 > nmax)
12875185a700Sflorian goto full;
12885185a700Sflorian nused += c + 1;
12895185a700Sflorian *ndata++ = c;
12905185a700Sflorian if (c == 0)
1291*1fb015a8Sflorian done = 1;
12925185a700Sflorian n = c;
12935185a700Sflorian state = fw_ordinary;
12945185a700Sflorian } else if (c >= 128 && c < 192) {
12955185a700Sflorian /*
12965185a700Sflorian * 14 bit local compression pointer.
12975185a700Sflorian * Local compression is no longer an
12985185a700Sflorian * IETF draft.
12995185a700Sflorian */
13005185a700Sflorian return (DNS_R_BADLABELTYPE);
13015185a700Sflorian } else if (c >= 192) {
13025185a700Sflorian /*
13035185a700Sflorian * Ordinary 14-bit pointer.
13045185a700Sflorian */
13055185a700Sflorian if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
13065185a700Sflorian 0)
13075185a700Sflorian return (DNS_R_DISALLOWED);
13085185a700Sflorian new_current = c & 0x3F;
13095185a700Sflorian state = fw_newcurrent;
13105185a700Sflorian } else
13115185a700Sflorian return (DNS_R_BADLABELTYPE);
13125185a700Sflorian break;
13135185a700Sflorian case fw_ordinary:
13145185a700Sflorian if (downcase)
13155185a700Sflorian c = maptolower[c];
13165185a700Sflorian *ndata++ = c;
13175185a700Sflorian n--;
13185185a700Sflorian if (n == 0)
13195185a700Sflorian state = fw_start;
13205185a700Sflorian break;
13215185a700Sflorian case fw_newcurrent:
13225185a700Sflorian new_current *= 256;
13235185a700Sflorian new_current += c;
13245185a700Sflorian if (new_current >= biggest_pointer)
13255185a700Sflorian return (DNS_R_BADPOINTER);
13265185a700Sflorian biggest_pointer = new_current;
13275185a700Sflorian current = new_current;
13285185a700Sflorian cdata = (unsigned char *)source->base + current;
1329*1fb015a8Sflorian seen_pointer = 1;
13305185a700Sflorian state = fw_start;
13315185a700Sflorian break;
13325185a700Sflorian default:
13335185a700Sflorian FATAL_ERROR(__FILE__, __LINE__,
13345185a700Sflorian "Unknown state %d", state);
13355185a700Sflorian /* Does not return. */
13365185a700Sflorian }
13375185a700Sflorian }
13385185a700Sflorian
13395185a700Sflorian if (!done)
13405185a700Sflorian return (ISC_R_UNEXPECTEDEND);
13415185a700Sflorian
13425185a700Sflorian name->ndata = (unsigned char *)target->base + target->used;
13435185a700Sflorian name->labels = labels;
13445185a700Sflorian name->length = nused;
13455185a700Sflorian name->attributes |= DNS_NAMEATTR_ABSOLUTE;
13465185a700Sflorian
13475185a700Sflorian isc_buffer_forward(source, cused);
13485185a700Sflorian isc_buffer_add(target, name->length);
13495185a700Sflorian
13505185a700Sflorian return (ISC_R_SUCCESS);
13515185a700Sflorian
13525185a700Sflorian full:
13535185a700Sflorian if (nmax == DNS_NAME_MAXWIRE)
13545185a700Sflorian /*
13555185a700Sflorian * The name did not fit even though we had a buffer
13565185a700Sflorian * big enough to fit a maximum-length name.
13575185a700Sflorian */
13585185a700Sflorian return (DNS_R_NAMETOOLONG);
13595185a700Sflorian else
13605185a700Sflorian /*
13615185a700Sflorian * The name might fit if only the caller could give us a
13625185a700Sflorian * big enough buffer.
13635185a700Sflorian */
13645185a700Sflorian return (ISC_R_NOSPACE);
13655185a700Sflorian }
13665185a700Sflorian
13675185a700Sflorian isc_result_t
dns_name_towire(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target)13685185a700Sflorian dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
13695185a700Sflorian isc_buffer_t *target)
13705185a700Sflorian {
13715185a700Sflorian unsigned int methods;
13725185a700Sflorian uint16_t offset;
13735185a700Sflorian dns_name_t gp; /* Global compression prefix */
1374*1fb015a8Sflorian int gf; /* Global compression target found */
13755185a700Sflorian uint16_t go; /* Global compression offset */
13765185a700Sflorian dns_offsets_t clo;
13775185a700Sflorian dns_name_t clname;
13785185a700Sflorian
13795185a700Sflorian /*
13805185a700Sflorian * Convert 'name' into wire format, compressing it as specified by the
13815185a700Sflorian * compression context 'cctx', and storing the result in 'target'.
13825185a700Sflorian */
13835185a700Sflorian
13845185a700Sflorian REQUIRE(cctx != NULL);
13855185a700Sflorian
13865185a700Sflorian /*
13875185a700Sflorian * If 'name' doesn't have an offsets table, make a clone which
13885185a700Sflorian * has one.
13895185a700Sflorian */
13905185a700Sflorian if (name->offsets == NULL) {
1391f1dacf25Sflorian dns_name_init(&clname, clo);
13925185a700Sflorian dns_name_clone(name, &clname);
13935185a700Sflorian name = &clname;
13945185a700Sflorian }
1395f1dacf25Sflorian dns_name_init(&gp, NULL);
13965185a700Sflorian
13975185a700Sflorian offset = target->used; /*XXX*/
13985185a700Sflorian
13995185a700Sflorian methods = dns_compress_getmethods(cctx);
14005185a700Sflorian
14015185a700Sflorian if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
14025185a700Sflorian (methods & DNS_COMPRESS_GLOBAL14) != 0)
14035185a700Sflorian gf = dns_compress_findglobal(cctx, name, &gp, &go);
14045185a700Sflorian else
1405*1fb015a8Sflorian gf = 0;
14065185a700Sflorian
14075185a700Sflorian /*
14085185a700Sflorian * If the offset is too high for 14 bit global compression, we're
14095185a700Sflorian * out of luck.
14105185a700Sflorian */
14115185a700Sflorian if (gf && go >= 0x4000)
1412*1fb015a8Sflorian gf = 0;
14135185a700Sflorian
14145185a700Sflorian /*
14155185a700Sflorian * Will the compression pointer reduce the message size?
14165185a700Sflorian */
14175185a700Sflorian if (gf && (gp.length + 2) >= name->length)
1418*1fb015a8Sflorian gf = 0;
14195185a700Sflorian
14205185a700Sflorian if (gf) {
14215185a700Sflorian if (target->length - target->used < gp.length)
14225185a700Sflorian return (ISC_R_NOSPACE);
14235185a700Sflorian if (gp.length != 0) {
14245185a700Sflorian unsigned char *base = target->base;
14255185a700Sflorian (void)memmove(base + target->used, gp.ndata,
14265185a700Sflorian (size_t)gp.length);
14275185a700Sflorian }
14285185a700Sflorian isc_buffer_add(target, gp.length);
14295185a700Sflorian go |= 0xc000;
14305185a700Sflorian if (target->length - target->used < 2)
14315185a700Sflorian return (ISC_R_NOSPACE);
14325185a700Sflorian isc_buffer_putuint16(target, go);
14335185a700Sflorian if (gp.length != 0)
14345185a700Sflorian dns_compress_add(cctx, name, &gp, offset);
14355185a700Sflorian } else {
14365185a700Sflorian if (target->length - target->used < name->length)
14375185a700Sflorian return (ISC_R_NOSPACE);
14385185a700Sflorian if (name->length != 0) {
14395185a700Sflorian unsigned char *base = target->base;
14405185a700Sflorian (void)memmove(base + target->used, name->ndata,
14415185a700Sflorian (size_t)name->length);
14425185a700Sflorian }
14435185a700Sflorian isc_buffer_add(target, name->length);
14445185a700Sflorian dns_compress_add(cctx, name, name, offset);
14455185a700Sflorian }
14465185a700Sflorian return (ISC_R_SUCCESS);
14475185a700Sflorian }
14485185a700Sflorian
14495185a700Sflorian isc_result_t
dns_name_concatenate(dns_name_t * prefix,dns_name_t * suffix,dns_name_t * name,isc_buffer_t * target)14505185a700Sflorian dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
14515185a700Sflorian isc_buffer_t *target)
14525185a700Sflorian {
14535185a700Sflorian unsigned char *ndata, *offsets;
14545185a700Sflorian unsigned int nrem, labels, prefix_length, length;
1455*1fb015a8Sflorian int copy_prefix = 1;
1456*1fb015a8Sflorian int copy_suffix = 1;
1457*1fb015a8Sflorian int absolute = 0;
14585185a700Sflorian dns_name_t tmp_name;
14595185a700Sflorian dns_offsets_t odata;
14605185a700Sflorian
14615185a700Sflorian /*
14625185a700Sflorian * Concatenate 'prefix' and 'suffix'.
14635185a700Sflorian */
14645185a700Sflorian
14655185a700Sflorian if (prefix == NULL || prefix->labels == 0)
1466*1fb015a8Sflorian copy_prefix = 0;
14675185a700Sflorian if (suffix == NULL || suffix->labels == 0)
1468*1fb015a8Sflorian copy_suffix = 0;
14695185a700Sflorian if (copy_prefix &&
14705185a700Sflorian (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1471*1fb015a8Sflorian absolute = 1;
14725185a700Sflorian REQUIRE(!copy_suffix);
14735185a700Sflorian }
14745185a700Sflorian if (name == NULL) {
1475f1dacf25Sflorian dns_name_init(&tmp_name, odata);
14765185a700Sflorian name = &tmp_name;
14775185a700Sflorian }
14785185a700Sflorian if (target == NULL) {
14795185a700Sflorian INSIST(name->buffer != NULL);
14805185a700Sflorian target = name->buffer;
14815185a700Sflorian isc_buffer_clear(name->buffer);
14825185a700Sflorian }
14835185a700Sflorian
14845185a700Sflorian REQUIRE(BINDABLE(name));
14855185a700Sflorian
14865185a700Sflorian /*
14875185a700Sflorian * Set up.
14885185a700Sflorian */
14895185a700Sflorian nrem = target->length - target->used;
14905185a700Sflorian ndata = (unsigned char *)target->base + target->used;
14915185a700Sflorian if (nrem > DNS_NAME_MAXWIRE)
14925185a700Sflorian nrem = DNS_NAME_MAXWIRE;
14935185a700Sflorian length = 0;
14945185a700Sflorian prefix_length = 0;
14955185a700Sflorian labels = 0;
14965185a700Sflorian if (copy_prefix) {
14975185a700Sflorian prefix_length = prefix->length;
14985185a700Sflorian length += prefix_length;
14995185a700Sflorian labels += prefix->labels;
15005185a700Sflorian }
15015185a700Sflorian if (copy_suffix) {
15025185a700Sflorian length += suffix->length;
15035185a700Sflorian labels += suffix->labels;
15045185a700Sflorian }
15055185a700Sflorian if (length > DNS_NAME_MAXWIRE) {
15065185a700Sflorian MAKE_EMPTY(name);
15075185a700Sflorian return (DNS_R_NAMETOOLONG);
15085185a700Sflorian }
15095185a700Sflorian if (length > nrem) {
15105185a700Sflorian MAKE_EMPTY(name);
15115185a700Sflorian return (ISC_R_NOSPACE);
15125185a700Sflorian }
15135185a700Sflorian
15145185a700Sflorian if (copy_suffix) {
15155185a700Sflorian if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1516*1fb015a8Sflorian absolute = 1;
15175185a700Sflorian memmove(ndata + prefix_length, suffix->ndata, suffix->length);
15185185a700Sflorian }
15195185a700Sflorian
15205185a700Sflorian /*
15215185a700Sflorian * If 'prefix' and 'name' are the same object, and the object has
15225185a700Sflorian * a dedicated buffer, and we're using it, then we don't have to
15235185a700Sflorian * copy anything.
15245185a700Sflorian */
15255185a700Sflorian if (copy_prefix && (prefix != name || prefix->buffer != target))
15265185a700Sflorian memmove(ndata, prefix->ndata, prefix_length);
15275185a700Sflorian
15285185a700Sflorian name->ndata = ndata;
15295185a700Sflorian name->labels = labels;
15305185a700Sflorian name->length = length;
15315185a700Sflorian if (absolute)
15325185a700Sflorian name->attributes = DNS_NAMEATTR_ABSOLUTE;
15335185a700Sflorian else
15345185a700Sflorian name->attributes = 0;
15355185a700Sflorian
15365185a700Sflorian if (name->labels > 0 && name->offsets != NULL) {
15375185a700Sflorian INIT_OFFSETS(name, offsets, odata);
15385185a700Sflorian set_offsets(name, offsets, NULL);
15395185a700Sflorian }
15405185a700Sflorian
15415185a700Sflorian isc_buffer_add(target, name->length);
15425185a700Sflorian
15435185a700Sflorian return (ISC_R_SUCCESS);
15445185a700Sflorian }
15455185a700Sflorian
15465185a700Sflorian isc_result_t
dns_name_dup(const dns_name_t * source,dns_name_t * target)15475185a700Sflorian dns_name_dup(const dns_name_t *source,
15485185a700Sflorian dns_name_t *target)
15495185a700Sflorian {
15505185a700Sflorian /*
15515185a700Sflorian * Make 'target' a dynamically allocated copy of 'source'.
15525185a700Sflorian */
15535185a700Sflorian
15545185a700Sflorian REQUIRE(source->length > 0);
15555185a700Sflorian REQUIRE(BINDABLE(target));
15565185a700Sflorian
15575185a700Sflorian /*
15585185a700Sflorian * Make 'target' empty in case of failure.
15595185a700Sflorian */
15605185a700Sflorian MAKE_EMPTY(target);
15615185a700Sflorian
15625185a700Sflorian target->ndata = malloc(source->length);
15635185a700Sflorian if (target->ndata == NULL)
15645185a700Sflorian return (ISC_R_NOMEMORY);
15655185a700Sflorian
15665185a700Sflorian memmove(target->ndata, source->ndata, source->length);
15675185a700Sflorian
15685185a700Sflorian target->length = source->length;
15695185a700Sflorian target->labels = source->labels;
15705185a700Sflorian target->attributes = DNS_NAMEATTR_DYNAMIC;
15715185a700Sflorian if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
15725185a700Sflorian target->attributes |= DNS_NAMEATTR_ABSOLUTE;
15735185a700Sflorian if (target->offsets != NULL) {
15745185a700Sflorian if (source->offsets != NULL)
15755185a700Sflorian memmove(target->offsets, source->offsets,
15765185a700Sflorian source->labels);
15775185a700Sflorian else
15785185a700Sflorian set_offsets(target, target->offsets, NULL);
15795185a700Sflorian }
15805185a700Sflorian
15815185a700Sflorian return (ISC_R_SUCCESS);
15825185a700Sflorian }
15835185a700Sflorian
15845185a700Sflorian isc_result_t
dns_name_dupwithoffsets(dns_name_t * source,dns_name_t * target)15855185a700Sflorian dns_name_dupwithoffsets(dns_name_t *source,
15865185a700Sflorian dns_name_t *target)
15875185a700Sflorian {
15885185a700Sflorian /*
15895185a700Sflorian * Make 'target' a read-only dynamically allocated copy of 'source'.
15905185a700Sflorian * 'target' will also have a dynamically allocated offsets table.
15915185a700Sflorian */
15925185a700Sflorian
15935185a700Sflorian REQUIRE(source->length > 0);
15945185a700Sflorian REQUIRE(BINDABLE(target));
15955185a700Sflorian REQUIRE(target->offsets == NULL);
15965185a700Sflorian
15975185a700Sflorian /*
15985185a700Sflorian * Make 'target' empty in case of failure.
15995185a700Sflorian */
16005185a700Sflorian MAKE_EMPTY(target);
16015185a700Sflorian
16025185a700Sflorian target->ndata = malloc(source->length + source->labels);
16035185a700Sflorian if (target->ndata == NULL)
16045185a700Sflorian return (ISC_R_NOMEMORY);
16055185a700Sflorian
16065185a700Sflorian memmove(target->ndata, source->ndata, source->length);
16075185a700Sflorian
16085185a700Sflorian target->length = source->length;
16095185a700Sflorian target->labels = source->labels;
16105185a700Sflorian target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
16115185a700Sflorian DNS_NAMEATTR_READONLY;
16125185a700Sflorian if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
16135185a700Sflorian target->attributes |= DNS_NAMEATTR_ABSOLUTE;
16145185a700Sflorian target->offsets = target->ndata + source->length;
16155185a700Sflorian if (source->offsets != NULL)
16165185a700Sflorian memmove(target->offsets, source->offsets, source->labels);
16175185a700Sflorian else
16185185a700Sflorian set_offsets(target, target->offsets, NULL);
16195185a700Sflorian
16205185a700Sflorian return (ISC_R_SUCCESS);
16215185a700Sflorian }
16225185a700Sflorian
16235185a700Sflorian void
dns_name_free(dns_name_t * name)16245185a700Sflorian dns_name_free(dns_name_t *name) {
16255185a700Sflorian /*
16265185a700Sflorian * Free 'name'.
16275185a700Sflorian */
16285185a700Sflorian
16295185a700Sflorian REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
16305185a700Sflorian
16315185a700Sflorian free(name->ndata);
16325185a700Sflorian dns_name_invalidate(name);
16335185a700Sflorian }
16345185a700Sflorian
1635*1fb015a8Sflorian int
dns_name_dynamic(dns_name_t * name)16365185a700Sflorian dns_name_dynamic(dns_name_t *name) {
16375185a700Sflorian
16385185a700Sflorian /*
16395185a700Sflorian * Returns whether there is dynamic memory associated with this name.
16405185a700Sflorian */
16415185a700Sflorian
16425185a700Sflorian return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
1643*1fb015a8Sflorian 1 : 0);
16445185a700Sflorian }
16455185a700Sflorian
16465185a700Sflorian void
dns_name_format(dns_name_t * name,char * cp,unsigned int size)16475185a700Sflorian dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
16485185a700Sflorian isc_result_t result;
16495185a700Sflorian isc_buffer_t buf;
16505185a700Sflorian
16515185a700Sflorian REQUIRE(size > 0);
16525185a700Sflorian
16535185a700Sflorian /*
16545185a700Sflorian * Leave room for null termination after buffer.
16555185a700Sflorian */
16565185a700Sflorian isc_buffer_init(&buf, cp, size - 1);
1657*1fb015a8Sflorian result = dns_name_totext(name, 1, &buf);
16585185a700Sflorian if (result == ISC_R_SUCCESS) {
16595185a700Sflorian /*
16605185a700Sflorian * Null terminate.
16615185a700Sflorian */
16625185a700Sflorian isc_region_t r;
16635185a700Sflorian isc_buffer_usedregion(&buf, &r);
16645185a700Sflorian ((char *) r.base)[r.length] = '\0';
16655185a700Sflorian
16665185a700Sflorian } else
16675185a700Sflorian snprintf(cp, size, "<unknown>");
16685185a700Sflorian }
16695185a700Sflorian
16705185a700Sflorian /*
16715185a700Sflorian * dns_name_fromstring() -- convert directly from a string to a name,
16725185a700Sflorian * allocating memory as needed
16735185a700Sflorian */
16745185a700Sflorian isc_result_t
dns_name_fromstring2(dns_name_t * target,const char * src,const dns_name_t * origin,unsigned int options)16755185a700Sflorian dns_name_fromstring2(dns_name_t *target, const char *src,
16765185a700Sflorian const dns_name_t *origin, unsigned int options)
16775185a700Sflorian {
16785185a700Sflorian isc_result_t result;
16795185a700Sflorian isc_buffer_t buf;
16805185a700Sflorian dns_fixedname_t fn;
16815185a700Sflorian dns_name_t *name;
16825185a700Sflorian
16835185a700Sflorian REQUIRE(src != NULL);
16845185a700Sflorian
168538a45998Sflorian isc_buffer_init(&buf, (void *)src, strlen(src));
16865185a700Sflorian isc_buffer_add(&buf, strlen(src));
16875185a700Sflorian if (BINDABLE(target) && target->buffer != NULL)
16885185a700Sflorian name = target;
16895185a700Sflorian else {
16905185a700Sflorian dns_fixedname_init(&fn);
16915185a700Sflorian name = dns_fixedname_name(&fn);
16925185a700Sflorian }
16935185a700Sflorian
16945185a700Sflorian result = dns_name_fromtext(name, &buf, origin, options, NULL);
16955185a700Sflorian if (result != ISC_R_SUCCESS)
16965185a700Sflorian return (result);
16975185a700Sflorian
16985185a700Sflorian if (name != target)
16995185a700Sflorian result = dns_name_dupwithoffsets(name, target);
17005185a700Sflorian return (result);
17015185a700Sflorian }
17025185a700Sflorian
17035185a700Sflorian isc_result_t
dns_name_copy(dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)17045185a700Sflorian dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
17055185a700Sflorian unsigned char *ndata;
17065185a700Sflorian
17075185a700Sflorian /*
17085185a700Sflorian * Make dest a copy of source.
17095185a700Sflorian */
17105185a700Sflorian
17115185a700Sflorian REQUIRE(target != NULL || dest->buffer != NULL);
17125185a700Sflorian
17135185a700Sflorian if (target == NULL) {
17145185a700Sflorian target = dest->buffer;
17155185a700Sflorian isc_buffer_clear(dest->buffer);
17165185a700Sflorian }
17175185a700Sflorian
17185185a700Sflorian REQUIRE(BINDABLE(dest));
17195185a700Sflorian
17205185a700Sflorian /*
17215185a700Sflorian * Set up.
17225185a700Sflorian */
17235185a700Sflorian if (target->length - target->used < source->length)
17245185a700Sflorian return (ISC_R_NOSPACE);
17255185a700Sflorian
17265185a700Sflorian ndata = (unsigned char *)target->base + target->used;
17275185a700Sflorian dest->ndata = target->base;
17285185a700Sflorian
17295185a700Sflorian if (source->length != 0)
17305185a700Sflorian memmove(ndata, source->ndata, source->length);
17315185a700Sflorian
17325185a700Sflorian dest->ndata = ndata;
17335185a700Sflorian dest->labels = source->labels;
17345185a700Sflorian dest->length = source->length;
17355185a700Sflorian if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
17365185a700Sflorian dest->attributes = DNS_NAMEATTR_ABSOLUTE;
17375185a700Sflorian else
17385185a700Sflorian dest->attributes = 0;
17395185a700Sflorian
17405185a700Sflorian if (dest->labels > 0 && dest->offsets != NULL) {
17415185a700Sflorian if (source->offsets != NULL)
17425185a700Sflorian memmove(dest->offsets, source->offsets, source->labels);
17435185a700Sflorian else
17445185a700Sflorian set_offsets(dest, dest->offsets, NULL);
17455185a700Sflorian }
17465185a700Sflorian
17475185a700Sflorian isc_buffer_add(target, dest->length);
17485185a700Sflorian
17495185a700Sflorian return (ISC_R_SUCCESS);
17505185a700Sflorian }
1751