2 * Copyright (C) 2004, 2005, 2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2001-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: builtin.c,v 1.26 2012/01/21 19:44:18 each Exp $ */
22 * The built-in "version", "hostname", "id", "authors" and "empty" databases.
31 #include <isc/print.h>
32 #include <isc/result.h>
35 #include <dns/result.h>
38 #include <named/builtin.h>
39 #include <named/globals.h>
40 #include <named/server.h>
43 typedef struct builtin builtin_t;
45 static isc_result_t do_version_lookup(dns_sdblookup_t *lookup);
46 static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup);
47 static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup);
48 static isc_result_t do_id_lookup(dns_sdblookup_t *lookup);
49 static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup);
50 static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
53 * We can't use function pointers as the db_data directly
54 * because ANSI C does not guarantee that function pointers
55 * can safely be cast to void pointers and back.
59 isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
64 static builtin_t version_builtin = { do_version_lookup, NULL, NULL };
65 static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL };
66 static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL };
67 static builtin_t id_builtin = { do_id_lookup, NULL, NULL };
68 static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
69 static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
71 static dns_sdbimplementation_t *builtin_impl;
72 static dns_sdbimplementation_t *dns64_impl;
75 * Pre computed HEX * 16 or 1 table.
77 static const unsigned char hex16[256] = {
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/
79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/
81 0, 16, 32, 48, 64, 80, 96,112,128,144, 1, 1, 1, 1, 1, 1, /*30*/
82 1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/
83 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/
84 1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/
86 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/
90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/
91 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/
92 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/
93 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/
96 const unsigned char decimal[] = "0123456789";
99 dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
102 for (i = 0; i < 4U; i++) {
103 unsigned char c = v[start++];
108 rdata[j++] = decimal[c/100]; c = c % 100;
109 rdata[j++] = decimal[c/10]; c = c % 10;
110 rdata[j++] = decimal[c];
113 rdata[j++] = decimal[c/10]; c = c % 10;
114 rdata[j++] = decimal[c];
117 rdata[j++] = decimal[c];
120 memmove(&rdata[j], "\07in-addr\04arpa", 14);
125 dns64_cname(const dns_name_t *zone, const dns_name_t *name,
126 dns_sdblookup_t *lookup)
128 size_t zlen, nlen, j, len;
129 unsigned char v[16], n;
131 unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
132 unsigned char *ndata;
135 * The combined length of the zone and name is 74.
137 * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
139 * The length of name should always be even as we are expecting
140 * a series of nibbles.
144 if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
145 return (ISC_R_NOTFOUND);
148 * We assume the zone name is well formed.
152 * XXXMPA We could check the dns64 suffix here if we need to.
155 * Check that name is a series of nibbles.
156 * Compute the byte values that correspond to the nibbles as we go.
158 * Shift the final result 4 bits, by setting 'i' to 1, if we if we
159 * have a odd number of nibbles so that "must be zero" tests below
160 * are byte aligned and we correctly return ISC_R_NOTFOUND or
161 * ISC_R_SUCCESS. We will not generate a CNAME in this case.
164 i = (nlen % 4) == 2U ? 1 : 0;
166 memset(v, 0, sizeof(v));
168 INSIST((i/2) < sizeof(v));
170 return (ISC_R_NOTFOUND);
171 n = hex16[ndata[1]&0xff];
173 return (ISC_R_NOTFOUND);
174 v[i/2] = n | (v[i/2]>>4);
181 * If we get here then we know name only consisted of nibbles.
182 * Now we need to determine if the name exists or not and whether
183 * it corresponds to a empty node in the zone or there should be
186 #define ZLEN(x) (10 + (x)/2)
188 case ZLEN(32): /* prefix len 32 */
190 * The nibbles that map to this byte must be zero for 'name'
191 * to exist in the zone.
193 if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
194 return (ISC_R_NOTFOUND);
196 * If the total length is not 74 then this is a empty node
199 if (nlen + zlen != 74U)
200 return (ISC_R_SUCCESS);
201 len = dns64_rdata(v, 8, rdata);
203 case ZLEN(40): /* prefix len 40 */
205 * The nibbles that map to this byte must be zero for 'name'
206 * to exist in the zone.
208 if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
209 return (ISC_R_NOTFOUND);
211 * If the total length is not 74 then this is a empty node
214 if (nlen + zlen != 74U)
215 return (ISC_R_SUCCESS);
216 len = dns64_rdata(v, 6, rdata);
218 case ZLEN(48): /* prefix len 48 */
220 * The nibbles that map to this byte must be zero for 'name'
221 * to exist in the zone.
223 if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
224 return (ISC_R_NOTFOUND);
226 * If the total length is not 74 then this is a empty node
229 if (nlen + zlen != 74U)
230 return (ISC_R_SUCCESS);
231 len = dns64_rdata(v, 5, rdata);
233 case ZLEN(56): /* prefix len 56 */
235 * The nibbles that map to this byte must be zero for 'name'
236 * to exist in the zone.
238 if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
239 return (ISC_R_NOTFOUND);
241 * If the total length is not 74 then this is a empty node
244 if (nlen + zlen != 74U)
245 return (ISC_R_SUCCESS);
246 len = dns64_rdata(v, 4, rdata);
248 case ZLEN(64): /* prefix len 64 */
250 * The nibbles that map to this byte must be zero for 'name'
251 * to exist in the zone.
253 if (v[(nlen-1)/4] != 0)
254 return (ISC_R_NOTFOUND);
256 * If the total length is not 74 then this is a empty node
259 if (nlen + zlen != 74U)
260 return (ISC_R_SUCCESS);
261 len = dns64_rdata(v, 3, rdata);
263 case ZLEN(96): /* prefix len 96 */
265 * If the total length is not 74 then this is a empty node
268 if (nlen + zlen != 74U)
269 return (ISC_R_SUCCESS);
270 len = dns64_rdata(v, 0, rdata);
274 * This should never be reached unless someone adds a
275 * zone declaration with this internal type to named.conf.
277 return (ISC_R_NOTFOUND);
279 return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600,
280 rdata, (unsigned int)len));
284 builtin_lookup(const char *zone, const char *name, void *dbdata,
285 dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
286 dns_clientinfo_t *clientinfo)
288 builtin_t *b = (builtin_t *) dbdata;
294 if (strcmp(name, "@") == 0)
295 return (b->do_lookup(lookup));
297 return (ISC_R_NOTFOUND);
301 dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
302 dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
303 dns_clientinfo_t *clientinfo)
305 builtin_t *b = (builtin_t *) dbdata;
310 if (name->labels == 0 && name->length == 0)
311 return (b->do_lookup(lookup));
313 return (dns64_cname(zone, name, lookup));
317 put_txt(dns_sdblookup_t *lookup, const char *text) {
318 unsigned char buf[256];
319 unsigned int len = strlen(text);
321 len = 255; /* Silently truncate */
323 memmove(&buf[1], text, len);
324 return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
328 do_version_lookup(dns_sdblookup_t *lookup) {
329 if (ns_g_server->version_set) {
330 if (ns_g_server->version == NULL)
331 return (ISC_R_SUCCESS);
333 return (put_txt(lookup, ns_g_server->version));
335 return (put_txt(lookup, ns_g_version));
340 do_hostname_lookup(dns_sdblookup_t *lookup) {
341 if (ns_g_server->hostname_set) {
342 if (ns_g_server->hostname == NULL)
343 return (ISC_R_SUCCESS);
345 return (put_txt(lookup, ns_g_server->hostname));
348 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
349 if (result != ISC_R_SUCCESS)
351 return (put_txt(lookup, buf));
356 do_authors_lookup(dns_sdblookup_t *lookup) {
359 static const char *authors[] = {
364 "John H. DuBois III",
367 "Andreas Gustafsson",
383 * If a version string is specified, disable the authors.bind zone.
385 if (ns_g_server->version_set)
386 return (ISC_R_SUCCESS);
388 for (p = authors; *p != NULL; p++) {
389 result = put_txt(lookup, *p);
390 if (result != ISC_R_SUCCESS)
393 return (ISC_R_SUCCESS);
397 do_id_lookup(dns_sdblookup_t *lookup) {
399 if (ns_g_server->server_usehostname) {
401 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
402 if (result != ISC_R_SUCCESS)
404 return (put_txt(lookup, buf));
407 if (ns_g_server->server_id == NULL)
408 return (ISC_R_SUCCESS);
410 return (put_txt(lookup, ns_g_server->server_id));
414 do_dns64_lookup(dns_sdblookup_t *lookup) {
416 return (ISC_R_SUCCESS);
420 do_empty_lookup(dns_sdblookup_t *lookup) {
423 return (ISC_R_SUCCESS);
427 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
429 const char *contact = "hostmaster";
430 const char *server = "@";
431 builtin_t *b = (builtin_t *) dbdata;
436 if (b == &empty_builtin) {
440 if (b->server != NULL)
442 if (b->contact != NULL)
443 contact = b->contact;
446 result = dns_sdb_putsoa(lookup, server, contact, 0);
447 if (result != ISC_R_SUCCESS)
448 return (ISC_R_FAILURE);
450 result = dns_sdb_putrr(lookup, "ns", 0, server);
451 if (result != ISC_R_SUCCESS)
452 return (ISC_R_FAILURE);
454 return (ISC_R_SUCCESS);
458 builtin_create(const char *zone, int argc, char **argv,
459 void *driverdata, void **dbdata)
466 if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
468 return (DNS_R_SYNTAX);
469 } else if (argc != 1)
470 return (DNS_R_SYNTAX);
472 if (strcmp(argv[0], "version") == 0)
473 *dbdata = &version_builtin;
474 else if (strcmp(argv[0], "hostname") == 0)
475 *dbdata = &hostname_builtin;
476 else if (strcmp(argv[0], "authors") == 0)
477 *dbdata = &authors_builtin;
478 else if (strcmp(argv[0], "id") == 0)
479 *dbdata = &id_builtin;
480 else if (strcmp(argv[0], "empty") == 0 ||
481 strcmp(argv[0], "dns64") == 0) {
486 * We don't want built-in zones to fail. Fallback to
487 * the static configuration if memory allocation fails.
489 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
490 server = isc_mem_strdup(ns_g_mctx, argv[1]);
491 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
492 if (empty == NULL || server == NULL || contact == NULL) {
493 if (strcmp(argv[0], "empty") == 0)
494 *dbdata = &empty_builtin;
496 *dbdata = &dns64_builtin;
498 isc_mem_free(ns_g_mctx, server);
500 isc_mem_free(ns_g_mctx, contact);
502 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
504 if (strcmp(argv[0], "empty") == 0)
505 memmove(empty, &empty_builtin,
506 sizeof (empty_builtin));
508 memmove(empty, &dns64_builtin,
509 sizeof (empty_builtin));
510 empty->server = server;
511 empty->contact = contact;
515 return (ISC_R_NOTIMPLEMENTED);
516 return (ISC_R_SUCCESS);
520 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
521 builtin_t *b = (builtin_t *) *dbdata;
527 * Don't free the static versions.
529 if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
530 *dbdata == &authors_builtin || *dbdata == &id_builtin ||
531 *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
534 isc_mem_free(ns_g_mctx, b->server);
535 isc_mem_free(ns_g_mctx, b->contact);
536 isc_mem_put(ns_g_mctx, b, sizeof (*b));
539 static dns_sdbmethods_t builtin_methods = {
548 static dns_sdbmethods_t dns64_methods = {
558 ns_builtin_init(void) {
559 RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
560 DNS_SDBFLAG_RELATIVEOWNER |
561 DNS_SDBFLAG_RELATIVERDATA,
562 ns_g_mctx, &builtin_impl)
564 RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
565 DNS_SDBFLAG_RELATIVEOWNER |
566 DNS_SDBFLAG_RELATIVERDATA |
568 ns_g_mctx, &dns64_impl)
570 return (ISC_R_SUCCESS);
574 ns_builtin_deinit(void) {
575 dns_sdb_unregister(&builtin_impl);
576 dns_sdb_unregister(&dns64_impl);