[master] some improvements in doc/dev [RT #46011]
- add info about rdatasets, etc, to dev.md (thanks to Tony Finch) - convert rdata.html to markdown
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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(&name, NULL);
|
||||
dns_name_init(&prefix, NULL);
|
||||
dns_rdata_toregion(rdata, &region);
|
||||
dns_name_fromregion(&name, &region);
|
||||
sub = <B>name_prefix</B>(&name, origin, &prefix);
|
||||
return (dns_name_totext(&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> >= 0)
|
||||
bytes have been read or base64 pad characters are seen.
|
||||
If <CODE>length</CODE> < 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><value of x></I>);</CODE> if the result is not <CODE>DNS_R_SUCCESS</CODE>.
|
||||
</DL>
|
||||
</BODY>
|
||||
</HTML>
|
||||
498
doc/dev/rdata.md
Normal file
498
doc/dev/rdata.md
Normal file
@@ -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, ®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 (<value of x>);` if the result is
|
||||
not `ISC_R_SUCCESS`.
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user