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