diff --git a/doc/dev/dev.md b/doc/dev/dev.md index 293ea18f1f..a1e56133a8 100644 --- a/doc/dev/dev.md +++ b/doc/dev/dev.md @@ -22,6 +22,7 @@ * [Lists](#lists) * [Buffers and regions](#buffers) * [Names](#names) + * [Rdata Classes](#rdata) * [Iterators](#iterators) * [Logging](#logging) * [Adding a new RR type](#rrtype) @@ -875,6 +876,38 @@ name. This allows names to be stack-allocated with minimal initialization: stored for the duration of this function; there is no need to initialize, allocate, or free memory. +#### Rdata Classes + +##### Rdataset + +An rdataset (`dns_rdataset_t`) is BIND's representation of a DNS RRset, +excluding the owner name but including the type, TTL, and the contents of +each RR. The rdataset object does not hold the data itself: it is a view +that refers to data held elsewhere -- for example, in a DNS message, or in +an rbtdb (for cached or authoritative data). + +It is a vaguely object-oriented polymorphic data structure, with different +implementations depending on the backing data structure that actually holds +the records. The rdataset is explicitly associated/disassociated with the +backing data structure so that it can maintain reference counts. + +One important rdataset implementation is part of the red-black tree +database, implemented in `rdata.c`. + +##### Rdatalist + +Another backing data structure for an rdataset is the rdatalist +(`dns_rdatalist_t`) -- a linked list of rdata structures. An rdatalist is +used to record the locations of records in a DNS message. It does not +maintain reference counts. An rdatalist can be converted to or from an +rdataset using `dns_rdatalist_tordataset()` and +`dns_rdatalist_fromrdataset()`. + +##### Rdata + +See the [RRATA Types](rdata.md) document for details on type-specific +rdata conversions. + #### Iterators Retrieving data from BIND databases involves the use of iterator diff --git a/doc/dev/rdata.html b/doc/dev/rdata.html deleted file mode 100644 index d4c888a895..0000000000 --- a/doc/dev/rdata.html +++ /dev/null @@ -1,608 +0,0 @@ - - - - - - -
-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.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. - -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.
-
-
-
diff --git a/doc/dev/rdata.md b/doc/dev/rdata.md
new file mode 100644
index 0000000000..41074992ef
--- /dev/null
+++ b/doc/dev/rdata.md
@@ -0,0 +1,498 @@
+
+
+## RDATA Types
+
+### Overview
+
+The dns rdata routines (`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, in which there were multiple places in the
+code base that decoded wire format to internal format or compared rdata,
+sometimes with subtly different behaviour (bugs), and sometimes failing to
+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.
+
+### Adding new RDATA types
+
+Adding a new rdata type requires determining whether the new rdata type is
+class-specific or generic, writing code to perform the rdata operations for the
+type, then integrating it into the build by placing the code into the rdata
+hierachy at the correct location under `lib/dns/rdata`. Running `make clean`
+followed by `make` in `lib/dns` will cause the new rdata type to be picked up
+and compiled.
+
+Each rdata module must perform the following operations:
+
+* Convert from text format to internal format
+* Convert from internal format to text format
+* Convert from wire format to internal format
+* Convert from internal format to wire format
+* Convert from a structure to internal format
+* Convert from internal format to a structure
+* Compare two rdata in internal format
+
+There is an additional set of support functions and macros only available to
+rdata code.
+
+#### RDATA Hierarchy
+
+The `rdata` hierarchy has the following format.
+
+ rdata/
+ generic/
+ typename_typenumber.h
+ classname_classnumber/
+ 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 == )` should be present at the start of the function.|
+|`type`|This should be tested with a `REQUIRE(type == )` 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 == )` should be present at the start of the function.|
+|`type`|This should be tested with a `REQUIRE(type == )` 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 == )` should be present at the start of the function.|
+|`type`|This should be tested with a `REQUIRE(type == )` 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, ®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);
+
+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 ();` if the result is
+not `ISC_R_SUCCESS`.
diff --git a/util/copyrights b/util/copyrights
index 96834d25f0..2aec81b344 100644
--- a/util/copyrights
+++ b/util/copyrights
@@ -3126,7 +3126,7 @@
./doc/dev/cvs-usage TXT.BRIEF 2000,2001,2004,2016
./doc/dev/dev.md MKD 2017
./doc/dev/magic_numbers TXT.BRIEF 1999,2000,2001,2002,2004,2016
-./doc/dev/rdata.html HTML 1999,2000,2001,2004,2007,2016
+./doc/dev/rdata.md MKD 1999,2000,2001,2004,2007,2016,2017
./doc/dev/release TXT.BRIEF 2000,2001,2002,2003,2004,2005,2006,2007,2009,2014,2016
./doc/dev/results TXT.BRIEF 1999,2000,2001,2004,2016
./doc/dev/style.md MKD 2017