dns_rdata_fromtext()
,
dns_rdata_totext()
, dns_rdata_fromwire()
,
dns_rdata_towire()
dns_rdata_fromstruct()
,
dns_rdata_tostruct()
and dns_rdata_compare()
)
are designed to provide a single set of routines
for encoding, decoding and comparing dns data preventing the problems that
occurred in BIND 8.x and earlier where there were multiple places in the
code base that
decoded wire format to internal format or compared rdata sometimes with
subtly different behaviour (bugs) or didn't support a particular type leading
to internal inconsistancy.
Each of these generic routines calls type specific routines that provide the type specific details.
From time to time new types are defined and it is necessary to add these types into the existing structure. This document is written to provide instruction on how to do this.
make clean
followed make
in
lib/dns
will cause the new rdata type to be picked up.
Each rdata module must perform the following operations:
There is an additional set of support functions and macros only available to to rdata code.
rdata
hierarchy has the following format.
rdata/ generic/ typename_typenumber.h classname_classnumber/ typename_typenumber.hInitial rdata hierarchy:
rdata/ generic/ ns_2.h md_3.h mf_4.h cname_5.h soa_6.h mb_7.h mg_8.h mr_9.h null_10.h ptr_12.h hinfo_13.h minfo_14.h mx_15.h txt_16.h rp_17.h afsdb_18.h x25_19.h isdn_20.h rt_21.h sig_24.h key_25.h gpos_27.h loc_29.h nxt_30.h cert_37.h dname_39.h unspec_103.h tkey_249.h in_1/ a_1.h wks_11.h nsap_22.h nsap-ptr_23.h px_26.h aaaa_28.h srv_33.h naptr_35.h kx_36.h a6_38.h any_255/ tsig_250.hCLASSNAME and TYPENAME
Class and type names must be from the following alphabet and less that 11 characters in length or otherwise they will be ignored. Permissible alphabet: a to z, 0 to 9 and dash (-). Dash is mapped to underscore (_) for the C function names below.Internal Format
The internal format chosen is DNS wire format without any compression being applied to domain names in the rdata.Convert from text format to internal format
The functions to convert from text format has the following call formats and is declared as follows for class generic functions.Class specific functions contain the class name in addition to the type name.static dns_result_t fromtext_typename(dns_rdataclass_t class, dns_rdatatype_t type, isc_lex_t *lexer, dns_name_t *origin, isc_boolean_t downcase, isc_buffer_t *target);
static dns_result_t fromtext_classname_typename(dns_rdataclass_t class, dns_rdatatype_t type, isc_lex_t *lexer, dns_name_t *origin, isc_boolean_t downcase, isc_buffer_t *target);
class
REQUIRE(class == #)
should be present at the start
of the function.
type
REQUIRE(type == #)
statement at
the begining of the function.
lexer
origin
downcase
target
BINARY
buffer used to write the internal format of the rdata record being read in to.
fromtext_typename()
reads tokens from lexer
,
up to but not including the end of line (EOL) token or end of file (EOF) token.
If the EOL / EOF token is read it should be returned to the input stream.
gettoken()
should be used to read the next token from the input stream and
will return EOL / EOF tokens
automatically unless
they are specifcally requested.
isc_lex_ungettoken()
should
be used to return EOL / EOF (or any other token) to the input stream if
the EOL / EOF token is read.
Unused tokens will cause dns_rdata_fromtext()
to return
DNS_R_EXTRATOKEN
if fromtext_typename()
was successful.
fromtext_typename()
reads external input and as such is a high security area and must be paranoid about its input.
static dns_result_t
totext_typename(dns_rdata_t *rdata, dns_name_t *origin,
isc_buffer_t *target);
static dns_result_t
totext_classname_typename(dns_rdata_t *rdata, dns_name_t *origin,
isc_buffer_t *target);
rdata
rdata->type
and rdata->class
for class specific
RR types should be checked at the start of the function with
REQUIRE(rdata->type == #)
statements.
origin
NULL
then any domainnames with this suffix
should be written out unqualified.
name_prefix()
can be used to
check if origin
is NULL
and provide the correct
arguments to the name conversion routines.
target
TEXT
buffer used to hold the output.
static dns_result_t
fromwire_typename(dns_rdataclass_t class, dns_rdatatype_t type,
isc_buffer_t *source, dns_decompress_t *dctx,
isc_boolean_t downcase, isc_buffer_t *target);
static dns_result_t
fromwire_classname_typename(dns_rdataclass_t class, dns_rdatatype_t type,
isc_buffer_t *source, dns_decompress_t *dctx,
isc_boolean_t downcase, isc_buffer_t *target);
fromwire_classname_typename()
is required to set the valid
decompression methods if there is a domain name in the rdata.
if (dns_decompress_edns(dctx) >= # || !dns_decompress_strict(dctx))
dns_decompress_setmethods(dctx, DNS_COMPRESS_ALL);
else
dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);
class
REQUIRE(class == #)
should be present at the start
of the function.
type
REQUIRE(type == #)
statement at
the begining of the function.
source
BINARY
buffer with the active
region
containing a RR record in wire format.
dctx
dns_name_fromwire()
,
along with downcase
, to enable a compressed domain name
to be extracted from the source.
downcase
dns_name_fromwire()
to say whether the
extracted domainname should be downcased during the extraction.
target
BINARY
buffer where the decompressed and checked
RR record is written.
fromwire_typename()
is a security sensitive routine
as it reads external data and should take extreme care to ensure that
the input data matches its description.
If the active
buffer is not empty at completion and
fromwire_typename()
was otherwise successful
dns_rdata_fromwire()
will return DNS_R_EXTRADATA
.
static dns_result_t
towire_typename(dns_rdata_t *rdata, dns_compress_t *cctx,
isc_buffer_t *target);
static dns_result_t
towire_classname_typename(dns_rdata_t *rdata, dns_compress_t *cctx,
isc_buffer_t *target);
towire_classname_typename()
is required to set the
allowed name compression methods based on EDNS version if there is a
domain name in the rdata.
if (dns_compress_getedns(cctx) >= #)
dns_compress_setmethods(cctx, DNS_COMPRESS_ALL);
else
dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);
rdata
rdata->type
and rdata->class
for class specific
RR types should be checked at the start of the function with
REQUIRE(rdata->type == #)
statements.
cctx
dns_name_towire()
when putting domainnames on the wire.
target
BINARY
buffer used to write the rdata to.
rdata
to the target buffer.
return (mem_tobuffer(target, rdata->data, rdata->length));
static dns_result_t
fromstruct_typename(dns_rdataclass_t class, dns_rdatatype_t type,
void *source, isc_buffer_t *target);
static dns_result_t
fromstruct_classname_typename(dns_rdataclass_t class, dns_rdatatype_t type,
void *source, isc_buffer_t *target);
class
REQUIRE(class == #)
should be present at the start
of the function.
type
REQUIRE(type == #)
statement at
the beginning of the function.
source
target
BINARY
buffer used to write the internal format of the rdata record being read in to.
static dns_result_t
tostruct_typename(dns_rdata_t *rdata, void *target);
static dns_result_t
tostruct_classname_typename(dns_rdata_t *rdata, void *target);
rdata
rdata->type
and rdata->class
for class specific
RR types should be checked at the start of the function with
REQUIRE(rdata->type == #)
statements.
target
static int
compare_typename(dns_rdata_t *rdata1, dns_rdata_t *rdata2);
static int
compare_classname_typename(dns_rdata_t *rdata1, dns_rdata_t *rdata2);
Compares rdata1
and rdata2 as required for DNSSEC
ordering. The routine should
ensure that the type
and class
of the two rdata
match with REQUIRE(rdata1->type == rdata2->type);
and
REQUIRE(rdata1->class == rdata2->class);
statements. The
rdata->type
should also be verified and if the RR type is
class specific the rdata->class.
compare_classname_typename()
returns -1, 0, 1.
Support Functions
The following static support functions are available to use.
static unsigned int
name_length(dns_name_t *name);
-
Returns the length of name
.
static dns_result_t
txt_totext(isc_region_t *source, isc_buffer_t *target);
-
Extracts the octet length tagged text string at the start of
source
and writes it as a quoted string to target
.
source
is adjusted so that it points to first octet after the
text string.
Returns DNS_R_NOSPACE
or DNS_R_SUCCESS
.
static dns_result_t
txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);
-
Take the text region source
and convert it to a length tagged
text string writing it to target
.
Returns DNS_R_NOSPACE
, DNS_R_TEXTTOLONG
or DNS_R_SUCCESS
.
static dns_result_t
txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);
-
Read a octet length tagged text string from source
and
write it to target
.
Ensures that octet length tagged text string was wholly within the active
area of source
.
Adjusts the active area of source
so that it refers to the first
octet after the octet length tagged text string.
Returns DNS_R_UNEXPECTEDEND
, DNS_R_NOSPACE
or
DNS_R_SUCCESS
.
static isc_boolean_t
name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);
-
If origin
is NULL or the root label set target to
refer to name
and return ISC_FALSE
.
Otherwise see if name
is a sub domain of origin
and are not equal.
If so make target
refer to the prefix of name
and
return ISC_TRUE
.
Otherwise make target
refer to name
and return
ISC_FALSE
.
Typical use:
static dns_result_t
totext_typename(dns_rdata_t *rdata, dns_name_t *origin,
isc_buffer_t * target)
{
isc_region_t region;
dns_name_t name, prefix;
isc_boolean_t sub;
dns_name_init(&name, NULL);
dns_name_init(&prefix, NULL);
dns_rdata_toregion(rdata, ®ion);
dns_name_fromregion(&name, ®ion);
sub = name_prefix(&name, origin, &prefix);
return (dns_name_totext(&prefix, sub, target));
}
static dns_result_t
str_totext(char *source, isc_buffer_t *target);
-
This adds the NULL
terminated string source
up to but not including NULL
to target
.
Returns DNS_R_NOSPACE
and DNS_R_SUCCESS
.
static isc_boolean_t
buffer_empty(isc_buffer_t *source);
-
Returns ISC_TRUE
if the active region of source
is
empty otherwise ISC_FALSE
.
static void
buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region,
unsigned int type);
-
Make buffer
refer to the memory in region
and
make it active.
static dns_result_t
uint32_tobuffer(isc_uint32_t value, isc_buffer_t *target);
-
Write the 32 bit value
in network order to target
.
Returns DNS_R_NOSPACE
and DNS_R_SUCCESS
.
static dns_result_t
uint16_tobuffer(isc_uint32_t value, isc_buffer_t *target);
-
Write them 16 bit value
in network order to target
.
Returns ISC_R_RANGE
, DNS_R_NOSPACE
and DNS_R_SUCCESS
.
static isc_uint32_t
uint32_fromregion(isc_region_t *region);
-
Returns the 32 bit at the start of region
in host order.
Requires (region->length >= 4)
.
static isc_uint16_t
uint16_fromregion(isc_region_t *region);
-
Returns the 16 bit at the start of region
in host order.
Requires (region->length >= 2)
.
static dns_result_t
gettoken(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect, isc_boolean_t eol);
-
Gets the next token from the input stream lexer
. Ensure that the
returned token matches expect
(isc_tokentype_qstring can also
return isc_tokentype_string), or isc_tokentype_eol and isc_tokentype_eof if
eol
is ISC_TRUE
.
Returns DNS_R_UNEXPECTED
, DNS_R_UNEXPECTEDEND
,
DNS_R_UNEXPECTEDTOKEN
and DNS_R_SUCCESS
.
static dns_result_t
mem_tobuffer(isc_buffer_t *target, void *base, unsigned int length);
-
Add the memory referred to by base
to target
.
Returns DNS_R_NOSPACE
and DNS_R_SUCCESS
.
static int
compare_region(isc_region_t *r1, isc_region_t *r2)
-
Compares two regions returning -1, 0, 1 based on their DNSSEC ordering.
static int
hexvalue(char value);
-
Returns the hexadecimal value of value
or -1 if not
a hexadecimal character.
static int
decvalue(char value);
-
Returns the decimal value of value
or -1 if not
a decimal character.
static dns_result_t
base64_totext(isc_region_t *source, isc_buffer_t *target);
-
Convert the region referred to by source
to base64 encoded text
and put it into target
.
Returns DNS_R_NOSPACE
or DNS_R_SUCCESS
.
static dns_result_t
base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target,
int length);
-
Read a series of tokens from lexer
that containing base64 data
until one of end of line, length
(length
>= 0)
bytes have been read or base64 pad characters are seen.
If length
< 0 it is ignored otherwise it is an error if there
are not length
octets of data or when processing a token
length
octets would have been exceeded.
Returns DNS_R_BADBASE64
, DNS_R_UNEXPECTED
,
DNS_R_UNEXPECTEDEND
, DNS_R_UNEXPECTEDTOKEN
and DNS_R_SUCCESS
.
static dns_result_t
time_totext(unsigned long value, isc_buffer_t *target);
-
Convert the date represented by value
into YYYYMMDDHHMMSS format
taking into account the active epochs. This code is Y2K and Y2038 compliant.
Returns DNS_R_NOSPACE
and DNS_R_SUCCESS
.
static dns_result_t
time_tobuffer(char *source, isc_buffer_t *target);
-
Take the date in source
and convert it seconds since January 1,
1970 (ignoring leap seconds) and place the least significant 32 bits into
target
.
Returns ISC_R_RANGE
, DNS_R_SYNTAX
,
DNS_R_NOSPACE
and DNS_R_SUCCESS
.
Support Macros
The following macro is available:
RETERR(x)
-
-
Evaluate x
and call return (<value of x>);
if the result is not DNS_R_SUCCESS
.