name.c revision 2f4ffd7f5594c0464f2a872aee5ef102f6f7b10f
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/*
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC")
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * Copyright (C) 1998-2003 Internet Software Consortium.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer *
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * Permission to use, copy, modify, and distribute this software for any
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * purpose with or without fee is hereby granted, provided that the above
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * copyright notice and this permission notice appear in all copies.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer *
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * PERFORMANCE OF THIS SOFTWARE.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/* $Id: name.c,v 1.148 2005/01/10 23:43:22 marka Exp $ */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <config.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <ctype.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/buffer.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/hash.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/mem.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/print.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/string.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <isc/util.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <dns/compress.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <dns/name.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#include <dns/result.h>
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayertypedef enum {
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_init = 0,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_start,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_ordinary,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_initialescape,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_escape,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_escdecimal,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ft_at
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer} ft_state;
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayertypedef enum {
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer fw_start = 0,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer fw_ordinary,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer fw_copy,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer fw_newcurrent
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer} fw_state;
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic char digitvalue[256] = {
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer};
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic unsigned char maptolower[] = {
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer};
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define CONVERTTOASCII(c)
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define CONVERTFROMASCII(c)
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define INIT_OFFSETS(name, var, default) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer if (name->offsets != NULL) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer var = name->offsets; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer else \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer var = default;
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define SETUP_OFFSETS(name, var, default) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer if (name->offsets != NULL) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer var = name->offsets; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer else { \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer var = default; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer set_offsets(name, var, NULL); \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer }
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/*
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * Note: If additional attributes are added that should not be set for
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * empty names, MAKE_EMPTY() must be changed so it clears them.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define MAKE_EMPTY(name) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerdo { \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer name->ndata = NULL; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer name->length = 0; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer name->labels = 0; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer} while (0);
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/*
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * A name is "bindable" if it can be set to point to a new value, i.e.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * name->ndata and name->length may be changed.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer#define BINDABLE(name) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer ((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer == 0)
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/*
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * Note that the name data must be a char array, not a string
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * literal, to avoid compiler warnings about discarding
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer * the const attribute of a string.
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic unsigned char root_ndata[] = { '\0' };
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic unsigned char root_offsets[] = { 0 };
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic dns_name_t root =
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer{
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer DNS_NAME_MAGIC,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer root_ndata, 1, 1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer root_offsets, NULL,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer {(void *)-1, (void *)-1},
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer {NULL, NULL}
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer};
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/* XXXDCL make const? */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny MayerLIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root;
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic unsigned char wild_ndata[] = { '\001', '*' };
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic unsigned char wild_offsets[] = { 0 };
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic dns_name_t wild =
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer{
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer DNS_NAME_MAGIC,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer wild_ndata, 2, 1,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer DNS_NAMEATTR_READONLY,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer wild_offsets, NULL,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer {(void *)-1, (void *)-1},
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer {NULL, NULL}
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer};
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer/* XXXDCL make const? */
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny MayerLIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild;
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerunsigned int
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerdns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive);
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerstatic void
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayerset_offsets(const dns_name_t *name, unsigned char *offsets,
48b785fe6bcc95831f962b9b3a61c0b39e339558Danny Mayer dns_name_t *set_name);
void
dns_name_init(dns_name_t *name, unsigned char *offsets) {
/*
* Initialize 'name'.
*/
DNS_NAME_INIT(name, offsets);
}
void
dns_name_reset(dns_name_t *name) {
REQUIRE(VALID_NAME(name));
REQUIRE(BINDABLE(name));
DNS_NAME_RESET(name);
}
void
dns_name_invalidate(dns_name_t *name) {
/*
* Make 'name' invalid.
*/
REQUIRE(VALID_NAME(name));
name->magic = 0;
name->ndata = NULL;
name->length = 0;
name->labels = 0;
name->attributes = 0;
name->offsets = NULL;
name->buffer = NULL;
ISC_LINK_INIT(name, link);
}
void
dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
/*
* Dedicate a buffer for use with 'name'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE((buffer != NULL && name->buffer == NULL) ||
(buffer == NULL));
name->buffer = buffer;
}
isc_boolean_t
dns_name_hasbuffer(const dns_name_t *name) {
/*
* Does 'name' have a dedicated buffer?
*/
REQUIRE(VALID_NAME(name));
if (name->buffer != NULL)
return (ISC_TRUE);
return (ISC_FALSE);
}
isc_boolean_t
dns_name_isabsolute(const dns_name_t *name) {
/*
* Does 'name' end in the root label?
*/
REQUIRE(VALID_NAME(name));
if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
return (ISC_TRUE);
return (ISC_FALSE);
}
#define hyphenchar(c) ((c) == 0x2d)
#define asterchar(c) ((c) == 0x2a)
#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
|| ((c) >= 0x61 && (c) <= 0x7a))
#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
#define borderchar(c) (alphachar(c) || digitchar(c))
#define middlechar(c) (borderchar(c) || hyphenchar(c))
#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
isc_boolean_t
dns_name_ismailbox(const dns_name_t *name) {
unsigned char *ndata, ch;
unsigned int n;
isc_boolean_t first;
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
/*
* Root label.
*/
if (name->length == 1)
return (ISC_TRUE);
ndata = name->ndata;
n = *ndata++;
INSIST(n <= 63);
while (n--) {
ch = *ndata++;
if (!domainchar(ch))
return (ISC_FALSE);
}
if (ndata == name->ndata + name->length)
return (ISC_FALSE);
/*
* RFC292/RFC1123 hostname.
*/
while (ndata < (name->ndata + name->length)) {
n = *ndata++;
INSIST(n <= 63);
first = ISC_TRUE;
while (n--) {
ch = *ndata++;
if (first || n == 0) {
if (!borderchar(ch))
return (ISC_FALSE);
} else {
if (!middlechar(ch))
return (ISC_FALSE);
}
first = ISC_FALSE;
}
}
return (ISC_TRUE);
}
isc_boolean_t
dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) {
unsigned char *ndata, ch;
unsigned int n;
isc_boolean_t first;
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
/*
* Root label.
*/
if (name->length == 1)
return (ISC_TRUE);
/*
* Skip wildcard if this is a ownername.
*/
ndata = name->ndata;
if (wildcard && ndata[0] == 1 && ndata[1] == '*')
ndata += 2;
/*
* RFC292/RFC1123 hostname.
*/
while (ndata < (name->ndata + name->length)) {
n = *ndata++;
INSIST(n <= 63);
first = ISC_TRUE;
while (n--) {
ch = *ndata++;
if (first || n == 0) {
if (!borderchar(ch))
return (ISC_FALSE);
} else {
if (!middlechar(ch))
return (ISC_FALSE);
}
first = ISC_FALSE;
}
}
return (ISC_TRUE);
}
isc_boolean_t
dns_name_iswildcard(const dns_name_t *name) {
unsigned char *ndata;
/*
* Is 'name' a wildcard name?
*/
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
if (name->length >= 2) {
ndata = name->ndata;
if (ndata[0] == 1 && ndata[1] == '*')
return (ISC_TRUE);
}
return (ISC_FALSE);
}
isc_boolean_t
dns_name_internalwildcard(const dns_name_t *name) {
unsigned char *ndata;
unsigned int count;
unsigned int label;
/*
* Does 'name' contain a internal wildcard?
*/
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
/*
* Skip first label.
*/
ndata = name->ndata;
count = *ndata++;
INSIST(count <= 63);
ndata += count;
label = 1;
/*
* Check all but the last of the remaining labels.
*/
while (label + 1 < name->labels) {
count = *ndata++;
INSIST(count <= 63);
if (count == 1 && *ndata == '*')
return (ISC_TRUE);
ndata += count;
label++;
}
return (ISC_FALSE);
}
static inline unsigned int
name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
unsigned int length;
const unsigned char *s;
unsigned int h = 0;
unsigned char c;
length = name->length;
if (length > 16)
length = 16;
/*
* This hash function is similar to the one Ousterhout
* uses in Tcl.
*/
s = name->ndata;
if (case_sensitive) {
while (length > 0) {
h += ( h << 3 ) + *s;
s++;
length--;
}
} else {
while (length > 0) {
c = maptolower[*s];
h += ( h << 3 ) + c;
s++;
length--;
}
}
return (h);
}
unsigned int
dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
/*
* Provide a hash value for 'name'.
*/
REQUIRE(VALID_NAME(name));
if (name->labels == 0)
return (0);
return (name_hash(name, case_sensitive));
}
unsigned int
dns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) {
/*
* Provide a hash value for 'name'.
*/
REQUIRE(VALID_NAME(name));
if (name->labels == 0)
return (0);
return (isc_hash_calc((const unsigned char *)name->ndata,
name->length, case_sensitive));
}
unsigned int
dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
/*
* This function was deprecated due to the breakage of the name space
* convention. We only keep this internally to provide binary backward
* compatibility.
*/
REQUIRE(VALID_NAME(name));
return (dns_name_fullhash(name, case_sensitive));
}
unsigned int
dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) {
unsigned char *offsets;
dns_offsets_t odata;
dns_name_t tname;
unsigned int h = 0;
unsigned int i;
/*
* Provide a hash value for 'name'.
*/
REQUIRE(VALID_NAME(name));
if (name->labels == 0)
return (0);
else if (name->labels == 1)
return (name_hash(name, case_sensitive));
SETUP_OFFSETS(name, offsets, odata);
DNS_NAME_INIT(&tname, NULL);
tname.labels = 1;
h = 0;
for (i = 0; i < name->labels; i++) {
tname.ndata = name->ndata + offsets[i];
if (i == name->labels - 1)
tname.length = name->length - offsets[i];
else
tname.length = offsets[i + 1] - offsets[i];
h += name_hash(&tname, case_sensitive);
}
return (h);
}
dns_namereln_t
dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
int *orderp, unsigned int *nlabelsp)
{
unsigned int l1, l2, l, count1, count2, count, nlabels;
int cdiff, ldiff, chdiff;
unsigned char *label1, *label2;
unsigned char *offsets1, *offsets2;
dns_offsets_t odata1, odata2;
dns_namereln_t namereln = dns_namereln_none;
/*
* Determine the relative ordering under the DNSSEC order relation of
* 'name1' and 'name2', and also determine the hierarchical
* relationship of the names.
*
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* same domain.
*/
REQUIRE(VALID_NAME(name1));
REQUIRE(VALID_NAME(name2));
REQUIRE(orderp != NULL);
REQUIRE(nlabelsp != NULL);
/*
* Either name1 is absolute and name2 is absolute, or neither is.
*/
REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
SETUP_OFFSETS(name1, offsets1, odata1);
SETUP_OFFSETS(name2, offsets2, odata2);
nlabels = 0;
l1 = name1->labels;
l2 = name2->labels;
ldiff = (int)l1 - (int)l2;
if (ldiff < 0)
l = l1;
else
l = l2;
while (l > 0) {
l--;
l1--;
l2--;
label1 = &name1->ndata[offsets1[l1]];
label2 = &name2->ndata[offsets2[l2]];
count1 = *label1++;
count2 = *label2++;
/*
* We dropped bitstring labels, and we don't support any
* other extended label types.
*/
INSIST(count1 <= 63 && count2 <= 63);
cdiff = (int)count1 - (int)count2;
if (cdiff < 0)
count = count1;
else
count = count2;
while (count > 0) {
chdiff = (int)maptolower[*label1] -
(int)maptolower[*label2];
if (chdiff != 0) {
*orderp = chdiff;
goto done;
}
count--;
label1++;
label2++;
}
if (cdiff != 0) {
*orderp = cdiff;
goto done;
}
nlabels++;
}
*orderp = ldiff;
if (ldiff < 0)
namereln = dns_namereln_contains;
else if (ldiff > 0)
namereln = dns_namereln_subdomain;
else
namereln = dns_namereln_equal;
done:
*nlabelsp = nlabels;
if (nlabels > 0 && namereln == dns_namereln_none)
namereln = dns_namereln_commonancestor;
return (namereln);
}
int
dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
int order;
unsigned int nlabels;
/*
* Determine the relative ordering under the DNSSEC order relation of
* 'name1' and 'name2'.
*
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* same domain.
*/
(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
return (order);
}
isc_boolean_t
dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
unsigned int l, count;
unsigned char c;
unsigned char *label1, *label2;
/*
* Are 'name1' and 'name2' equal?
*
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* same domain.
*/
REQUIRE(VALID_NAME(name1));
REQUIRE(VALID_NAME(name2));
/*
* Either name1 is absolute and name2 is absolute, or neither is.
*/
REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
if (name1->length != name2->length)
return (ISC_FALSE);
l = name1->labels;
if (l != name2->labels)
return (ISC_FALSE);
label1 = name1->ndata;
label2 = name2->ndata;
while (l > 0) {
l--;
count = *label1++;
if (count != *label2++)
return (ISC_FALSE);
INSIST(count <= 63); /* no bitstring support */
while (count > 0) {
count--;
c = maptolower[*label1++];
if (c != maptolower[*label2++])
return (ISC_FALSE);
}
}
return (ISC_TRUE);
}
int
dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
unsigned int l1, l2, l, count1, count2, count;
unsigned char c1, c2;
unsigned char *label1, *label2;
/*
* Compare two absolute names as rdata.
*/
REQUIRE(VALID_NAME(name1));
REQUIRE(name1->labels > 0);
REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
REQUIRE(VALID_NAME(name2));
REQUIRE(name2->labels > 0);
REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
l1 = name1->labels;
l2 = name2->labels;
l = (l1 < l2) ? l1 : l2;
label1 = name1->ndata;
label2 = name2->ndata;
while (l > 0) {
l--;
count1 = *label1++;
count2 = *label2++;
/* no bitstring support */
INSIST(count1 <= 63 && count2 <= 63);
if (count1 != count2)
return ((count1 < count2) ? -1 : 1);
count = count1;
while (count > 0) {
count--;
c1 = maptolower[*label1++];
c2 = maptolower[*label2++];
if (c1 < c2)
return (-1);
else if (c1 > c2)
return (1);
}
}
/*
* If one name had more labels than the other, their common
* prefix must have been different because the shorter name
* ended with the root label and the longer one can't have
* a root label in the middle of it. Therefore, if we get
* to this point, the lengths must be equal.
*/
INSIST(l1 == l2);
return (0);
}
isc_boolean_t
dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
int order;
unsigned int nlabels;
dns_namereln_t namereln;
/*
* Is 'name1' a subdomain of 'name2'?
*
* Note: It makes no sense for one of the names to be relative and the
* other absolute. If both names are relative, then to be meaningfully
* compared the caller must ensure that they are both relative to the
* same domain.
*/
namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
if (namereln == dns_namereln_subdomain ||
namereln == dns_namereln_equal)
return (ISC_TRUE);
return (ISC_FALSE);
}
isc_boolean_t
dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
int order;
unsigned int nlabels, labels;
dns_name_t tname;
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
REQUIRE(VALID_NAME(wname));
labels = wname->labels;
REQUIRE(labels > 0);
REQUIRE(dns_name_iswildcard(wname));
DNS_NAME_INIT(&tname, NULL);
dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
dns_namereln_subdomain)
return (ISC_TRUE);
return (ISC_FALSE);
}
unsigned int
dns_name_countlabels(const dns_name_t *name) {
/*
* How many labels does 'name' have?
*/
REQUIRE(VALID_NAME(name));
ENSURE(name->labels <= 128);
return (name->labels);
}
void
dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
unsigned char *offsets;
dns_offsets_t odata;
/*
* Make 'label' refer to the 'n'th least significant label of 'name'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(name->labels > 0);
REQUIRE(n < name->labels);
REQUIRE(label != NULL);
SETUP_OFFSETS(name, offsets, odata);
label->base = &name->ndata[offsets[n]];
if (n == name->labels - 1)
label->length = name->length - offsets[n];
else
label->length = offsets[n + 1] - offsets[n];
}
void
dns_name_getlabelsequence(const dns_name_t *source,
unsigned int first, unsigned int n,
dns_name_t *target)
{
unsigned char *offsets;
dns_offsets_t odata;
unsigned int firstoffset, endoffset;
/*
* Make 'target' refer to the 'n' labels including and following
* 'first' in 'source'.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(VALID_NAME(target));
REQUIRE(first <= source->labels);
REQUIRE(first + n <= source->labels);
REQUIRE(BINDABLE(target));
SETUP_OFFSETS(source, offsets, odata);
if (first == source->labels)
firstoffset = source->length;
else
firstoffset = offsets[first];
if (first + n == source->labels)
endoffset = source->length;
else
endoffset = offsets[first + n];
target->ndata = &source->ndata[firstoffset];
target->length = endoffset - firstoffset;
if (first + n == source->labels && n > 0 &&
(source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
target->attributes |= DNS_NAMEATTR_ABSOLUTE;
else
target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
target->labels = n;
/*
* If source and target are the same, and we're making target
* a prefix of source, the offsets table is correct already
* so we don't need to call set_offsets().
*/
if (target->offsets != NULL &&
(target != source || first != 0))
set_offsets(target, target->offsets, NULL);
}
void
dns_name_clone(dns_name_t *source, dns_name_t *target) {
/*
* Make 'target' refer to the same name as 'source'.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(VALID_NAME(target));
REQUIRE(BINDABLE(target));
target->ndata = source->ndata;
target->length = source->length;
target->labels = source->labels;
target->attributes = source->attributes &
(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
DNS_NAMEATTR_DYNOFFSETS);
if (target->offsets != NULL && source->labels > 0) {
if (source->offsets != NULL)
memcpy(target->offsets, source->offsets,
source->labels);
else
set_offsets(target, target->offsets, NULL);
}
}
void
dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
unsigned char *offsets;
dns_offsets_t odata;
unsigned int len;
isc_region_t r2;
/*
* Make 'name' refer to region 'r'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(r != NULL);
REQUIRE(BINDABLE(name));
INIT_OFFSETS(name, offsets, odata);
if (name->buffer != NULL) {
isc_buffer_clear(name->buffer);
isc_buffer_availableregion(name->buffer, &r2);
len = (r->length < r2.length) ? r->length : r2.length;
if (len > DNS_NAME_MAXWIRE)
len = DNS_NAME_MAXWIRE;
memcpy(r2.base, r->base, len);
name->ndata = r2.base;
name->length = len;
} else {
name->ndata = r->base;
name->length = (r->length <= DNS_NAME_MAXWIRE) ?
r->length : DNS_NAME_MAXWIRE;
}
if (r->length > 0)
set_offsets(name, offsets, name);
else {
name->labels = 0;
name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
}
if (name->buffer != NULL)
isc_buffer_add(name->buffer, name->length);
}
void
dns_name_toregion(dns_name_t *name, isc_region_t *r) {
/*
* Make 'r' refer to 'name'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(r != NULL);
DNS_NAME_TOREGION(name, r);
}
isc_result_t
dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
dns_name_t *origin, unsigned int options,
isc_buffer_t *target)
{
unsigned char *ndata, *label;
char *tdata;
char c;
ft_state state, kind;
unsigned int value, count, tbcount, bitlength, maxlength;
unsigned int n1, n2, vlen, tlen, nrem, nused, digits, labels, tused;
isc_boolean_t done;
unsigned char *offsets;
dns_offsets_t odata;
isc_boolean_t downcase;
/*
* Convert the textual representation of a DNS name at source
* into uncompressed wire form stored in target.
*
* Notes:
* Relative domain names will have 'origin' appended to them
* unless 'origin' is NULL, in which case relative domain names
* will remain relative.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(ISC_BUFFER_VALID(source));
REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
(target == NULL && ISC_BUFFER_VALID(name->buffer)));
downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
if (target == NULL && name->buffer != NULL) {
target = name->buffer;
isc_buffer_clear(target);
}
REQUIRE(BINDABLE(name));
INIT_OFFSETS(name, offsets, odata);
offsets[0] = 0;
/*
* Initialize things to make the compiler happy; they're not required.
*/
n1 = 0;
n2 = 0;
vlen = 0;
label = NULL;
digits = 0;
value = 0;
count = 0;
tbcount = 0;
bitlength = 0;
maxlength = 0;
kind = ft_init;
/*
* Make 'name' empty in case of failure.
*/
MAKE_EMPTY(name);
/*
* Set up the state machine.
*/
tdata = (char *)source->base + source->current;
tlen = isc_buffer_remaininglength(source);
tused = 0;
ndata = isc_buffer_used(target);
nrem = isc_buffer_availablelength(target);
if (nrem > 255)
nrem = 255;
nused = 0;
labels = 0;
done = ISC_FALSE;
state = ft_init;
while (nrem > 0 && tlen > 0 && !done) {
c = *tdata++;
tlen--;
tused++;
switch (state) {
case ft_init:
/*
* Is this the root name?
*/
if (c == '.') {
if (tlen != 0)
return (DNS_R_EMPTYLABEL);
labels++;
*ndata++ = 0;
nrem--;
nused++;
done = ISC_TRUE;
break;
}
if (c == '@' && tlen == 0) {
state = ft_at;
break;
}
/* FALLTHROUGH */
case ft_start:
label = ndata;
ndata++;
nrem--;
nused++;
count = 0;
if (c == '\\') {
state = ft_initialescape;
break;
}
kind = ft_ordinary;
state = ft_ordinary;
if (nrem == 0)
return (ISC_R_NOSPACE);
/* FALLTHROUGH */
case ft_ordinary:
if (c == '.') {
if (count == 0)
return (DNS_R_EMPTYLABEL);
*label = count;
labels++;
INSIST(labels <= 127);
offsets[labels] = nused;
if (tlen == 0) {
labels++;
*ndata++ = 0;
nrem--;
nused++;
done = ISC_TRUE;
}
state = ft_start;
} else if (c == '\\') {
state = ft_escape;
} else {
if (count >= 63)
return (DNS_R_LABELTOOLONG);
count++;
CONVERTTOASCII(c);
if (downcase)
c = maptolower[(int)c];
*ndata++ = c;
nrem--;
nused++;
}
break;
case ft_initialescape:
if (c == '[') {
/*
* This looks like a bitstring label, which
* was deprecated. Intentionally drop it.
*/
return (DNS_R_BADLABELTYPE);
}
kind = ft_ordinary;
state = ft_escape;
/* FALLTHROUGH */
case ft_escape:
if (!isdigit(c & 0xff)) {
if (count >= 63)
return (DNS_R_LABELTOOLONG);
count++;
CONVERTTOASCII(c);
if (downcase)
c = maptolower[(int)c];
*ndata++ = c;
nrem--;
nused++;
state = ft_ordinary;
break;
}
digits = 0;
value = 0;
state = ft_escdecimal;
/* FALLTHROUGH */
case ft_escdecimal:
if (!isdigit(c & 0xff))
return (DNS_R_BADESCAPE);
value *= 10;
value += digitvalue[(int)c];
digits++;
if (digits == 3) {
if (value > 255)
return (DNS_R_BADESCAPE);
if (count >= 63)
return (DNS_R_LABELTOOLONG);
count++;
if (downcase)
value = maptolower[value];
*ndata++ = value;
nrem--;
nused++;
state = ft_ordinary;
}
break;
default:
FATAL_ERROR(__FILE__, __LINE__,
"Unexpected state %d", state);
/* Does not return. */
}
}
if (!done) {
if (nrem == 0)
return (ISC_R_NOSPACE);
INSIST(tlen == 0);
if (state != ft_ordinary && state != ft_at)
return (ISC_R_UNEXPECTEDEND);
if (state == ft_ordinary) {
INSIST(count != 0);
*label = count;
labels++;
INSIST(labels <= 127);
offsets[labels] = nused;
}
if (origin != NULL) {
if (nrem < origin->length)
return (ISC_R_NOSPACE);
label = origin->ndata;
n1 = origin->length;
nrem -= n1;
while (n1 > 0) {
n2 = *label++;
INSIST(n2 <= 63); /* no bitstring support */
*ndata++ = n2;
n1 -= n2 + 1;
nused += n2 + 1;
while (n2 > 0) {
c = *label++;
if (downcase)
c = maptolower[(int)c];
*ndata++ = c;
n2--;
}
labels++;
if (n1 > 0) {
INSIST(labels <= 127);
offsets[labels] = nused;
}
}
if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
name->attributes |= DNS_NAMEATTR_ABSOLUTE;
}
} else
name->attributes |= DNS_NAMEATTR_ABSOLUTE;
name->ndata = (unsigned char *)target->base + target->used;
name->labels = labels;
name->length = nused;
isc_buffer_forward(source, tused);
isc_buffer_add(target, name->length);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
isc_buffer_t *target)
{
unsigned char *ndata;
char *tdata;
unsigned int nlen, tlen;
unsigned char c;
unsigned int trem, count;
unsigned int labels;
isc_boolean_t saw_root = ISC_FALSE;
/*
* This function assumes the name is in proper uncompressed
* wire format.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(ISC_BUFFER_VALID(target));
ndata = name->ndata;
nlen = name->length;
labels = name->labels;
tdata = isc_buffer_used(target);
tlen = isc_buffer_availablelength(target);
trem = tlen;
if (labels == 0 && nlen == 0) {
/*
* Special handling for an empty name.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
/*
* The names of these booleans are misleading in this case.
* This empty name is not necessarily from the root node of
* the DNS root zone, nor is a final dot going to be included.
* They need to be set this way, though, to keep the "@"
* from being trounced.
*/
saw_root = ISC_TRUE;
omit_final_dot = ISC_FALSE;
*tdata++ = '@';
trem--;
/*
* Skip the while() loop.
*/
nlen = 0;
} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
/*
* Special handling for the root label.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
saw_root = ISC_TRUE;
omit_final_dot = ISC_FALSE;
*tdata++ = '.';
trem--;
/*
* Skip the while() loop.
*/
nlen = 0;
}
while (labels > 0 && nlen > 0 && trem > 0) {
labels--;
count = *ndata++;
nlen--;
if (count == 0) {
saw_root = ISC_TRUE;
break;
}
if (count < 64) {
INSIST(nlen >= count);
while (count > 0) {
c = *ndata;
switch (c) {
case 0x22: /* '"' */
case 0x28: /* '(' */
case 0x29: /* ')' */
case 0x2E: /* '.' */
case 0x3B: /* ';' */
case 0x5C: /* '\\' */
/* Special modifiers in zone files. */
case 0x40: /* '@' */
case 0x24: /* '$' */
if (trem < 2)
return (ISC_R_NOSPACE);
*tdata++ = '\\';
CONVERTFROMASCII(c);
*tdata++ = c;
ndata++;
trem -= 2;
nlen--;
break;
default:
if (c > 0x20 && c < 0x7f) {
if (trem == 0)
return (ISC_R_NOSPACE);
CONVERTFROMASCII(c);
*tdata++ = c;
ndata++;
trem--;
nlen--;
} else {
char buf[5];
if (trem < 4)
return (ISC_R_NOSPACE);
snprintf(buf, sizeof(buf),
"\\%03u", c);
memcpy(tdata, buf, 4);
tdata += 4;
trem -= 4;
ndata++;
nlen--;
}
}
count--;
}
} else {
FATAL_ERROR(__FILE__, __LINE__,
"Unexpected label type %02x", count);
/* NOTREACHED */
}
/*
* The following assumes names are absolute. If not, we
* fix things up later. Note that this means that in some
* cases one more byte of text buffer is required than is
* needed in the final output.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
*tdata++ = '.';
trem--;
}
if (nlen != 0 && trem == 0)
return (ISC_R_NOSPACE);
if (!saw_root || omit_final_dot)
trem++;
isc_buffer_add(target, tlen - trem);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
isc_buffer_t *target)
{
unsigned char *ndata;
char *tdata;
unsigned int nlen, tlen;
unsigned char c;
unsigned int trem, count;
unsigned int labels;
/*
* This function assumes the name is in proper uncompressed
* wire format.
*/
REQUIRE(VALID_NAME(name));
REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
REQUIRE(ISC_BUFFER_VALID(target));
ndata = name->ndata;
nlen = name->length;
labels = name->labels;
tdata = isc_buffer_used(target);
tlen = isc_buffer_availablelength(target);
trem = tlen;
if (nlen == 1 && labels == 1 && *ndata == '\0') {
/*
* Special handling for the root label.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
omit_final_dot = ISC_FALSE;
*tdata++ = '.';
trem--;
/*
* Skip the while() loop.
*/
nlen = 0;
}
while (labels > 0 && nlen > 0 && trem > 0) {
labels--;
count = *ndata++;
nlen--;
if (count == 0)
break;
if (count < 64) {
INSIST(nlen >= count);
while (count > 0) {
c = *ndata;
if ((c >= 0x30 && c <= 0x39) || /* digit */
(c >= 0x41 && c <= 0x5A) || /* uppercase */
(c >= 0x61 && c <= 0x7A) || /* lowercase */
c == 0x2D || /* hyphen */
c == 0x5F) /* underscore */
{
if (trem == 0)
return (ISC_R_NOSPACE);
/* downcase */
if (c >= 0x41 && c <= 0x5A)
c += 0x20;
CONVERTFROMASCII(c);
*tdata++ = c;
ndata++;
trem--;
nlen--;
} else {
if (trem < 3)
return (ISC_R_NOSPACE);
sprintf(tdata, "%%%02X", c);
tdata += 3;
trem -= 3;
ndata++;
nlen--;
}
count--;
}
} else {
FATAL_ERROR(__FILE__, __LINE__,
"Unexpected label type %02x", count);
/* NOTREACHED */
}
/*
* The following assumes names are absolute. If not, we
* fix things up later. Note that this means that in some
* cases one more byte of text buffer is required than is
* needed in the final output.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
*tdata++ = '.';
trem--;
}
if (nlen != 0 && trem == 0)
return (ISC_R_NOSPACE);
if (omit_final_dot)
trem++;
isc_buffer_add(target, tlen - trem);
return (ISC_R_SUCCESS);
}
isc_result_t
dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
unsigned char *sndata, *ndata;
unsigned int nlen, count, labels;
isc_buffer_t buffer;
/*
* Downcase 'source'.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(VALID_NAME(name));
if (source == name) {
REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
isc_buffer_init(&buffer, source->ndata, source->length);
target = &buffer;
ndata = source->ndata;
} else {
REQUIRE(BINDABLE(name));
REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
(target == NULL && ISC_BUFFER_VALID(name->buffer)));
if (target == NULL) {
target = name->buffer;
isc_buffer_clear(name->buffer);
}
ndata = (unsigned char *)target->base + target->used;
name->ndata = ndata;
}
sndata = source->ndata;
nlen = source->length;
labels = source->labels;
if (nlen > (target->length - target->used)) {
MAKE_EMPTY(name);
return (ISC_R_NOSPACE);
}
while (labels > 0 && nlen > 0) {
labels--;
count = *sndata++;
*ndata++ = count;
nlen--;
if (count < 64) {
INSIST(nlen >= count);
while (count > 0) {
*ndata++ = maptolower[(*sndata++)];
nlen--;
count--;
}
} else {
FATAL_ERROR(__FILE__, __LINE__,
"Unexpected label type %02x", count);
/* Does not return. */
}
}
if (source != name) {
name->labels = source->labels;
name->length = source->length;
if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
name->attributes = DNS_NAMEATTR_ABSOLUTE;
else
name->attributes = 0;
if (name->labels > 0 && name->offsets != NULL)
set_offsets(name, name->offsets, NULL);
}
isc_buffer_add(target, name->length);
return (ISC_R_SUCCESS);
}
static void
set_offsets(const dns_name_t *name, unsigned char *offsets,
dns_name_t *set_name)
{
unsigned int offset, count, length, nlabels;
unsigned char *ndata;
isc_boolean_t absolute;
ndata = name->ndata;
length = name->length;
offset = 0;
nlabels = 0;
absolute = ISC_FALSE;
while (offset != length) {
INSIST(nlabels < 128);
offsets[nlabels++] = offset;
count = *ndata++;
offset++;
INSIST(count <= 63);
offset += count;
ndata += count;
INSIST(offset <= length);
if (count == 0) {
absolute = ISC_TRUE;
break;
}
}
if (set_name != NULL) {
INSIST(set_name == name);
set_name->labels = nlabels;
set_name->length = offset;
if (absolute)
set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
else
set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
}
INSIST(nlabels == name->labels);
INSIST(offset == name->length);
}
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)
{
unsigned char *cdata, *ndata;
unsigned int cused; /* Bytes of compressed name data used */
unsigned int hops, nused, labels, n, nmax;
unsigned int current, new_current, biggest_pointer;
isc_boolean_t done;
fw_state state = fw_start;
unsigned int c;
unsigned char *offsets;
dns_offsets_t odata;
isc_boolean_t downcase;
/*
* Copy the possibly-compressed name at source into target,
* decompressing it.
*/
REQUIRE(VALID_NAME(name));
REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
(target == NULL && ISC_BUFFER_VALID(name->buffer)));
downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
if (target == NULL && name->buffer != NULL) {
target = name->buffer;
isc_buffer_clear(target);
}
REQUIRE(dctx != NULL);
REQUIRE(BINDABLE(name));
INIT_OFFSETS(name, offsets, odata);
/*
* Make 'name' empty in case of failure.
*/
MAKE_EMPTY(name);
/*
* Initialize things to make the compiler happy; they're not required.
*/
n = 0;
new_current = 0;
/*
* Set up.
*/
labels = 0;
hops = 0;
done = ISC_FALSE;
ndata = isc_buffer_used(target);
nused = 0;
/*
* Find the maximum number of uncompressed target name
* bytes we are willing to generate. This is the smaller
* of the available target buffer length and the
* maximum legal domain name length (255).
*/
nmax = isc_buffer_availablelength(target);
if (nmax > DNS_NAME_MAXWIRE)
nmax = DNS_NAME_MAXWIRE;
cdata = isc_buffer_current(source);
cused = 0;
current = source->current;
biggest_pointer = current;
/*
* Note: The following code is not optimized for speed, but
* rather for correctness. Speed will be addressed in the future.
*/
while (current < source->active && !done) {
c = *cdata++;
current++;
if (hops == 0)
cused++;
switch (state) {
case fw_start:
if (c < 64) {
offsets[labels] = nused;
labels++;
if (nused + c + 1 > nmax)
goto full;
nused += c + 1;
*ndata++ = c;
if (c == 0)
done = ISC_TRUE;
n = c;
state = fw_ordinary;
} else if (c >= 128 && c < 192) {
/*
* 14 bit local compression pointer.
* Local compression is no longer an
* IETF draft.
*/
return (DNS_R_BADLABELTYPE);
} else if (c >= 192) {
/*
* Ordinary 14-bit pointer.
*/
if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
0)
return (DNS_R_DISALLOWED);
new_current = c & 0x3F;
n = 1;
state = fw_newcurrent;
} else
return (DNS_R_BADLABELTYPE);
break;
case fw_ordinary:
if (downcase)
c = maptolower[c];
/* FALLTHROUGH */
case fw_copy:
*ndata++ = c;
n--;
if (n == 0)
state = fw_start;
break;
case fw_newcurrent:
new_current *= 256;
new_current += c;
n--;
if (n != 0)
break;
if (new_current >= biggest_pointer)
return (DNS_R_BADPOINTER);
biggest_pointer = new_current;
current = new_current;
cdata = (unsigned char *)source->base +
current;
hops++;
if (hops > DNS_POINTER_MAXHOPS)
return (DNS_R_TOOMANYHOPS);
state = fw_start;
break;
default:
FATAL_ERROR(__FILE__, __LINE__,
"Unknown state %d", state);
/* Does not return. */
}
}
if (!done)
return (ISC_R_UNEXPECTEDEND);
name->ndata = (unsigned char *)target->base + target->used;
name->labels = labels;
name->length = nused;
name->attributes |= DNS_NAMEATTR_ABSOLUTE;
isc_buffer_forward(source, cused);
isc_buffer_add(target, name->length);
return (ISC_R_SUCCESS);
full:
if (nmax == DNS_NAME_MAXWIRE)
/*
* The name did not fit even though we had a buffer
* big enough to fit a maximum-length name.
*/
return (DNS_R_NAMETOOLONG);
else
/*
* The name might fit if only the caller could give us a
* big enough buffer.
*/
return (ISC_R_NOSPACE);
}
isc_result_t
dns_name_towire(dns_name_t *name, dns_compress_t *cctx, isc_buffer_t *target) {
unsigned int methods;
isc_uint16_t offset;
dns_name_t gp; /* Global compression prefix */
isc_boolean_t gf; /* Global compression target found */
isc_uint16_t go; /* Global compression offset */
dns_offsets_t clo;
dns_name_t clname;
/*
* Convert 'name' into wire format, compressing it as specified by the
* compression context 'cctx', and storing the result in 'target'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(cctx != NULL);
REQUIRE(ISC_BUFFER_VALID(target));
/*
* If 'name' doesn't have an offsets table, make a clone which
* has one.
*/
if (name->offsets == NULL) {
DNS_NAME_INIT(&clname, clo);
dns_name_clone(name, &clname);
name = &clname;
}
DNS_NAME_INIT(&gp, NULL);
offset = target->used; /*XXX*/
methods = dns_compress_getmethods(cctx);
if ((methods & DNS_COMPRESS_GLOBAL14) != 0)
gf = dns_compress_findglobal(cctx, name, &gp, &go);
else
gf = ISC_FALSE;
/*
* If the offset is too high for 14 bit global compression, we're
* out of luck.
*/
if (gf && go >= 0x4000)
gf = ISC_FALSE;
/*
* Will the compression pointer reduce the message size?
*/
if (gf && (gp.length + 2) >= name->length)
gf = ISC_FALSE;
if (gf) {
if (target->length - target->used < gp.length)
return (ISC_R_NOSPACE);
(void)memcpy((unsigned char *)target->base + target->used,
gp.ndata, (size_t)gp.length);
isc_buffer_add(target, gp.length);
go |= 0xc000;
if (target->length - target->used < 2)
return (ISC_R_NOSPACE);
isc_buffer_putuint16(target, go);
if (gp.length != 0)
dns_compress_add(cctx, name, &gp, offset);
} else {
if (target->length - target->used < name->length)
return (ISC_R_NOSPACE);
(void)memcpy((unsigned char *)target->base + target->used,
name->ndata, (size_t)name->length);
isc_buffer_add(target, name->length);
dns_compress_add(cctx, name, name, offset);
}
return (ISC_R_SUCCESS);
}
isc_result_t
dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
isc_buffer_t *target)
{
unsigned char *ndata, *offsets;
unsigned int nrem, labels, prefix_length, length;
isc_boolean_t copy_prefix = ISC_TRUE;
isc_boolean_t copy_suffix = ISC_TRUE;
isc_boolean_t absolute = ISC_FALSE;
dns_name_t tmp_name;
dns_offsets_t odata;
/*
* Concatenate 'prefix' and 'suffix'.
*/
REQUIRE(prefix == NULL || VALID_NAME(prefix));
REQUIRE(suffix == NULL || VALID_NAME(suffix));
REQUIRE(name == NULL || VALID_NAME(name));
REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
(target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer)));
if (prefix == NULL || prefix->labels == 0)
copy_prefix = ISC_FALSE;
if (suffix == NULL || suffix->labels == 0)
copy_suffix = ISC_FALSE;
if (copy_prefix &&
(prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
absolute = ISC_TRUE;
REQUIRE(!copy_suffix);
}
if (name == NULL) {
DNS_NAME_INIT(&tmp_name, odata);
name = &tmp_name;
}
if (target == NULL) {
INSIST(name->buffer != NULL);
target = name->buffer;
isc_buffer_clear(name->buffer);
}
REQUIRE(BINDABLE(name));
/*
* Set up.
*/
nrem = target->length - target->used;
ndata = (unsigned char *)target->base + target->used;
if (nrem > DNS_NAME_MAXWIRE)
nrem = DNS_NAME_MAXWIRE;
length = 0;
prefix_length = 0;
labels = 0;
if (copy_prefix) {
prefix_length = prefix->length;
length += prefix_length;
labels += prefix->labels;
}
if (copy_suffix) {
length += suffix->length;
labels += suffix->labels;
}
if (length > DNS_NAME_MAXWIRE) {
MAKE_EMPTY(name);
return (DNS_R_NAMETOOLONG);
}
if (length > nrem) {
MAKE_EMPTY(name);
return (ISC_R_NOSPACE);
}
if (copy_suffix) {
if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
absolute = ISC_TRUE;
if (suffix == name && suffix->buffer == target)
memmove(ndata + prefix_length, suffix->ndata,
suffix->length);
else
memcpy(ndata + prefix_length, suffix->ndata,
suffix->length);
}
/*
* If 'prefix' and 'name' are the same object, and the object has
* a dedicated buffer, and we're using it, then we don't have to
* copy anything.
*/
if (copy_prefix && (prefix != name || prefix->buffer != target))
memcpy(ndata, prefix->ndata, prefix_length);
name->ndata = ndata;
name->labels = labels;
name->length = length;
if (absolute)
name->attributes = DNS_NAMEATTR_ABSOLUTE;
else
name->attributes = 0;
if (name->labels > 0 && name->offsets != NULL) {
INIT_OFFSETS(name, offsets, odata);
set_offsets(name, offsets, NULL);
}
isc_buffer_add(target, name->length);
return (ISC_R_SUCCESS);
}
void
dns_name_split(dns_name_t *name, unsigned int suffixlabels,
dns_name_t *prefix, dns_name_t *suffix)
{
unsigned int splitlabel;
REQUIRE(VALID_NAME(name));
REQUIRE(suffixlabels > 0);
REQUIRE(suffixlabels < name->labels);
REQUIRE(prefix != NULL || suffix != NULL);
REQUIRE(prefix == NULL ||
(VALID_NAME(prefix) &&
prefix->buffer != NULL &&
BINDABLE(prefix)));
REQUIRE(suffix == NULL ||
(VALID_NAME(suffix) &&
suffix->buffer != NULL &&
BINDABLE(suffix)));
splitlabel = name->labels - suffixlabels;
if (prefix != NULL)
dns_name_getlabelsequence(name, 0, splitlabel, prefix);
if (suffix != NULL)
dns_name_getlabelsequence(name, splitlabel,
suffixlabels, suffix);
return;
}
isc_result_t
dns_name_dup(dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
/*
* Make 'target' a dynamically allocated copy of 'source'.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(source->length > 0);
REQUIRE(VALID_NAME(target));
REQUIRE(BINDABLE(target));
/*
* Make 'target' empty in case of failure.
*/
MAKE_EMPTY(target);
target->ndata = isc_mem_get(mctx, source->length);
if (target->ndata == NULL)
return (ISC_R_NOMEMORY);
memcpy(target->ndata, source->ndata, source->length);
target->length = source->length;
target->labels = source->labels;
target->attributes = DNS_NAMEATTR_DYNAMIC;
if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
target->attributes |= DNS_NAMEATTR_ABSOLUTE;
if (target->offsets != NULL) {
if (source->offsets != NULL)
memcpy(target->offsets, source->offsets,
source->labels);
else
set_offsets(target, target->offsets, NULL);
}
return (ISC_R_SUCCESS);
}
isc_result_t
dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
dns_name_t *target)
{
/*
* Make 'target' a read-only dynamically allocated copy of 'source'.
* 'target' will also have a dynamically allocated offsets table.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(source->length > 0);
REQUIRE(VALID_NAME(target));
REQUIRE(BINDABLE(target));
REQUIRE(target->offsets == NULL);
/*
* Make 'target' empty in case of failure.
*/
MAKE_EMPTY(target);
target->ndata = isc_mem_get(mctx, source->length + source->labels);
if (target->ndata == NULL)
return (ISC_R_NOMEMORY);
memcpy(target->ndata, source->ndata, source->length);
target->length = source->length;
target->labels = source->labels;
target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
DNS_NAMEATTR_READONLY;
if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
target->attributes |= DNS_NAMEATTR_ABSOLUTE;
target->offsets = target->ndata + source->length;
if (source->offsets != NULL)
memcpy(target->offsets, source->offsets, source->labels);
else
set_offsets(target, target->offsets, NULL);
return (ISC_R_SUCCESS);
}
void
dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
size_t size;
/*
* Free 'name'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
size = name->length;
if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0)
size += name->labels;
isc_mem_put(mctx, name->ndata, size);
dns_name_invalidate(name);
}
isc_result_t
dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
dns_name_t downname;
unsigned char data[256];
isc_buffer_t buffer;
isc_result_t result;
isc_region_t r;
/*
* Send 'name' in DNSSEC canonical form to 'digest'.
*/
REQUIRE(VALID_NAME(name));
REQUIRE(digest != NULL);
DNS_NAME_INIT(&downname, NULL);
isc_buffer_init(&buffer, data, sizeof(data));
result = dns_name_downcase(name, &downname, &buffer);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_usedregion(&buffer, &r);
return ((digest)(arg, &r));
}
isc_boolean_t
dns_name_dynamic(dns_name_t *name) {
REQUIRE(VALID_NAME(name));
/*
* Returns whether there is dynamic memory associated with this name.
*/
return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
ISC_TRUE : ISC_FALSE);
}
isc_result_t
dns_name_print(dns_name_t *name, FILE *stream) {
isc_result_t result;
isc_buffer_t b;
isc_region_t r;
char t[1024];
/*
* Print 'name' on 'stream'.
*/
REQUIRE(VALID_NAME(name));
isc_buffer_init(&b, t, sizeof(t));
result = dns_name_totext(name, ISC_FALSE, &b);
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_usedregion(&b, &r);
fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
return (ISC_R_SUCCESS);
}
void
dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
isc_result_t result;
isc_buffer_t buf;
REQUIRE(size > 0);
/*
* Leave room for null termination after buffer.
*/
isc_buffer_init(&buf, cp, size - 1);
result = dns_name_totext(name, ISC_TRUE, &buf);
if (result == ISC_R_SUCCESS) {
/*
* Null terminate.
*/
isc_region_t r;
isc_buffer_usedregion(&buf, &r);
((char *) r.base)[r.length] = '\0';
} else
snprintf(cp, size, "<unknown>");
}
isc_result_t
dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
unsigned char *ndata;
/*
* Make dest a copy of source.
*/
REQUIRE(VALID_NAME(source));
REQUIRE(VALID_NAME(dest));
REQUIRE(target != NULL || dest->buffer != NULL);
if (target == NULL) {
target = dest->buffer;
isc_buffer_clear(dest->buffer);
}
REQUIRE(BINDABLE(dest));
/*
* Set up.
*/
if (target->length - target->used < source->length)
return (ISC_R_NOSPACE);
ndata = (unsigned char *)target->base + target->used;
dest->ndata = target->base;
memcpy(ndata, source->ndata, source->length);
dest->ndata = ndata;
dest->labels = source->labels;
dest->length = source->length;
if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
dest->attributes = DNS_NAMEATTR_ABSOLUTE;
else
dest->attributes = 0;
if (dest->labels > 0 && dest->offsets != NULL) {
if (source->offsets != NULL)
memcpy(dest->offsets, source->offsets, source->labels);
else
set_offsets(dest, dest->offsets, NULL);
}
isc_buffer_add(target, dest->length);
return (ISC_R_SUCCESS);
}