1OVERVIEW:
2
3DLZ (Dynamically Loadable Zones) is an extension to BIND 9 that
4allows zone data to be retrieved directly from an external database.
5There is no required format or schema.  DLZ drivers exist for several
6different database backends including PostgreSQL, MySQL, and LDAP and
7can be written for any other.
8
9Historically, DLZ drivers had to be statically linked with the named
10binary and were turned on via a configure option at compile time (for
11example, "configure --with-dlz-ldap").  Currently, the drivers provided
12in the BIND 9 tarball in contrib/dlz/drivers are still linked this way.
13
14However, as of BIND 9.8, it is also possible to link some DLZ modules
15dynamically at runtime, via the DLZ "dlopen" driver, which acts as a
16generic wrapper around a shared object that implements the DLZ API.  The
17"dlopen" driver is linked into named by default, so configure options are
18no longer necessary unless using older DLZ drivers.
19
20When the DLZ module provides data to named, it does so in text format.
21The response is converted to DNS wire format by named.  This conversion,
22and the lack of any internal caching, places significant limits on the
23query performance of DLZ modules.  Consequently, DLZ is not recommended
24for use on high-volume servers.  However, it can be used in a hidden
25master configuration, with slaves retrieving zone updates via AXFR.
26(Note, however, that DLZ has no built-in support for DNS notify; slaves
27are not automatically informed of changes to the zones in the database.)
28
29CONFIGURING DLZ:
30
31A DLZ database is configured with a "dlz" statement in named.conf.
32
33    dlz example {
34        database "dlopen driver.so <args>";
35        search yes;
36    };
37
38This specifies a DLZ module to search when answering queries; the module
39is implemented in "driver.so" and is loaded at runtime by the dlopen DLZ
40driver.  Multiple "dlz" statements can be specified; when answering a
41query, all DLZ modules with the "search" option set to "yes" will be
42checked for an answer, and the best available answer will be returned
43to the client.
44
45The "search" option in this example can be omitted, as "yes" is the
46default value.  If it is set to "no", then this DLZ module is *not*
47searched for best-match when a query is received.  Instead, zones in
48this DLZ must be separately specified in a zone statement.  This can
49be useful when conventional zone semantics are desired but you wish
50to use a different back-end storage mechanism than the standard zone
51database.  For example, to use a DLZ module for an NXDOMAIN redirection
52zone:
53
54    dlz other {
55        database "dlopen driver.so <args>";
56        search no;
57    };
58
59    zone "." {
60        type redirect;
61        dlz other;
62    };
63
64EXAMPLE DRIVER:
65
66This directory contains an example of an externally-lodable DLZ module,
67dlz_example.c, which demonstrates the features of the DLZ API.  It sets up
68a single zone, whose name is configured in named.conf.  The zone can answer
69queries and AXFR requests, and accept DDNS updates.
70
71By default, at runtime, the zone implemented by this driver will contain
72an SOA, NS, and a single A record at the apex.  If configured in named.conf
73to use the name "example.nil", then, the zone will look like this:
74
75 example.nil.  3600    IN      SOA     example.nil. hostmaster.example.nil. (
76                                               123 900 600 86400 3600
77                                       )
78 example.nil.  3600    IN      NS      example.nil.
79 example.nil.  1800    IN      A       10.53.0.1
80
81The driver is also capable of retrieving information about the querying
82client, and altering its response on the basis of this information.  To
83demonstrate this feature, the example driver responds to queries for
84"source-addr.<zonename>/TXT" with the source address of the query.
85Note, however, that this record will *not* be included in AXFR or ANY
86responses.  (Normally, this feature would be used to alter responses in
87some other fashion, e.g., by providing different address records for
88a particular name depending on the network from which the query arrived.)
89
90DYNAMIC UPDATES AND TRANSACTIONS:
91
92If a DLZ module wants to implement dynamic DNS updates (DDNS), the
93normal calling sequence is
94 - dlz_newversion (start a 'transaction')
95 - dlz_addrdataset (add records)
96 - dlz_subrdataset (remove records)
97 - dlz_closeversion (end a 'transaction')
98
99However, BIND may also query the database during the transaction
100(e.g., to check prerequisites), and your DLZ might need to know whether
101the lookup is against the pre-existing data, or the new data.
102dlz_lookup() doesn't give you access to the 'versionp' pointer
103directly, so it must be passed via 'clientinfo' structure if
104it is needed.
105
106The dlz_example.c code has sample code to show how to get the 'versionp'
107pointer from within dlz_lookup(). If it's set to NULL, we query
108the standard database; if non-NULL, we query against the in-flight
109data within the appropriate uncommitted transaction.
110
111IMPLEMENTATION NOTES:
112
113The minimal set of type definitions, prototypes, and macros needed
114for implementing a DLZ driver is in ../modules/dlz_minimal.h.  Copy this
115header file into your source tree when creating an external DLZ module.
116
117The DLZ dlopen driver provides a set of callback functions:
118
119  - void log(int level, const char *fmt, ...);
120
121    Writes the specified string to the named log, at the specified
122    log level.  Uses printf() format semantics.
123
124  - isc_result_t putrr(dns_sdlzlookup_t *lookup, const char *type,
125                       dns_ttl_t ttl, const char *data);
126
127    Puts a DNS resource record into the query response, which
128    referenced by the opaque structure 'lookup' provided by named.
129
130  - isc_result_t putnamedrr(dns_sdlzallnotes_t *allnodes,
131                            const char *name, const char *type,
132                            dns_ttl_t ttl, const char *data);
133
134    Puts a DNS resource record into an AXFR response, which is
135    referenced by the opaque structure 'allnodes' provided by named.
136
137  - isc_result_t writeable_zone(dns_view_t *view, const char *zone_name);
138
139    Allows the DLZ module to inform named that a given zone can receive
140    DDNS updates.  (Note: This is not currently supported for DLZ
141    databases that are configured as 'search no;')
142
143The external DLZ module can define the following functions (some of these
144are mandatory, others optional).
145
146  - int dlz_version(unsigned int *flags);
147
148    Required for alL external DLZ modules, to indicate the version number
149    of the DLZ dlopen driver that this module supports.  It should return
150    the value DLZ_DLOPEN_VERSION, which is defined in the file
151    contrib/dlz/modules/dlz_minimal.h and is currently 3.  'flags' is
152    updated to indicate capabilities of the module.  In particular, if
153    the module is thread-safe then it sets 'flags' to include
154    DNS_SDLZFLAG_THREADSAFE.  (Other capability flags may be added in
155    the future.)
156
157  - isc_result_t dlz_create(const char *dlzname,
158                            unsigned int argc, char *argv[],
159                            void **dbdata, ...);
160
161    Required for all external DLZ modules; this call initializes the
162    module.
163
164  - void dlz_destroy(void *dbdata);
165
166    Optional.  If supplied, this will be called when the driver is
167    unloaded.
168
169  - isc_result_t dlz_findzonedb(void *dbdata, const char *name,
170                                dns_clientinfomethods_t *methods,
171                                dns_clientinfo_t *clientinfo);
172
173    Required for all external DLZ modules.  This indicates whether
174    the DLZ module can answer for the given name.  Returns ISC_R_SUCCESS
175    if so, and ISC_R_NOTFOUND if not.  As an optimization, it can
176    also return ISC_R_NOMORE: this indicates that the DLZ module has
177    no data for the given name or for any name above it in the DNS.
178    This prevents named from searching for a zone cut.
179
180   - isc_result_t dlz_lookup(const char *zone, const char *name, void *dbdata,
181                             dns_sdlzlookup_t *lookup,
182                             dns_clientinfomethods_t *methods,
183                             dns_clientinfo_t *clientinfo);
184
185    Required for all external DLZ modules.  This carries out the database
186    lookup for a query.
187
188  - isc_result_t dlz_allowzonexfr(void *dbdata, const char *name,
189                                  const char *client);
190
191    Optional.  Supply this if you want the module to support AXFR
192    for the specified zone and client.  A return value of ISC_R_SUCCESS
193    means AXFR is allowed, any other value means it isn't.
194
195  -  isc_result_t dlz_allnodes(const char *zone, void *dbdata,
196                               dns_sdlzallnodes_t *allnodes);
197
198     Optional, but must be supplied dlz_allowzonexfr() is.  This function
199     returns all nodes in the zone in order to perform a zone transfer.
200
201  - isc_result_t dlz_newversion(const char *zone, void *dbdata,
202                                void **versionp);
203
204    Optional.  Supply this if you want the module to support DDNS
205    updates.  This function starts a transaction in the database.
206
207
208  - void dlz_closeversion(const char *zone, bool commit,
209                          void *dbdata, void **versionp);
210
211    Optional, but must be supplied if dlz_newversion() is.  This function
212    closes a transaction.  'commit' indicates whether to commit the changes
213    to the database, or ignore them.
214
215  - isc_result_t dlz_configure(dns_view_t *view, void *dbdata);
216
217    Optional, but must be supplied in order to support DDNS updates.
218
219  - bool dlz_ssumatch(const char *signer, const char *name,
220                               const char *tcpaddr, const char *type,
221                               const char *key, uint32_t keydatalen,
222                               uint8_t *keydata, void *dbdata);
223
224    Optional, but must be supplied in order to support DDNS updates.
225
226  - isc_result_t dlz_addrdataset(const char *name, const char *rdatastr,
227                                 void *dbdata, void *version);
228
229    Optional, but must be supplied in order to support DDNS updates.
230    Adds the data in 'rdatastr' to a database node.
231
232  - isc_result_t dlz_subrdataset(const char *name, const char *rdatastr,
233                                 void *dbdata, void *version);
234
235    Optional, but must be supplied in order to support DDNS updates.
236    Removes the data in 'rdatastr' from a database node.
237
238  - isc_result_t dlz_delrdataset(const char *name, const char *rdatastr,
239                                 void *dbdata, void *version);
240
241    Optional, but must be supplied in order to support DDNS updates.
242    Deletes all data matching the type specified in 'rdatastr' from
243    the database.
244