name.c revision 9427d2229955845dfbd5953ae889a62c63a16a39
/*
* Copyright (C) 1998-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
* DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
* INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: name.c,v 1.118 2001/01/22 03:30:26 bwelling Exp $ */
#include <config.h>
#include <ctype.h>
#include <dns/compress.h>
typedef enum {
ft_init = 0,
} ft_state;
typedef enum {
fw_start = 0,
} fw_state;
static char digitvalue[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
};
static char hexdigits[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
static unsigned char maptolower[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
#define CONVERTTOASCII(c)
#define CONVERTFROMASCII(c)
else \
var = default;
else { \
var = default; \
}
/*
* Note: If additional attributes are added that should not be set for
* empty names, MAKE_EMPTY() must be changed so it clears them.
*/
#define MAKE_EMPTY(name) \
do { \
} while (0);
/*
* A name is "bindable" if it can be set to point to a new value, i.e.
* name->ndata and name->length may be changed.
*/
== 0)
/*
* Note that the name data must be a char array, not a string
* literal, to avoid compiler warnings about discarding
* the const attribute of a string.
*/
static unsigned char root_ndata[] = { '\0' };
static unsigned char root_offsets[] = { 0 };
static dns_name_t root =
{
{(void *)-1, (void *)-1},
};
/* XXXDCL make const? */
static unsigned char wild_offsets[] = { 0 };
static dns_name_t wild =
{
{(void *)-1, (void *)-1},
};
/* XXXDCL make const? */
static void
static void
/*
* Yes, get_bit and set_bit are lame. We define them here so they can
* be inlined by smart compilers.
*/
static inline unsigned int
}
static inline void
if (bit != 0)
else
}
/*
* Get the type of 'label'.
*/
return (dns_labeltype_ordinary);
else
return (dns_labeltype_bitstring);
}
unsigned int
unsigned int count;
/*
* The number of bits in a bitstring label.
*/
if (count == 0)
count = 256;
return (count);
}
/*
* The 'n'th most significant bit of 'label'.
*
* Notes:
* Numbering starts at 0.
*/
if (count == 0)
count = 256;
if (bit == 0)
return (dns_bitlabel_0);
return (dns_bitlabel_1);
}
void
/*
* Initialize 'name'.
*/
}
void
}
void
/*
* Make 'name' invalid.
*/
name->attributes = 0;
}
void
/*
* Dedicate a buffer for use with 'name'.
*/
}
/*
* Does 'name' have a dedicated buffer?
*/
return (ISC_TRUE);
return (ISC_FALSE);
}
/*
* Does 'name' end in the root label?
*/
return (ISC_TRUE);
return (ISC_FALSE);
}
unsigned char *ndata;
/*
* Is 'name' a wildcard name?
*/
return (ISC_TRUE);
}
return (ISC_FALSE);
}
unsigned char *ndata;
/*
* Does 'name' require EDNS for transmission?
*/
while (nrem > 0) {
nrem--;
if (count == 0)
break;
if (count > 63) {
break;
}
}
return (requiresedns);
}
unsigned int
unsigned int length;
const unsigned char *s;
unsigned int h = 0;
unsigned char c;
/*
* Provide a hash value for 'name'.
*/
return (0);
if (length > 16)
length = 16;
/*
* This hash function is similar to the one Ousterhout
* uses in Tcl.
*/
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);
}
int *orderp,
{
/*
* 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.
*/
/*
* Either name1 is absolute and name2 is absolute, or neither is.
*/
nlabels = 0;
nbits = 0;
if (ldiff < 0)
l = l1;
else
l = l2;
while (l > 0) {
l--;
l1--;
l2--;
if (cdiff < 0)
else
while (count > 0) {
(int)maptolower[*label2];
if (chdiff != 0) {
goto done;
}
count--;
label1++;
label2++;
}
if (cdiff != 0) {
goto done;
}
nlabels++;
if (count2 == 0)
*orderp = 1;
else
*orderp = -1;
goto done;
if (count1 == 0)
*orderp = -1;
else
*orderp = 1;
goto done;
} else {
if (count1 == 0)
count1 = 256;
if (count2 == 0)
count2 = 256;
cdiff = -1;
} else {
cdiff = 1;
else
cdiff = 0;
}
/* Yes, this loop is really slow! */
for (n = 0; n < count; n++) {
*orderp = -1;
goto done;
*orderp = 1;
goto done;
}
if (nbits == 0)
nlabels++;
nbits++;
}
if (cdiff != 0) {
/*
* If we're here, then we have two bitstrings
* of differing length.
*
* If the name with the shorter bitstring
* has any labels, then it must be greater
* than the longer bitstring. This is a bit
* counterintuitive. If the name with the
* shorter bitstring has any more labels, then
* the next label must be an ordinary label.
* It can't be a bitstring label because if it
* were, then there would be room for it in
* the current bitstring label (since all
* bitstrings are canonicalized). Since
* there's at least one more bit in the
* name with the longer bitstring, and since
* a bitlabel sorts before any ordinary label,
* the name with the longer bitstring must
* be lexically before the one with the shorter
* bitstring.
*
* On the other hand, if there are no more
* labels in the name with the shorter
* bitstring, then that name contains the
* other name.
*/
if (cdiff < 0) {
if (l1 > 0)
*orderp = 1;
else {
*orderp = -1;
namereln =
}
} else {
if (l2 > 0)
*orderp = -1;
else {
*orderp = 1;
namereln =
}
}
goto done;
}
nbits = 0;
}
}
if (ldiff < 0)
else if (ldiff > 0)
else
done:
return (namereln);
}
int
int order;
/*
* 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.
*/
return (order);
}
unsigned int l, count;
unsigned char c;
/*
* 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.
*/
/*
* Either name1 is absolute and name2 is absolute, or neither is.
*/
return (ISC_FALSE);
return (ISC_FALSE);
while (l > 0) {
l--;
return (ISC_FALSE);
if (count <= 63) {
while (count > 0) {
count--;
c = maptolower[*label1++];
if (c != maptolower[*label2++])
return (ISC_FALSE);
}
} else {
return (ISC_FALSE);
if (count == 0)
count = 256;
/*
* Number of bytes.
*/
while (count > 0) {
count--;
c = *label1++;
if (c != *label2++)
return (ISC_FALSE);
}
}
}
return (ISC_TRUE);
}
int
/*
* Compare two absolute names as rdata.
*/
while (l > 0) {
l--;
while (count > 0) {
count--;
return (-1);
return (1);
}
return (1);
return (-1);
} else {
if (count1 == 0)
count1 = 256;
if (count2 == 0)
count2 = 256;
/* number of bytes */
while (count > 0) {
count--;
}
}
}
/*
* 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.
*/
return (0);
}
int order;
/*
* 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.
*/
&nbits);
if (namereln == dns_namereln_subdomain ||
return (ISC_TRUE);
return (ISC_FALSE);
}
int order;
return (ISC_TRUE);
return (ISC_FALSE);
}
unsigned int
unsigned char *ndata;
/*
* The depth of 'name'.
*/
return (0);
depth = 0;
while (nrem > 0) {
nrem--;
if (count > 63) {
n = *ndata++;
nrem--;
if (n == 0)
n = 256;
depth += n;
count = n / 8;
if (n % 8 != 0)
count++;
} else {
depth++;
if (count == 0)
break;
}
}
return (depth);
}
unsigned int
/*
* How many labels does 'name' have?
*/
}
void
unsigned char *offsets;
/*
* Make 'label' refer to the 'n'th least significant label of 'name'.
*/
else
}
void
unsigned int first, unsigned int n,
{
unsigned char *offsets;
unsigned int firstoffset, endoffset;
/*
* Make 'target' refer to the 'n' labels including and following
* 'first' in 'source'.
*/
else
else
else
/*
* 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().
*/
}
void
/*
* Make 'target' refer to the same name as 'source'.
*/
(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
else
}
}
void
unsigned char *offsets;
unsigned int len;
/*
* Make 'name' refer to region 'r'.
*/
if (len > DNS_NAME_MAXWIRE)
} else {
r->length : DNS_NAME_MAXWIRE;
}
if (r->length > 0)
else {
}
}
void
/*
* Make 'r' refer to 'name'.
*/
DNS_NAME_TOREGION(name, r);
}
{
char *tdata;
char c;
unsigned char dqchars[4];
unsigned char *offsets;
/*
* 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.
*/
}
offsets[0] = 0;
/*
* Initialize things to make the compiler happy; they're not required.
*/
n1 = 0;
n2 = 0;
vlen = 0;
digits = 0;
value = 0;
count = 0;
tbcount = 0;
bitlength = 0;
maxlength = 0;
/*
* Make 'name' empty in case of failure.
*/
/*
* Set up the state machine.
*/
tused = 0;
if (nrem > 255)
nrem = 255;
nused = 0;
labels = 0;
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++;
break;
}
if (c == '@' && tlen == 0) {
break;
}
/* FALLTHROUGH */
case ft_start:
ndata++;
nrem--;
nused++;
count = 0;
if (c == '\\') {
break;
}
kind = ft_ordinary;
state = ft_ordinary;
/* FALLTHROUGH */
case ft_ordinary:
if (c == '.') {
if (count == 0)
return (DNS_R_EMPTYLABEL);
labels++;
if (tlen == 0) {
labels++;
*ndata++ = 0;
nrem--;
nused++;
}
} else if (c == '\\') {
} 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 == '[') {
kind = ft_bitstring;
ndata++;
nrem--;
nused++;
break;
}
kind = ft_ordinary;
/* 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;
/* 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)
nrem--;
nused++;
state = ft_ordinary;
}
break;
case ft_bitstring:
/* count is zero */
tbcount = 0;
value = 0;
if (c == 'b') {
vlen = 8;
maxlength = 256;
} else if (c == 'o') {
vlen = 8;
maxlength = 256;
} else if (c == 'x') {
vlen = 8;
maxlength = 256;
} else if (isdigit(c & 0xff)) {
vlen = 32;
maxlength = 32;
n1 = 0;
n2 = 0;
digits = 0;
goto no_read;
} else
return (DNS_R_BADBITSTRING);
break;
case ft_binary:
if (c != '0' && c != '1') {
goto no_read;
}
value <<= 1;
if (c == '1')
value |= 1;
count++;
tbcount++;
if (tbcount > 256)
return (DNS_R_BITSTRINGTOOLONG);
if (count == 8) {
nrem--;
nused++;
count = 0;
}
break;
case ft_octal:
goto no_read;
}
value <<= 3;
value += digitvalue[(int)c];
count += 3;
tbcount += 3;
/*
* The total bit count is tested against 258 instead
* of 256 because of the possibility that the bitstring
* label is exactly 256 bits long; on the last octal
* digit (which must be 4) tbcount is incremented
* from 255 to 258. This case is adequately handled
* later.
*/
if (tbcount > 258)
return (DNS_R_BITSTRINGTOOLONG);
if (count == 8) {
nrem--;
nused++;
count = 0;
} else if (count == 9) {
nrem--;
nused++;
value &= 1;
count = 1;
} else if (count == 10) {
nrem--;
nused++;
value &= 3;
count = 2;
}
break;
case ft_hex:
if (!isxdigit(c & 0xff)) {
goto no_read;
}
value <<= 4;
value += digitvalue[(int)c];
count += 4;
tbcount += 4;
if (tbcount > 256)
return (DNS_R_BITSTRINGTOOLONG);
if (count == 8) {
nrem--;
nused++;
count = 0;
}
break;
case ft_dottedquad:
return (DNS_R_BADDOTTEDQUAD);
n2 *= 256;
n1++;
if (n1 == 4) {
tbcount = 32;
goto no_read;
}
value = 0;
digits = 0;
break;
case ft_dqdecimal:
if (!isdigit(c & 0xff)) {
return (DNS_R_BADDOTTEDQUAD);
goto no_read;
}
digits++;
if (digits > 3)
return (DNS_R_BADDOTTEDQUAD);
value *= 10;
value += digitvalue[(int)c];
break;
case ft_maybeslash:
bitlength = 0;
if (c == '/') {
break;
}
/* FALLTHROUGH */
case ft_finishbitstring:
if (c == ']') {
if (tbcount == 0)
return (DNS_R_BADBITSTRING);
if (count > 0) {
if (n1 != 0)
}
if (bitlength != 0) {
return (DNS_R_BADBITSTRING);
return (DNS_R_BADBITSTRING);
/*
* Figure out correct number
* of octal digits for the
* bitlength, and compare to
* what was given.
*/
if (bitlength % 3 != 0)
n1++;
/* tbcount % 3 == 0 */
return (DNS_R_BADBITSTRING);
/*
* Check that no bits extend
* past the end of the last
* byte that is included in
* the bitlength. Example:
* \[o036/8] == \[b00001111],
* which fits into just one
* byte, but the three octal
* digits actually specified
* two bytes worth of data,
* 9 bits, before the bitlength
* limited it back to one byte.
*
* n1 is the number of bytes
* necessary for the bitlength.
* n2 is the number of bytes
* encompassed by the octal
* digits. If they are not
* equal, then "value" holds
* the excess bits, which
* must be zero. If the bits
* are zero, then "count" is
* zero'ed to prevent the
* addition of another byte
* below.
*/
if (value != 0)
return
else
count = 0;
}
/*
* Figure out correct number
* of hex digits for the
* bitlength, and compare to
* what was given.
*/
if (bitlength % 4 != 0)
n1++;
/* tbcount % 4 == 0 */
return (DNS_R_BADBITSTRING);
}
if (n1 != 0) {
/*
* Are the pad bits in the
* last 'vlen' bits zero?
*/
if ((value &
return (DNS_R_BADBITSTRING);
}
} else if (kind == ft_dottedquad)
bitlength = 32;
else if (tbcount > 256)
/*
* This can happen when an octal
* bitstring label of 86 octal digits
* is specified; tbcount will be 258.
* This is not trapped above because
* the bitstring label might be limited
* by a "/256" modifier.
*/
return (DNS_R_BADBITSTRING);
else
if (count > 0) {
nrem--;
nused++;
}
if (kind == ft_dottedquad) {
if (bitlength % 8 != 0)
n1++;
return (ISC_R_NOSPACE);
nrem--;
nused++;
}
}
if (bitlength == 256)
*label = 0;
else
labels++;
} else
return (DNS_R_BADBITSTRING);
break;
case ft_bitlength:
if (!isdigit(c & 0xff)) {
if (bitlength == 0)
return (DNS_R_BADBITSTRING);
goto no_read;
}
bitlength *= 10;
bitlength += digitvalue[(int)c];
return (DNS_R_BADBITSTRING);
break;
case ft_eatdot:
if (c != '.')
return (DNS_R_BADBITSTRING);
if (tlen == 0) {
labels++;
*ndata++ = 0;
nrem--;
nused++;
}
break;
default:
"Unexpected state %d", state);
/* Does not return. */
}
}
if (!done) {
if (nrem == 0)
return (ISC_R_NOSPACE);
return (ISC_R_UNEXPECTEDEND);
if (state == ft_ordinary) {
labels++;
}
return (ISC_R_NOSPACE);
while (n1 > 0) {
if (n2 <= 63) {
while (n2 > 0) {
c = *label++;
if (downcase)
c = maptolower[(int)c];
*ndata++ = c;
n2--;
}
} else {
if (bitlength == 0)
bitlength = 256;
if (bitlength % 8 != 0)
n2++;
while (n2 > 0) {
n2--;
}
}
labels++;
if (n1 > 0) {
}
}
}
} else
if (saw_bitstring)
return (ISC_R_SUCCESS);
}
{
unsigned char *ndata;
char *tdata;
unsigned char c;
unsigned int labels;
char num[4];
/*
* This function assumes the name is in proper uncompressed
* wire format.
*/
/*
* 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.
*/
*tdata++ = '@';
trem--;
/*
* Skip the while() loop.
*/
nlen = 0;
/*
* Special handling for the root label.
*/
if (trem == 0)
return (ISC_R_NOSPACE);
*tdata++ = '.';
trem--;
/*
* Skip the while() loop.
*/
nlen = 0;
}
labels--;
nlen--;
if (count == 0) {
break;
}
if (count < 64) {
while (count > 0) {
c = *ndata;
switch (c) {
case 0x22: /* '"' */
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 {
if (trem < 4)
return (ISC_R_NOSPACE);
c);
tdata += 4;
trem -= 4;
ndata++;
nlen--;
}
}
count--;
}
} else if (count == DNS_LABELTYPE_BITSTRING) {
if (trem < 3)
return (ISC_R_NOSPACE);
*tdata++ = '\\';
*tdata++ = '[';
*tdata++ = 'x';
trem -= 3;
if (count == 0)
count = 256;
nlen--;
if (count % 8 != 0)
bytes++;
if (count % 4 != 0)
nibbles++;
return (ISC_R_NOSPACE);
while (nibbles > 0) {
c = *ndata++;
nibbles--;
if (nibbles != 0) {
i++;
nibbles--;
}
}
return (ISC_R_NOSPACE);
*tdata++ = '/';
for (i = 0; i < len; i++)
*tdata++ = ']';
} else {
"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--;
}
return (ISC_R_NOSPACE);
if (!saw_root || omit_final_dot)
trem++;
return (ISC_R_SUCCESS);
}
/*
* Downcase 'source'.
*/
} else {
}
}
return (ISC_R_NOSPACE);
}
labels--;
nlen--;
if (count < 64) {
while (count > 0) {
nlen--;
count--;
}
} else if (count == DNS_LABELTYPE_BITSTRING) {
if (count == 0)
count = 256;
nlen--;
if (count % 8 != 0)
bytes++;
while (bytes > 0) {
bytes--;
}
} else {
"Unexpected label type %02x", count);
/* Does not return. */
}
}
else
name->attributes = 0;
}
return (ISC_R_SUCCESS);
}
static void
{
unsigned char *ndata;
offset = 0;
nlabels = 0;
offset++;
if (count <= 63) {
if (count == 0) {
break;
}
} else {
n = *ndata++;
offset++;
if (n == 0)
n = 256;
count = n / 8;
if (n % 8 != 0)
count++;
}
}
if (absolute)
else
}
}
static void
unsigned char tail[32];
/*
* The caller MUST ensure that all bitstrings are correctly formatted
* and that the offsets table is valid.
*/
while (n > 0) {
if (n != 0) {
n--;
if (curr[0] != DNS_LABELTYPE_BITSTRING)
continue;
/*
* We have consecutive bitstrings labels, and
* the more significant label ('head') has
* space.
*/
if (currbits == 0)
currbits = 256;
currindex = 0;
if (headbits == 0)
headbits = 256;
if (headrem != 0)
if (headrem != 0) {
do {
bit);
currindex++;
headindex++;
headbits++;
count--;
headrem--;
} while (headrem != 0);
}
tailindex = 0;
tailbits = 0;
while (count > 0) {
currindex++;
tailindex++;
tailbits++;
count--;
}
newbits = 0;
newindex = 0;
bit);
currindex++;
newindex++;
newbits++;
}
/* Zero remaining pad bits, if any. */
if (newrem != 0) {
count++;
while (newrem > 0) {
0);
newrem--;
newindex++;
}
}
} else {
/* We got rid of curr. */
}
/* copy head, then tail, then rest to curr. */
curr[0] = DNS_LABELTYPE_BITSTRING;
if (count == 256)
curr[1] = 0;
else
curr += 2;
head += 2;
if (headbits % 8 != 0)
count++;
while (count > 0) {
count--;
}
if (tailbits % 8 != 0)
count++;
while (count > 0) {
count--;
}
/*
* The offsets table may now be invalid.
*/
goto again;
}
}
n--;
}
}
{
unsigned int cused; /* Bytes of compressed name data used */
unsigned int c;
unsigned char *offsets;
/*
* Copy the possibly-compressed name at source into target,
* decompressing it.
*/
}
/*
* Make 'name' empty in case of failure.
*/
/*
* Initialize things to make the compiler happy; they're not required.
*/
n = 0;
new_current = 0;
/*
* Set up.
*/
labels = 0;
hops = 0;
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).
*/
if (nmax > DNS_NAME_MAXWIRE)
cused = 0;
/*
* Note: The following code is not optimized for speed, but
* rather for correctness. Speed will be addressed in the future.
*/
c = *cdata++;
current++;
if (hops == 0)
cused++;
switch (state) {
case fw_start:
if (c < 64) {
labels++;
goto full;
nused += c + 1;
*ndata++ = c;
if (c == 0)
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.
*/
0)
return (DNS_R_DISALLOWED);
new_current = c & 0x3F;
n = 1;
} else if (c == DNS_LABELTYPE_BITSTRING) {
labels++;
goto full;
nused++;
*ndata++ = c;
} else
return (DNS_R_BADLABELTYPE);
break;
case fw_ordinary:
if (downcase)
c = maptolower[c];
/* FALLTHROUGH */
case fw_copy:
*ndata++ = c;
n--;
if (n == 0)
break;
case fw_bitstring:
if (c == 0)
n = 256 / 8;
else
n = c / 8;
if ((c % 8) != 0)
n++;
goto full;
nused += n + 1;
*ndata++ = c;
break;
case fw_newcurrent:
new_current *= 256;
new_current += c;
n--;
if (n != 0)
break;
if (new_current >= biggest_pointer)
return (DNS_R_BADPOINTER);
hops++;
if (hops > DNS_POINTER_MAXHOPS)
return (DNS_R_TOOMANYHOPS);
break;
default:
"Unknown state %d", state);
/* Does not return. */
}
}
if (!done)
return (ISC_R_UNEXPECTEDEND);
/*
* We should build the offsets table directly.
*/
if (saw_bitstring)
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);
}
unsigned int methods;
/*
* Convert 'name' into wire format, compressing it as specified by the
* compression context 'cctx', and storing the result in 'target'.
*/
/*
* If 'name' doesn't have an offsets table, make a clone which
* has one.
*/
}
if ((methods & DNS_COMPRESS_GLOBAL14) != 0)
else
/*
* If the offset is too high for 14 bit global compression, we're
* out of luck.
*/
/*
* Will the compression pointer reduce the message size?
*/
if (gf) {
return (ISC_R_NOSPACE);
go |= 0xc000;
return (ISC_R_NOSPACE);
} else {
return (ISC_R_NOSPACE);
}
return (ISC_R_SUCCESS);
}
{
/*
* Concatenate 'prefix' and 'suffix'.
*/
if (copy_prefix &&
}
}
}
/*
* XXX IMPORTANT NOTE
*
* If the most-signficant label in prefix is a bitstring,
* and the least-signficant label in suffix is a bitstring,
* it's possible that compaction could convert them into
* one label. If this happens, then the final size will
* be three bytes less than nrem.
*
* We do not check for this special case, and handling it is
* a little messy; we can't just concatenate and compact,
* because we may only have 255 bytes but might need 258 bytes
* temporarily. There are ways to do this with only 255 bytes,
* which will be implemented later.
*
* For now, we simply reject these few cases as being too
* long.
*/
/*
* Set up.
*/
if (nrem > DNS_NAME_MAXWIRE)
length = 0;
prefix_length = 0;
labels = 0;
if (copy_prefix) {
length += prefix_length;
}
if (copy_suffix) {
}
if (length > DNS_NAME_MAXWIRE) {
return (DNS_R_NAMETOOLONG);
}
return (ISC_R_NOSPACE);
}
if (copy_suffix) {
if (copy_prefix &&
/*
* We only need to call compact() if both the
* least-significant label of the suffix and the
* most-significant label of the prefix are both
* bitstrings.
*
* A further possible optimization, which we don't do,
* is to not compact() if the suffix bitstring is
* full. It will usually not be full, so I don't
* think this is worth it.
*/
} else {
/*
* We don't have an offsets table for prefix,
* and rather than spend the effort to make it
* we'll just compact(), which doesn't cost
* more than computing the offsets table if
* there is no bitstring in prefix.
*/
}
}
else
}
/*
* 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 (absolute)
else
name->attributes = 0;
if (saw_bitstring)
}
return (ISC_R_SUCCESS);
}
unsigned int suffixlabels, unsigned int nbits,
{
REQUIRE(suffixlabels > 0);
(VALID_NAME(prefix) &&
(VALID_NAME(suffix) &&
/*
* When splitting bitstring labels, if prefix and suffix have the same
* buffer, suffix will overwrite the ndata of prefix, corrupting it.
* If prefix has the ndata of name, then it modifies the bitstring
* label and suffix doesn't have the original available. This latter
* problem could be worked around if it is ever deemed desirable.
*/
/*
* Make p point at the count byte of the bitstring label,
* if there is one (p will not be used if we are not
* splitting bits).
*/
/*
* When a bit count is specified, ensure that the label is a bitstring
* label and it has more bits than the requested slice.
*/
(*p == 0 || *p > nbits)));
if (nbits > 0) {
/*
* '2' is for the DNS_LABELTYPE_BITSTRING id
* plus the existing number of bits byte.
*/
/*
* If these are overlapping names ...
* wow. How bizarre could that be?
*/
}
/*
* Set the new bit count. Also, when a bitstring
* label being split is maximal length, compaction
* might be necessary on the prefix.
*/
if (*p == 0) {
*p = 256 - nbits;
} else
*p = *p - nbits;
/*
* Calculate the number of bytes necessary to hold
* all of the bits left in the prefix.
*/
return(ISC_R_NOSPACE);
}
/*
* All of the bits now need to be shifted to the left
* to fill in the space taken by the removed bits.
* This is wonderfully easy when the number of removed
* bits is an integral multiple of 8, but of course
* life isn't always that easy.
*/
dst = p + 1;
if (mod == 0) {
else
} else {
/*
* p is adjusted to point to the last byte of
* the starting bitstring label to make it
* cheap to determine when bits from the next
* byte should be shifted into the low order
* bits of the current byte.
*/
while (len--) {
/*
* The 0xff subexpression guards
* against arithmetic sign extension
* by the right shift.
*/
if (src <= p)
*dst++ |=
~(0xFF << mod);
}
/*
* Et voila, the very last byte has
* automatically already had its padding
* fixed by the left shift.
*/
}
/*
* Yes, = is meant here, not ==. The intent is
* to have it set only when INSISTs are turned on,
* to doublecheck the result of set_offsets.
*/
} else
prefix);
}
if (nbits > 0) {
/*
* The existing bitcount is in src.
* Set len to the number of bytes to be removed,
* and the suffix length to the number of bytes in
* the new name.
*/
src++;
return (ISC_R_NOSPACE);
}
/*
* First set up the bitstring label.
*/
*dst++ = DNS_LABELTYPE_BITSTRING;
if (len > 0) {
/*
* Remember where the next label starts.
*/
/*
* Some bytes are being removed from the
* middle of the name because of the truncation
* of bits in the bitstring label. Copy
* the bytes (whether full with 8 bits or not)
* that are being kept.
*/
/*
* Now just copy the rest of the labels of
* the name by adjusting src to point to
* the next label.
*
* 2 == label type byte + bitcount byte.
*/
src = p;
} else
/*
* XXX DCL better way to decide memcpy vs memmove?
*/
if (len > 0) {
else
}
/*
* The byte that contains the end of the
* bitstring has its pad bytes (if any) masked
* to zero.
*/
if (mod != 0)
/*
* Yes, = is meant here, not ==. The intent is
* to have it set only when INSISTs are turned on,
* to doublecheck the result of set_offsets.
*/
} else
}
/*
* Compacting the prefix can't be done until after the suffix is
* set, because it would screw up the offsets table of 'name'
* when 'name' == 'prefix'.
*/
if (maybe_compact_prefix && splitlabel > 0 &&
return (result);
}
{
/*
* Split 'name' into two pieces at a certain depth.
*/
suffixlabels = 0;
nbits = 0;
do {
label--;
if (count > 63) {
/*
* Get the number of bits in the bitstring label.
*/
n = *ndata++;
if (n == 0)
n = 256;
suffixlabels++;
if (n <= depth) {
/*
* This entire bitstring is in the suffix.
*/
depth -= n;
} else {
/*
* Only the first 'depth' bits of this
* bitstring are in the suffix.
*/
depth = 0;
}
} else {
suffixlabels++;
depth--;
}
/*
* If depth is not zero, then the caller violated the requirement
* that depth <= dns_name_depth(name).
*/
if (depth != 0) {
/*
* We should never get here!
*/
INSIST(0);
}
}
/*
* Make 'target' a dynamically allocated copy of 'source'.
*/
/*
* Make 'target' empty in case of failure.
*/
return (ISC_R_NOMEMORY);
else
}
return (ISC_R_SUCCESS);
}
{
/*
* Make 'target' a read-only dynamically allocated copy of 'source'.
* 'target' will also have a dynamically allocated offsets table.
*/
/*
* Make 'target' empty in case of failure.
*/
return (ISC_R_NOMEMORY);
else
return (ISC_R_SUCCESS);
}
void
/*
* Free 'name'.
*/
}
unsigned char data[256];
isc_region_t r;
/*
* Send 'name' in DNSSEC canonical form to 'digest'.
*/
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_usedregion(&buffer, &r);
}
/*
* Returns whether there is dynamic memory associated with this name.
*/
}
isc_buffer_t b;
isc_region_t r;
char t[1024];
/*
* Print 'name' on 'stream'.
*/
isc_buffer_init(&b, t, sizeof(t));
if (result != ISC_R_SUCCESS)
return (result);
isc_buffer_usedregion(&b, &r);
return (ISC_R_SUCCESS);
}
void
/*
* Leave room for null termination after buffer.
*/
if (result == ISC_R_SUCCESS) {
/*
* Null terminate.
*/
isc_region_t r;
isc_buffer_usedregion(&buf, &r);
} else
}
/*
* Make dest a copy of source.
*/
}
/*
* Set up.
*/
return (ISC_R_NOSPACE);
else
dest->attributes = 0;
}
return (ISC_R_SUCCESS);
}