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);
classREQUIRE(class == #) should be present at the start
of the function.
typeREQUIRE(type == #) statement at
the begining of the function.
lexerorigindowncasetargetBINARY 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);
rdatardata->type and rdata->class for class specific
RR types should be checked at the start of the function with
REQUIRE(rdata->type == #) statements.
originNULL 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.
targetTEXT 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);
classREQUIRE(class == #) should be present at the start
of the function.
typeREQUIRE(type == #) statement at
the begining of the function.
sourceBINARY buffer with the active region
containing a RR record in wire format.
dctxdns_name_fromwire(),
along with downcase, to enable a compressed domain name
to be extracted from the source.
downcasedns_name_fromwire() to say whether the
extracted domainname should be downcased during the extraction.
targetBINARY 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);
rdatardata->type and rdata->class for class specific
RR types should be checked at the start of the function with
REQUIRE(rdata->type == #) statements.
cctxdns_name_towire() when putting domainnames on the wire.
targetBINARY 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);
classREQUIRE(class == #) should be present at the start
of the function.
typeREQUIRE(type == #) statement at
the beginning of the function.
sourcetargetBINARY 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);
rdatardata->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.