2 * Copyright (C) 2004, 2005, 2007, 2009-2012 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.20.14.3 2012/01/11 20:19:40 ckb 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;
73 static const char hex[] = "0123456789abcdef";
74 static const char HEX[] = "0123456789ABCDEF";
77 dns64_cname(const char *zone, const char *name, dns_sdblookup_t *lookup) {
82 char reverse[sizeof("123.123.123.123.in-addr.arpa.")];
85 * The sum the length of the relative name and the length of the zone
86 * name for a IPv6 reverse lookup comes to 71.
88 * The reverse of 2001::10.0.0.1 (dns64 2001::/96) has a zone of
89 * "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.2.ip6.arpa"
90 * and a name of "1.0.0.0.0.0.a.0". The sum of the lengths of these
93 * The minimum length for a ip6.arpa zone name is 8.
95 * The length of name should always be odd as we are expecting
96 * a series of nibbles.
100 if ((zlen + nlen) > 71U || zlen < 8U || (nlen % 2) != 1U)
101 return (ISC_R_NOTFOUND);
104 * We assume the zone name is well formed.
108 * XXXMPA We could check the dns64 suffix here if we need to.
111 * Check that name is a series of nibbles.
112 * Compute the byte values that correspond to the nibbles as we go.
114 * Shift the final result 4 bits, by setting 'i' to 1, if we if we
115 * have a odd number of nibbles so that "must be zero" tests below
116 * are byte aligned and we correctly return ISC_R_NOTFOUND or
117 * ISC_R_SUCCESS. We will not generate a CNAME in this case.
119 i = (nlen % 4) == 1U ? 1 : 0;
121 memset(v, 0, sizeof(v));
123 INSIST((i/2) < sizeof(v));
124 if (j > 1U && name[1] != '.')
125 return (ISC_R_NOTFOUND);
127 if ((s = strchr(hex, name[0])) != NULL)
128 v[i/2] |= (s - hex) << 4;
129 else if ((s = strchr(HEX, name[0])) != NULL)
130 v[i/2] |= (s - HEX) << 4;
132 return (ISC_R_NOTFOUND);
142 * If we get here then we know name only consisted of nibbles.
143 * Now we need to determine if the name exists or not and whether
144 * it corresponds to a empty node in the zone or there should be
148 case 24: /* prefix len 32 */
150 * If the total length is not 71 then this is a empty node
153 if (nlen + zlen != 71U)
154 return (ISC_R_SUCCESS);
155 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
156 v[8], v[9], v[10], v[11]);
158 case 28: /* prefix len 40 */
160 * The nibbles that map to this byte must be zero for 'name'
161 * to exist in the zone.
163 if (nlen > 11U && v[nlen/4 - 3] != 0)
164 return (ISC_R_NOTFOUND);
166 * If the total length is not 71 then this is a empty node
169 if (nlen + zlen != 71U)
170 return (ISC_R_SUCCESS);
171 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
172 v[6], v[8], v[9], v[10]);
174 case 32: /* prefix len 48 */
176 * The nibbles that map to this byte must be zero for 'name'
177 * to exist in the zone.
179 if (nlen > 7U && v[nlen/4 - 2] != 0)
180 return (ISC_R_NOTFOUND);
182 * If the total length is not 71 then this is a empty node
185 if (nlen + zlen != 71U)
186 return (ISC_R_SUCCESS);
187 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
188 v[5], v[6], v[8], v[9]);
190 case 36: /* prefix len 56 */
192 * The nibbles that map to this byte must be zero for 'name'
193 * to exist in the zone.
195 if (nlen > 3U && v[nlen/4 - 1] != 0)
196 return (ISC_R_NOTFOUND);
198 * If the total length is not 71 then this is a empty node
201 if (nlen + zlen != 71U)
202 return (ISC_R_SUCCESS);
203 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
204 v[4], v[5], v[6], v[8]);
206 case 40: /* prefix len 64 */
208 * The nibbles that map to this byte must be zero for 'name'
209 * to exist in the zone.
212 return (ISC_R_NOTFOUND);
214 * If the total length is not 71 then this is a empty node
217 if (nlen + zlen != 71U)
218 return (ISC_R_SUCCESS);
219 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
220 v[3], v[4], v[5], v[6]);
222 case 56: /* prefix len 96 */
224 * If the total length is not 71 then this is a empty node
227 if (nlen + zlen != 71U)
228 return (ISC_R_SUCCESS);
229 snprintf(reverse, sizeof(reverse), "%u.%u.%u.%u.in-addr.arpa.",
230 v[0], v[1], v[2], v[3]);
234 * This should never be reached unless someone adds a
235 * zone declaration with this internal type to named.conf.
237 return (ISC_R_NOTFOUND);
239 return (dns_sdb_putrr(lookup, "CNAME", 600, reverse));
243 builtin_lookup(const char *zone, const char *name, void *dbdata,
244 dns_sdblookup_t *lookup)
246 builtin_t *b = (builtin_t *) dbdata;
250 if (strcmp(name, "@") == 0)
251 return (b->do_lookup(lookup));
252 else if (b->do_lookup == do_dns64_lookup)
253 return (dns64_cname(zone, name, lookup));
255 return (ISC_R_NOTFOUND);
259 put_txt(dns_sdblookup_t *lookup, const char *text) {
260 unsigned char buf[256];
261 unsigned int len = strlen(text);
263 len = 255; /* Silently truncate */
265 memcpy(&buf[1], text, len);
266 return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
270 do_version_lookup(dns_sdblookup_t *lookup) {
271 if (ns_g_server->version_set) {
272 if (ns_g_server->version == NULL)
273 return (ISC_R_SUCCESS);
275 return (put_txt(lookup, ns_g_server->version));
277 return (put_txt(lookup, ns_g_version));
282 do_hostname_lookup(dns_sdblookup_t *lookup) {
283 if (ns_g_server->hostname_set) {
284 if (ns_g_server->hostname == NULL)
285 return (ISC_R_SUCCESS);
287 return (put_txt(lookup, ns_g_server->hostname));
290 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
291 if (result != ISC_R_SUCCESS)
293 return (put_txt(lookup, buf));
298 do_authors_lookup(dns_sdblookup_t *lookup) {
301 static const char *authors[] = {
307 "Andreas Gustafsson",
323 * If a version string is specified, disable the authors.bind zone.
325 if (ns_g_server->version_set)
326 return (ISC_R_SUCCESS);
328 for (p = authors; *p != NULL; p++) {
329 result = put_txt(lookup, *p);
330 if (result != ISC_R_SUCCESS)
333 return (ISC_R_SUCCESS);
337 do_id_lookup(dns_sdblookup_t *lookup) {
339 if (ns_g_server->server_usehostname) {
341 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
342 if (result != ISC_R_SUCCESS)
344 return (put_txt(lookup, buf));
347 if (ns_g_server->server_id == NULL)
348 return (ISC_R_SUCCESS);
350 return (put_txt(lookup, ns_g_server->server_id));
354 do_dns64_lookup(dns_sdblookup_t *lookup) {
356 return (ISC_R_SUCCESS);
360 do_empty_lookup(dns_sdblookup_t *lookup) {
363 return (ISC_R_SUCCESS);
367 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
369 const char *contact = "hostmaster";
370 const char *server = "@";
371 builtin_t *b = (builtin_t *) dbdata;
376 if (b == &empty_builtin) {
380 if (b->server != NULL)
382 if (b->contact != NULL)
383 contact = b->contact;
386 result = dns_sdb_putsoa(lookup, server, contact, 0);
387 if (result != ISC_R_SUCCESS)
388 return (ISC_R_FAILURE);
390 result = dns_sdb_putrr(lookup, "ns", 0, server);
391 if (result != ISC_R_SUCCESS)
392 return (ISC_R_FAILURE);
394 return (ISC_R_SUCCESS);
398 builtin_create(const char *zone, int argc, char **argv,
399 void *driverdata, void **dbdata)
406 if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
408 return (DNS_R_SYNTAX);
409 } else if (argc != 1)
410 return (DNS_R_SYNTAX);
412 if (strcmp(argv[0], "version") == 0)
413 *dbdata = &version_builtin;
414 else if (strcmp(argv[0], "hostname") == 0)
415 *dbdata = &hostname_builtin;
416 else if (strcmp(argv[0], "authors") == 0)
417 *dbdata = &authors_builtin;
418 else if (strcmp(argv[0], "id") == 0)
419 *dbdata = &id_builtin;
420 else if (strcmp(argv[0], "empty") == 0 ||
421 strcmp(argv[0], "dns64") == 0) {
426 * We don't want built-in zones to fail. Fallback to
427 * the static configuration if memory allocation fails.
429 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
430 server = isc_mem_strdup(ns_g_mctx, argv[1]);
431 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
432 if (empty == NULL || server == NULL || contact == NULL) {
433 if (strcmp(argv[0], "empty") == 0)
434 *dbdata = &empty_builtin;
436 *dbdata = &dns64_builtin;
438 isc_mem_free(ns_g_mctx, server);
440 isc_mem_free(ns_g_mctx, contact);
442 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
444 if (strcmp(argv[0], "empty") == 0)
445 memcpy(empty, &empty_builtin,
446 sizeof (empty_builtin));
448 memcpy(empty, &dns64_builtin,
449 sizeof (empty_builtin));
450 empty->server = server;
451 empty->contact = contact;
455 return (ISC_R_NOTIMPLEMENTED);
456 return (ISC_R_SUCCESS);
460 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
461 builtin_t *b = (builtin_t *) *dbdata;
467 * Don't free the static versions.
469 if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
470 *dbdata == &authors_builtin || *dbdata == &id_builtin ||
471 *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
474 isc_mem_free(ns_g_mctx, b->server);
475 isc_mem_free(ns_g_mctx, b->contact);
476 isc_mem_put(ns_g_mctx, b, sizeof (*b));
479 static dns_sdbmethods_t builtin_methods = {
488 ns_builtin_init(void) {
489 RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
490 DNS_SDBFLAG_RELATIVEOWNER |
491 DNS_SDBFLAG_RELATIVERDATA,
492 ns_g_mctx, &builtin_impl)
494 return (ISC_R_SUCCESS);
498 ns_builtin_deinit(void) {
499 dns_sdb_unregister(&builtin_impl);