]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[master] some improvements in doc/dev [RT #46011]
authorEvan Hunt <each@isc.org>
Thu, 26 Oct 2017 06:30:10 +0000 (23:30 -0700)
committerEvan Hunt <each@isc.org>
Thu, 26 Oct 2017 06:30:10 +0000 (23:30 -0700)
- add info about rdatasets, etc, to dev.md (thanks to Tony Finch)
- convert rdata.html to markdown

doc/dev/dev.md
doc/dev/rdata.html [deleted file]
doc/dev/rdata.md [new file with mode: 0644]
util/copyrights

index 293ea18f1ff69e246b5b282de403001cf793e095..a1e56133a80fe605fce40af5b4c70e23d41ff1bb 100644 (file)
@@ -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.
 
+#### <a name="rdata"></a>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.
+
 #### <a name="iterators"></a>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 (file)
index d4c888a..0000000
+++ /dev/null
@@ -1,608 +0,0 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
-<!--
- - Copyright (C) 1999-2001, 2004, 2007, 2016  Internet Systems Consortium, Inc. ("ISC")
- -
- - This Source Code Form is subject to the terms of the Mozilla Public
- - License, v. 2.0. If a copy of the MPL was not distributed with this
- - file, You can obtain one at http://mozilla.org/MPL/2.0/.
--->
-
-<!-- $Id: rdata.html,v 1.15 2007/06/19 23:47:13 tbox Exp $ -->
-
-<HTML>
-<HEAD>
-  <TITLE>Adding new RDATA type</TITLE>
-</HEAD>
-<BODY>
-<H2>Overview</H2>
-The dns rdata routines (<CODE>dns_rdata_fromtext()</CODE>,
-<CODE>dns_rdata_totext()</CODE>, <CODE>dns_rdata_fromwire()</CODE>,
-<CODE>dns_rdata_towire()</CODE> <CODE>dns_rdata_fromstruct()</CODE>,
-<CODE>dns_rdata_tostruct()</CODE> and <CODE>dns_rdata_compare()</CODE>)
-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.
-<P>
-Each of these generic routines calls type specific routines that provide
-the type specific details.
-<P>
-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.
-<H2>Adding new RDATA types</H2>
-
-Adding a new rdata type requires determining if the new rdata type is class
-specific or generic.
-Writing code to perform the following set of operations
-and then integrating it into the build by placing the code into the rdata
-hierachy at the correct place.
-Running <CODE>make clean</CODE> followed <CODE>make</CODE> in
-<CODE>lib/dns</CODE> will cause the new rdata type to be picked up.
-<P>
-Each rdata module must perform the following operations:
-<DL>
-<DT>Convert from text format to internal format</DT>
-<DT>Convert from internal format to text format</DT>
-<DT>Convert from wire format to internal format</DT>
-<DT>Convert from internal format to wire format</DT>
-<DT>Convert from a structure to internal format</DT>
-<DT>Convert from internal format to a structure</DT>
-<DT>Compare two rdata in internal format<DT>
-</DL>
-<P>
-There is an additional set of support <A HREF="#functions">functions</A> and
-<A HREF="#macros">macros</A> only available to
-to rdata code.
-<H2>RDATA Hierarchy</H2>
-The <CODE>rdata</CODE> hierarchy has the following format.
-<PRE>
-       rdata/
-               generic/
-                       <I>typename_typenumber</I>.h
-               <I>classname_classnumber</I>/
-                       <I>typename_typenumber</I>.h
-<PRE>
-<P>
-Initial rdata hierarchy:
-<P>
-<PRE>
-       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
-</PRE>
-
-<H2>CLASSNAME and TYPENAME</H2>
-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.
-
-<H2>Internal Format</H2>
-The internal format chosen is DNS wire format without any compression being
-applied to domain names in the rdata.
-
-<H2>Convert from text format to internal format</H2>
-The functions to convert from text format has the following call formats and
-is declared as follows for class generic functions.
-<PRE>
-<CODE>static dns_result_t
-fromtext_<I>typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                 isc_lex_t *lexer, dns_name_t *origin,
-                 isc_boolean_t downcase, isc_buffer_t *target);</CODE>
-</PRE>
-Class specific functions contain the class name in addition to the
-type name.
-<PRE>
-<CODE>static dns_result_t
-fromtext_<I>classname_typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                          isc_lex_t *lexer, dns_name_t *origin,
-                          isc_boolean_t downcase, isc_buffer_t *target);</CODE>
-</PRE>
-
-<DL>
-<DT><CODE>class</CODE></DT>
-<DD>
-This argument should be ignored when used with a class generic RR type
-otherwise <CODE>REQUIRE(class == #)</CODE> should be present at the start
-of the function.
-<DT><CODE>type</CODE></DT>
-<DD>
-This should be tested with a <CODE>REQUIRE(type == #)</CODE> statement at
-the begining of the function.
-<DT><CODE>lexer</CODE></DT>
-<DD>
-This is used to read the input text stream.
-<DT><CODE>origin</CODE></DT>
-<DD>
-This is a absolute name used to qualify unqualified / partially qualified
-domainnames in the text stream.
-It is passed to the name parsing routines.
-<DT><CODE>downcase</CODE></DT>
-<DD>
-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 pesented in.
-<DT><CODE>target</CODE></DT>
-<DD>
-This is a <CODE>BINARY</CODE> buffer used to write the internal format of the rdata record being read in to.
-</DL>
-
-<CODE>fromtext_<I>typename</I>()</CODE> reads tokens from <CODE>lexer</CODE>,
-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.
-<A HREF="#gettoken"><CODE>gettoken()</CODE></A>
-should be used to read the next token from the input stream and
-will return EOL / EOF tokens
-automatically unless
-they are specifcally requested.
-<CODE>isc_lex_ungettoken()</CODE> 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 <CODE>dns_rdata_fromtext()</CODE> to return
-<CODE>DNS_R_EXTRATOKEN</CODE> if <CODE>fromtext_<I>typename</I>()</CODE> was successful.
-<P>
-<CODE>fromtext_<I>typename</I>()</CODE> reads external input and as such is a high security area and must be paranoid about its input.
-<H2>Convert from internal format to text format</H2>
-<PRE>
-<CODE>static dns_result_t
-totext_<I>typename</I>(dns_rdata_t *rdata, dns_name_t *origin,
-               isc_buffer_t *target);</CODE>
-</PRE>
-<PRE>
-<CODE>static dns_result_t
-totext_<I>classname_typename</I>(dns_rdata_t *rdata, dns_name_t *origin,
-                         isc_buffer_t *target);</CODE>
-</PRE>
-<DL>
-<DT><CODE>rdata</CODE></DT>
-<DD>
-This is the rdata record to be converted from internal format to text.
-<CODE>rdata->type</CODE> and <CODE>rdata->class</CODE> for class specific
-RR types should be checked at the start of the function with
-<CODE>REQUIRE(rdata->type == #)</CODE> statements.
-<DT><CODE>origin</CODE></DT>
-<DD>
-If this in non <CODE>NULL</CODE> then any domainnames with this suffix
-should be written out unqualified.
-<A HREF="#name_prefix"><CODE>name_prefix()</CODE></A> can be used to
-check if <CODE>origin</CODE> is <CODE>NULL</CODE> and provide the correct
-arguments to the name conversion routines.
-<DT><CODE>target</CODE></DT>
-<DD>
-This is a <CODE>TEXT</CODE> buffer used to hold the output.
-</DL>
-<H2>Convert from wire format to internal format</H2>
-<PRE>
-<CODE>static dns_result_t
-fromwire_<I>typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                  isc_buffer_t *source, dns_decompress_t *dctx,
-                 isc_boolean_t downcase, isc_buffer_t *target);</CODE>
-</PRE>
-<PRE>
-<CODE>static dns_result_t
-fromwire_<I>classname_typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                           isc_buffer_t *source, dns_decompress_t *dctx,
-                           isc_boolean_t downcase, isc_buffer_t *target);</CODE>
-</PRE>
-<P>
-<CODE>fromwire_<I>classname_typename</I>()</CODE> is required to set the valid
-decompression methods if there is a domain name in the rdata.
-<PRE>
-<CODE>if (dns_decompress_edns(dctx) >= # || !dns_decompress_strict(dctx))
-       dns_decompress_setmethods(dctx, DNS_COMPRESS_ALL);
-else
-       dns_decompress_setmethods(dctx, DNS_COMPRESS_GLOBAL14);</CODE>
-</PRE>
-
-<DL>
-<DT><CODE>class</CODE></DT>
-<DD>
-This argument should be ignored when used with a class generic RR type
-otherwise <CODE>REQUIRE(class == #)</CODE> should be present at the start
-of the function.
-<DT><CODE>type</CODE></DT>
-<DD>
-This should be tested with a <CODE>REQUIRE(type == #)</CODE> statement at
-the begining of the function.
-<DT><CODE>source</CODE></DT>
-<DD>
-This is a <CODE>BINARY</CODE> buffer with the <CODE>active</CODE> region
-containing a RR record in wire format.
-<DT><CODE>dctx</CODE></DT>
-<DD>
-This is the decompression context and is passed to
-<CODE>dns_name_fromwire()</CODE>,
-along with <CODE>downcase</CODE>, to enable a compressed domain name
-to be extracted from the source.
-<DT><CODE>downcase</CODE></DT>
-<DD>
-This is passed to <CODE>dns_name_fromwire()</CODE> to say whether the
-extracted domainname should be downcased during the extraction.
-<DT><CODE>target</CODE></DT>
-<DD>
-This is a <CODE>BINARY</CODE> buffer where the decompressed and checked
-RR record is written.
-</DL>
-<CODE>fromwire_<I>typename</I>()</CODE> is a security sensitive routine
-as it reads external data and should take extreme care to ensure that
-the input data matches its description.
-<P>
-If the <CODE>active</CODE> buffer is not empty at completion and
-<CODE>fromwire_<I>typename</I>()</CODE> was otherwise successful
-<CODE>dns_rdata_fromwire()</CODE> will return <CODE>DNS_R_EXTRADATA</CODE>.
-<H2>Convert from internal format to wire format</H2>
-<PRE>
-<CODE>static dns_result_t
-towire_<I>typename</I>(dns_rdata_t *rdata, dns_compress_t *cctx,
-                isc_buffer_t *target);</CODE>
-</PRE>
-<PRE>
-<CODE>static dns_result_t
-towire_<I>classname_typename</I>(dns_rdata_t *rdata, dns_compress_t *cctx,
-                          isc_buffer_t *target);<CODE>
-</PRE>
-<P>
-<CODE>towire_<I>classname_typename</I>()</CODE> is required to set the
-allowed name compression methods based on EDNS version if there is a
-domain name in the rdata.
-<PRE>
-<CODE>if (dns_compress_getedns(cctx) >= #)
-       dns_compress_setmethods(cctx, DNS_COMPRESS_ALL);
-else
-       dns_compress_setmethods(cctx, DNS_COMPRESS_GLOBAL14);</CODE>
-</PRE>
-<DL>
-<DT><CODE>rdata</CODE></DT>
-<DD>
-This is the rdata record to be converted from internal format to text.
-<CODE>rdata->type</CODE> and <CODE>rdata->class</CODE> for class specific
-RR types should be checked at the start of the function with
-<CODE>REQUIRE(rdata->type == #)</CODE> statements.
-<DT><CODE>cctx</CODE></DT>
-<DD>
-This is the compression context, it should be passed to <CODE>dns_name_towire()</CODE> when putting domainnames on the wire.
-<DT><CODE>target</CODE></DT>
-<DD>
-This is a <CODE>BINARY</CODE> buffer used to write the rdata to.
-</DL>
-Simple RR types without domainnames can use the following code to
-transfer the contents of the <CODE>rdata</CODE> to the target buffer.
-<PRE>
-       <CODE>return (<A HREF="#mem_tobuffer">mem_tobuffer</A>(target, rdata->data, rdata->length));</CODE>
-</PRE>
-<H2>Convert from a structure to internal format</H2>
-<PRE>
-<CODE>static dns_result_t
-fromstruct_<I>typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                   void *source, isc_buffer_t *target);</CODE>
-</PRE>
-<PRE>
-<CODE>static dns_result_t
-fromstruct_<I>classname_typename</I>(dns_rdataclass_t class, dns_rdatatype_t type,
-                             void *source, isc_buffer_t *target);</CODE>
-</PRE>
-<DL>
-<DT><CODE>class</CODE></DT>
-<DD>
-This argument should be ignored when used with a class generic RR type
-otherwise <CODE>REQUIRE(class == #)</CODE> should be present at the start
-of the function.
-<DT><CODE>type</CODE></DT>
-<DD>
-This should be tested with a <CODE>REQUIRE(type == #)</CODE> statement at
-the beginning of the function.
-<DT><CODE>source</CODE></DT>
-<DD>
-This points to a type specific structure.
-<DT><CODE>target</CODE></DT>
-<DD>
-This is a <CODE>BINARY</CODE> buffer used to write the internal format of the rdata record being read in to.
-</DL>
-<H2>Convert from internal format to a structure</H2>
-<PRE>
-<CODE>static dns_result_t
-tostruct_<I>typename</I>(dns_rdata_t *rdata, void *target);</CODE>
-</PRE>
-<PRE>
-<CODE>static dns_result_t
-tostruct_<I>classname_typename</I>(dns_rdata_t *rdata, void *target);</CODE>
-</PRE>
-<DL>
-<DT><CODE>rdata</CODE></DT>
-<DD>
-This is the rdata record to be converted from internal format to a structure.
-<CODE>rdata->type</CODE> and <CODE>rdata->class</CODE> for class specific
-RR types should be checked at the start of the function with
-<CODE>REQUIRE(rdata->type == #)</CODE> statements.
-<DT><CODE>target</CODE></DT>
-<DD>
-Pointer to a type specific structure.
-</DL>
-<H2>Compare two rdata in internal format</H2>
-<PRE>
-<CODE>static int
-compare_<I>typename</I>(dns_rdata_t *rdata1, dns_rdata_t *rdata2);</CODE>
-</PRE>
-<PRE>
-<CODE>static int
-compare_<I>classname_typename</I>(dns_rdata_t *rdata1, dns_rdata_t *rdata2);</CODE>
-</PRE>
-Compares <CODE>rdata1</CODE> and <CODE>rdata2<CODE> as required for DNSSEC
-ordering.  The routine should
-ensure that the <CODE>type</CODE> and <CODE>class</CODE> of the two rdata
-match with <CODE>REQUIRE(rdata1->type == rdata2->type);</CODE> and
-<CODE>REQUIRE(rdata1->class == rdata2->class);</CODE> statements. The
-<CODE>rdata->type</CODE> should also be verified and if the RR type is
-class specific the <CODE>rdata->class</CLASS>.
-<P>
-<CODE>compare_<I>classname_typename</I>()</CODE> returns -1, 0, 1.
-<H2><A NAME="functions">Support Functions</A></H2>
-The following static support functions are available to use.
-<DL>
-<DT><CODE>static unsigned int<BR>
-name_length(dns_name_t *name);</CODE></DT>
-<DD>
-<P>
-Returns the length of <CODE>name</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-txt_totext(isc_region_t *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Extracts the octet length tagged text string at the start of
-<CODE>source</CODE> and writes it as a quoted string to <CODE>target</CODE>.
-<CODE>source</CODE> is adjusted so that it points to first octet after the
-text string.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> or <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-txt_fromtext(isc_textregion_t *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Take the text region <CODE>source</CODE> and convert it to a length tagged
-text string writing it to <CODE>target</CODE>.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE>, <CODE>DNS_R_TEXTTOLONG</CODE>
-or <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-txt_fromwire(isc_buffer_t *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Read a octet length tagged text string from <CODE>source</CODE> and
-write it to <CODE>target</CODE>.
-Ensures that octet length tagged text string was wholly within the active
-area of <CODE>source</CODE>.
-Adjusts the active area of <CODE>source</CODE> so that it refers to the first
-octet after the octet length tagged text string.
-<P>
-Returns <CODE>DNS_R_UNEXPECTEDEND</CODE>, <CODE>DNS_R_NOSPACE</CODE> or
-<CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><A NAME="name_prefix"><CODE>static isc_boolean_t<BR>
-name_prefix(dns_name_t *name, dns_name_t *origin, dns_name_t *target);</CODE>
-</A></DT>
-<DD>
-<P>
-If <CODE>origin</CODE> is NULL or the root label set <CODE>target<CODE> to
-refer to <CODE>name</CODE> and return <CODE>ISC_FALSE</CODE>.
-Otherwise see if <CODE>name</CODE> is a sub domain of <CODE>origin</CODE>
-and are not equal.
-If so make <CODE>target</CODE> refer to the prefix of <CODE>name</CODE> and
-return <CODE>ISC_TRUE</CODE>.
-Otherwise make <CODE>target</CODE> refer to <CODE>name</CODE> and return
-<CODE>ISC_FALSE</CODE>.
-<P>
-Typical use:
-<PRE><CODE>
-static dns_result_t
-totext_<I>typename</I>(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(&amp;name, NULL);
-       dns_name_init(&amp;prefix, NULL);
-       dns_rdata_toregion(rdata, &amp;region);
-       dns_name_fromregion(&amp;name, &amp;region);
-       sub = <B>name_prefix</B>(&amp;name, origin, &amp;prefix);
-       return (dns_name_totext(&amp;prefix, sub, target));
-}
-</CODE></PRE>
-<DT><CODE>static dns_result_t<BR>
-str_totext(char *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-This adds the <CODE>NULL</CODE> terminated string <CODE>source</CODE>
-up to but not including <CODE>NULL</CODE> to <CODE>target</CODE>.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static isc_boolean_t<BR>
-buffer_empty(isc_buffer_t *source);</CODE></DT>
-<DD>
-<P>
-Returns <CODE>ISC_TRUE</CODE> if the active region of <CODE>source</CODE> is
-empty otherwise <CODE>ISC_FALSE</CODE>.
-<P>
-<DT><CODE>static void<BR>
-buffer_fromregion(isc_buffer_t *buffer, isc_region_t *region,
-unsigned int type);</CODE></DT>
-<DD>
-<P>
-Make <CODE>buffer</CODE> refer to the memory in <CODE>region</CODE> and
-make it active.
-<P>
-<DT><CODE>static dns_result_t<BR>
-uint32_tobuffer(isc_uint32_t value, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Write the 32 bit <CODE>value</CODE> in network order to <CODE>target</CODE>.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-uint16_tobuffer(isc_uint32_t value, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Write them 16 bit <CODE>value</CODE> in network order to <CODE>target</CODE>.
-<P>
-Returns <CODE>ISC_R_RANGE</CODE>, <CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static isc_uint32_t<BR>
-uint32_fromregion(isc_region_t *region);</CODE></DT>
-<DD>
-<P>
-Returns the 32 bit at the start of <CODE>region</CODE> in host order.
-<P>
-Requires <CODE>(region->length >= 4)</CODE>.
-<P>
-<DT><CODE>static isc_uint16_t<BR>
-uint16_fromregion(isc_region_t *region);</CODE></DT>
-<DD>
-<P>
-Returns the 16 bit at the start of <CODE>region</CODE> in host order.
-<P>
-Requires <CODE>(region->length >= 2)</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-<A NAME="gettoken">gettoken</A>(isc_lex_t *lexer, isc_token_t *token, isc_tokentype_t expect, isc_boolean_t eol);</CODE></DT>
-<DD>
-<P>
-Gets the next token from the input stream <CODE>lexer</CODE>. Ensure that the
-returned token matches <CODE>expect</CODE> (isc_tokentype_qstring can also
-return isc_tokentype_string), or isc_tokentype_eol and isc_tokentype_eof if
-<CODE>eol</CODE> is <CODE>ISC_TRUE</CODE>.
-<P>
-Returns <CODE>DNS_R_UNEXPECTED</CODE>, <CODE>DNS_R_UNEXPECTEDEND</CODE>,
-<CODE>DNS_R_UNEXPECTEDTOKEN</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-</DT>
-<DT><CODE>static dns_result_t<BR>
-<A NAME="mem_tobuffer">mem_tobuffer</A>(isc_buffer_t *target, void *base, unsigned int length);</CODE></DT>
-<DD>
-<P>
-Add the memory referred to by <CODE>base</CODE> to <CODE>target</CODE>.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static int<BR>
-compare_region(isc_region_t *r1, isc_region_t *r2)</CODE></DT>
-<DD>
-<P>
-Compares two regions returning -1, 0, 1 based on their DNSSEC ordering.
-<P>
-<DT><CODE>static int<BR>
-hexvalue(char value);</CODE></DT>
-<DD>
-<P>
-Returns the hexadecimal value of <CODE>value</CODE> or -1 if not
-a hexadecimal character.
-<P>
-<DT><CODE>static int<BR>
-decvalue(char value);</CODE></DT>
-<DD>
-<P>
-Returns the decimal value of <CODE>value</CODE> or -1 if not
-a decimal character.
-<P>
-<DT><CODE>static dns_result_t<BR>
-base64_totext(isc_region_t *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Convert the region referred to by <CODE>source</CODE> to base64 encoded text
-and put it into <CODE>target</CODE>.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> or <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-base64_tobuffer(isc_lex_t *lexer, isc_buffer_t *target,
-int length);</CODE></DT>
-<DD>
-<P>
-Read a series of tokens from <CODE>lexer</CODE> that containing base64 data
-until one of end of line, <CODE>length</CODE> (<CODE>length</CODE> &gt;= 0)
-bytes have been read or base64 pad characters are seen.
-If <CODE>length</CODE> &lt; 0 it is ignored otherwise it is an error if there
-are not <CODE>length</CODE> octets of data or when processing a token
-<CODE>length</CODE> octets would have been exceeded.
-<P>
-Returns <CODE>DNS_R_BADBASE64</CODE>, <CODE>DNS_R_UNEXPECTED</CODE>,
-<CODE>DNS_R_UNEXPECTEDEND</CODE>, <CODE>DNS_R_UNEXPECTEDTOKEN</CODE>
-and <CODE>DNS_R_SUCCESS</CODE>.
-<P>
-<DT><CODE>static dns_result_t<BR>
-time_totext(unsigned long value, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Convert the date represented by <CODE>value</CODE> into YYYYMMDDHHMMSS format
-taking into account the active epochs. This code is Y2K and Y2038 compliant.
-<P>
-Returns <CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-<DT><CODE>static dns_result_t<BR>
-time_tobuffer(char *source, isc_buffer_t *target);</CODE></DT>
-<DD>
-<P>
-Take the date in <CODE>source</CODE> and convert it seconds since January 1,
-1970 (ignoring leap seconds) and place the least significant 32 bits into
-<CODE>target</CODE>.
-<P>
-Returns <CODE>ISC_R_RANGE</CODE>, <CODE>DNS_R_SYNTAX</CODE>,
-<CODE>DNS_R_NOSPACE</CODE> and <CODE>DNS_R_SUCCESS</CODE>.
-</DL>
-<H2><A NAME="macros">Support Macros<A></H2>
-The following macro is available:
-<DL>
-<DT><CODE>RETERR(x)</CODE><DT>
-<DD>
-<P>
-Evaluate <CODE>x</CODE> and call <CODE>return (<I>&lt;value of x&gt;</I>);</CODE> if the result is not <CODE>DNS_R_SUCCESS</CODE>.
-</DL>
-</BODY>
-</HTML>
diff --git a/doc/dev/rdata.md b/doc/dev/rdata.md
new file mode 100644 (file)
index 0000000..4107499
--- /dev/null
@@ -0,0 +1,498 @@
+<!--
+ - Copyright (C) 1999-2001, 2004, 2007, 2016, 2017 Internet Systems Consortium, Inc. ("ISC")
+ -
+ - This Source Code Form is subject to the terms of the Mozilla Public
+ - License, v. 2.0. If a copy of the MPL was not distributed with this
+ - file, You can obtain one at http://mozilla.org/MPL/2.0/.
+-->
+
+## 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 == <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`.
index 96834d25f0032fcb4cd149495c96aa336238d7c8..2aec81b3440b1edc34e41bea4eb7344d0e6025b6 100644 (file)
 ./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