rdata.md revision 8e24455c8f0f4b4118b908c3d8ffda923d850e3e
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync<!--
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync - Copyright (C) 1999-2001, 2004, 2007, 2016, 2017 Internet Systems Consortium, Inc. ("ISC")
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync -
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync - This Source Code Form is subject to the terms of the Mozilla Public
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync - License, v. 2.0. If a copy of the MPL was not distributed with this
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync - file, You can obtain one at http://mozilla.org/MPL/2.0/.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync-->
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync## RDATA Types
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync### Overview
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncThe dns rdata routines (`dns_rdata_fromtext()`,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync`dns_rdata_totext()`, `dns_rdata_fromwire()`,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync`dns_rdata_towire()` `dns_rdata_fromstruct()`,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync`dns_rdata_tostruct()` and `dns_rdata_compare()`)
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncare designed to provide a single set of routines
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncfor encoding, decoding and comparing dns data preventing the problems that
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncoccurred in BIND 8.x and earlier, in which there were multiple places in the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynccode base that decoded wire format to internal format or compared rdata,
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncsometimes with subtly different behaviour (bugs), and sometimes failing to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncsupport a particular type, leading to internal inconsistancy.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEach of these generic routines calls type-specific routines that provide
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncthe type-specific details.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncFrom time to time new types are defined and it is necessary to add these types
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncinto the existing structure. This document is written to provide instruction
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncon how to do this.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync### Adding new RDATA types
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncAdding a new rdata type requires determining whether the new rdata type is
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncclass-specific or generic, writing code to perform the rdata operations for the
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynctype, then integrating it into the build by placing the code into the rdata
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsynchierachy at the correct location under `lib/dns/rdata`. Running `make clean`
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncfollowed by `make` in `lib/dns` will cause the new rdata type to be picked up
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncand compiled.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncEach rdata module must perform the following operations:
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from text format to internal format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from internal format to text format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from wire format to internal format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from internal format to wire format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from a structure to internal format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Convert from internal format to a structure
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync* Compare two rdata in internal format
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncThere is an additional set of support functions and macros only available to
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncrdata code.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync#### RDATA Hierarchy
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsyncThe `rdata` hierarchy has the following format.
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync rdata/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync generic/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync typename_typenumber.h
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync classname_classnumber/
4fd606d1f5abe38e1f42c38de1d2e895166bd0f4vboxsync typename_typenumber.h
Initial 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.h
#### CLASSNAME 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.
#### Converting 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.
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);
Class specific functions contain the class name in addition to the
type name.
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);
|Parameter|Description |
|---------|-----------------------|
|`class`|This argument should be ignored when used with a class-generic RR type, otherwise `REQUIRE(class == <value>)` should be present at the start of the function.|
|`type`|This should be tested with a `REQUIRE(type == <value>)` statement at the begining of the function.|
|`lexer`|This is used to read the input text stream.|
|`origin`|This is a absolute name used to qualify unqualified / partially qualified domain names in the text stream. It is passed to the name parsing routines.|
|`downcase`|This is passed to the name parsing routines to determine whether to downcase the names it generates or leave them in the case they are presented in.|
|`target`|This is a `BINARY` buffer into which to write the internal format of the rdata record being read.|
`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.
`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.
#### Converting from internal format to text format
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);
|Parameter|Description |
|---------|-----------------------|
|`rdata`|This is the rdata record to be converted from internal format to text. `rdata->type` (and `rdata->class` for class-specific RR types) should be checked at the start of the function with `REQUIRE` statements.|
|`origin`|If this is not `NULL`, then any domain names with this suffix should be written out as unqualified subdomains. `name_prefix()` can be used to check whether `origin` is `NULL` and provide the correct arguments to the name conversion routines.|
|`target`|This is a `TEXT` buffer into which to write the output.|
#### Converting from wire format to internal format
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);
|Parameter|Description |
|---------|-----------------------|
|`class`|This argument should be ignored when used with a class-generic RR type otherwise `REQUIRE(class == <value>)` should be present at the start of the function.|
|`type`|This should be tested with a `REQUIRE(type == <value>)` statement at the begining of the function.|
|`source`|This is a `BINARY` buffer with the `active` region containing a resource record in wire format.|
|`dctx`|This is the decompression context and is passed to `dns_name_fromwire()`, along with `downcase`, to enable a compressed domain name to be extracted from the source.|
|`downcase`|This is passed to `dns_name_fromwire()` to say whether the extracted domain name should be downcased during the extraction.|
|`target`|This is a `BINARY` buffer into which the decompressed and checked resource 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`.
#### Converting from internal format to wire format
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 the 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);
|Parameter|Description |
|---------|-----------------------|
|`rdata`|This is the rdata record to be converted from internal format to text. `rdata->type` (and `rdata->class` for class-specific RR types) should be checked at the start of the function with `REQUIRE` statements.|
|`cctx`|This is the compression context. It should be passed to `dns_name_towire()` when putting domain names on the wire.|
|`target`|This is a `BINARY` buffer into which to write the rdata|
Simple RR types without domain names can use the following code to
transfer the contents of the `rdata` to the target buffer.
return (mem_tobuffer(target, rdata->data, rdata->length));
#### Converting from a structure to internal format
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);
|Parameter|Description |
|---------|-----------------------|
|`class`|This argument should be ignored when used with a class-generic RR type otherwise `REQUIRE(class == <value>)` should be present at the start of the function.|
|`type`|This should be tested with a `REQUIRE(type == <value>)` statement at the beginning of the function.|
|`source`|This points to a type-specific structure.|
|`target`|This is a `BINARY` buffer into which to write the internal format of the rdata record being read in.|
#### Converting from internal format to a structure
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);
|Parameter|Description |
|---------|-----------------------|
|`rdata`|This is the rdata record to be converted from internal format to a structure. `rdata->type` (and `rdata->class` for class-specific RR types) should be checked at the start of the function with `REQUIRE` statements.|
|`target`|Pointer to a type-specific structure.|
#### Comparing two rdata in internal format
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);
This function 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, also 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 an 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 subdomain of `origin` and
not equal to it. 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, &region);
dns_name_fromregion(&name, &region);
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);
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 byte 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 byte 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`. Ensures 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 if 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 to 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 `ISC_R_SUCCESS`.