1 /* $NetBSD: builtin.c,v 1.8 2014/12/10 04:37:51 christos Exp $ */
4 * Copyright (C) 2004, 2005, 2007, 2009-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 2001-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: builtin.c,v 1.26 2012/01/21 19:44:18 each Exp */
24 * The built-in "version", "hostname", "id", "authors" and "empty" databases.
33 #include <isc/print.h>
34 #include <isc/result.h>
37 #include <dns/result.h>
40 #include <named/builtin.h>
41 #include <named/globals.h>
42 #include <named/server.h>
45 typedef struct builtin builtin_t
;
47 static isc_result_t
do_version_lookup(dns_sdblookup_t
*lookup
);
48 static isc_result_t
do_hostname_lookup(dns_sdblookup_t
*lookup
);
49 static isc_result_t
do_authors_lookup(dns_sdblookup_t
*lookup
);
50 static isc_result_t
do_id_lookup(dns_sdblookup_t
*lookup
);
51 static isc_result_t
do_empty_lookup(dns_sdblookup_t
*lookup
);
52 static isc_result_t
do_dns64_lookup(dns_sdblookup_t
*lookup
);
55 * We can't use function pointers as the db_data directly
56 * because ANSI C does not guarantee that function pointers
57 * can safely be cast to void pointers and back.
61 isc_result_t (*do_lookup
)(dns_sdblookup_t
*lookup
);
66 static builtin_t version_builtin
= { do_version_lookup
, NULL
, NULL
};
67 static builtin_t hostname_builtin
= { do_hostname_lookup
, NULL
, NULL
};
68 static builtin_t authors_builtin
= { do_authors_lookup
, NULL
, NULL
};
69 static builtin_t id_builtin
= { do_id_lookup
, NULL
, NULL
};
70 static builtin_t empty_builtin
= { do_empty_lookup
, NULL
, NULL
};
71 static builtin_t dns64_builtin
= { do_dns64_lookup
, NULL
, NULL
};
73 static dns_sdbimplementation_t
*builtin_impl
;
74 static dns_sdbimplementation_t
*dns64_impl
;
77 * Pre computed HEX * 16 or 1 table.
79 static const unsigned char hex16
[256] = {
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*00*/
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*20*/
83 0, 16, 32, 48, 64, 80, 96,112,128,144, 1, 1, 1, 1, 1, 1, /*30*/
84 1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*50*/
86 1,160,176,192,208,224,240, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/
89 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/
90 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*A0*/
91 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*B0*/
92 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*C0*/
93 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*D0*/
94 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*E0*/
95 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 /*F0*/
98 const unsigned char decimal
[] = "0123456789";
101 dns64_rdata(unsigned char *v
, size_t start
, unsigned char *rdata
) {
104 for (i
= 0; i
< 4U; i
++) {
105 unsigned char c
= v
[start
++];
110 rdata
[j
++] = decimal
[c
/100]; c
= c
% 100;
111 rdata
[j
++] = decimal
[c
/10]; c
= c
% 10;
112 rdata
[j
++] = decimal
[c
];
115 rdata
[j
++] = decimal
[c
/10]; c
= c
% 10;
116 rdata
[j
++] = decimal
[c
];
119 rdata
[j
++] = decimal
[c
];
122 memmove(&rdata
[j
], "\07in-addr\04arpa", 14);
127 dns64_cname(const dns_name_t
*zone
, const dns_name_t
*name
,
128 dns_sdblookup_t
*lookup
)
130 size_t zlen
, nlen
, j
, len
;
131 unsigned char v
[16], n
;
133 unsigned char rdata
[sizeof("123.123.123.123.in-addr.arpa.")];
134 unsigned char *ndata
;
137 * The combined length of the zone and name is 74.
139 * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
141 * The length of name should always be even as we are expecting
142 * a series of nibbles.
146 if ((zlen
+ nlen
) > 74U || zlen
< 10U || (nlen
% 2) != 0U)
147 return (ISC_R_NOTFOUND
);
150 * We assume the zone name is well formed.
154 * XXXMPA We could check the dns64 suffix here if we need to.
157 * Check that name is a series of nibbles.
158 * Compute the byte values that correspond to the nibbles as we go.
160 * Shift the final result 4 bits, by setting 'i' to 1, if we if we
161 * have a odd number of nibbles so that "must be zero" tests below
162 * are byte aligned and we correctly return ISC_R_NOTFOUND or
163 * ISC_R_SUCCESS. We will not generate a CNAME in this case.
166 i
= (nlen
% 4) == 2U ? 1 : 0;
168 memset(v
, 0, sizeof(v
));
170 INSIST((i
/2) < sizeof(v
));
172 return (ISC_R_NOTFOUND
);
173 n
= hex16
[ndata
[1]&0xff];
175 return (ISC_R_NOTFOUND
);
176 v
[i
/2] = n
| (v
[i
/2]>>4);
183 * If we get here then we know name only consisted of nibbles.
184 * Now we need to determine if the name exists or not and whether
185 * it corresponds to a empty node in the zone or there should be
188 #define ZLEN(x) (10 + (x)/2)
190 case ZLEN(32): /* prefix len 32 */
192 * The nibbles that map to this byte must be zero for 'name'
193 * to exist in the zone.
195 if (nlen
> 16U && v
[(nlen
-1)/4 - 4] != 0)
196 return (ISC_R_NOTFOUND
);
198 * If the total length is not 74 then this is a empty node
201 if (nlen
+ zlen
!= 74U)
202 return (ISC_R_SUCCESS
);
203 len
= dns64_rdata(v
, 8, rdata
);
205 case ZLEN(40): /* prefix len 40 */
207 * The nibbles that map to this byte must be zero for 'name'
208 * to exist in the zone.
210 if (nlen
> 12U && v
[(nlen
-1)/4 - 3] != 0)
211 return (ISC_R_NOTFOUND
);
213 * If the total length is not 74 then this is a empty node
216 if (nlen
+ zlen
!= 74U)
217 return (ISC_R_SUCCESS
);
218 len
= dns64_rdata(v
, 6, rdata
);
220 case ZLEN(48): /* prefix len 48 */
222 * The nibbles that map to this byte must be zero for 'name'
223 * to exist in the zone.
225 if (nlen
> 8U && v
[(nlen
-1)/4 - 2] != 0)
226 return (ISC_R_NOTFOUND
);
228 * If the total length is not 74 then this is a empty node
231 if (nlen
+ zlen
!= 74U)
232 return (ISC_R_SUCCESS
);
233 len
= dns64_rdata(v
, 5, rdata
);
235 case ZLEN(56): /* prefix len 56 */
237 * The nibbles that map to this byte must be zero for 'name'
238 * to exist in the zone.
240 if (nlen
> 4U && v
[(nlen
-1)/4 - 1] != 0)
241 return (ISC_R_NOTFOUND
);
243 * If the total length is not 74 then this is a empty node
246 if (nlen
+ zlen
!= 74U)
247 return (ISC_R_SUCCESS
);
248 len
= dns64_rdata(v
, 4, rdata
);
250 case ZLEN(64): /* prefix len 64 */
252 * The nibbles that map to this byte must be zero for 'name'
253 * to exist in the zone.
255 if (v
[(nlen
-1)/4] != 0)
256 return (ISC_R_NOTFOUND
);
258 * If the total length is not 74 then this is a empty node
261 if (nlen
+ zlen
!= 74U)
262 return (ISC_R_SUCCESS
);
263 len
= dns64_rdata(v
, 3, rdata
);
265 case ZLEN(96): /* prefix len 96 */
267 * If the total length is not 74 then this is a empty node
270 if (nlen
+ zlen
!= 74U)
271 return (ISC_R_SUCCESS
);
272 len
= dns64_rdata(v
, 0, rdata
);
276 * This should never be reached unless someone adds a
277 * zone declaration with this internal type to named.conf.
279 return (ISC_R_NOTFOUND
);
281 return (dns_sdb_putrdata(lookup
, dns_rdatatype_cname
, 600,
282 rdata
, (unsigned int)len
));
286 builtin_lookup(const char *zone
, const char *name
, void *dbdata
,
287 dns_sdblookup_t
*lookup
, dns_clientinfomethods_t
*methods
,
288 dns_clientinfo_t
*clientinfo
)
290 builtin_t
*b
= (builtin_t
*) dbdata
;
296 if (strcmp(name
, "@") == 0)
297 return (b
->do_lookup(lookup
));
299 return (ISC_R_NOTFOUND
);
303 dns64_lookup(const dns_name_t
*zone
, const dns_name_t
*name
, void *dbdata
,
304 dns_sdblookup_t
*lookup
, dns_clientinfomethods_t
*methods
,
305 dns_clientinfo_t
*clientinfo
)
307 builtin_t
*b
= (builtin_t
*) dbdata
;
312 if (name
->labels
== 0 && name
->length
== 0)
313 return (b
->do_lookup(lookup
));
315 return (dns64_cname(zone
, name
, lookup
));
319 put_txt(dns_sdblookup_t
*lookup
, const char *text
) {
320 unsigned char buf
[256];
321 unsigned int len
= strlen(text
);
323 len
= 255; /* Silently truncate */
325 memmove(&buf
[1], text
, len
);
326 return (dns_sdb_putrdata(lookup
, dns_rdatatype_txt
, 0, buf
, len
+ 1));
330 do_version_lookup(dns_sdblookup_t
*lookup
) {
331 if (ns_g_server
->version_set
) {
332 if (ns_g_server
->version
== NULL
)
333 return (ISC_R_SUCCESS
);
335 return (put_txt(lookup
, ns_g_server
->version
));
337 return (put_txt(lookup
, ns_g_version
));
342 do_hostname_lookup(dns_sdblookup_t
*lookup
) {
343 if (ns_g_server
->hostname_set
) {
344 if (ns_g_server
->hostname
== NULL
)
345 return (ISC_R_SUCCESS
);
347 return (put_txt(lookup
, ns_g_server
->hostname
));
350 isc_result_t result
= ns_os_gethostname(buf
, sizeof(buf
));
351 if (result
!= ISC_R_SUCCESS
)
353 return (put_txt(lookup
, buf
));
358 do_authors_lookup(dns_sdblookup_t
*lookup
) {
361 static const char *authors
[] = {
366 "John H. DuBois III",
369 "Andreas Gustafsson",
385 * If a version string is specified, disable the authors.bind zone.
387 if (ns_g_server
->version_set
)
388 return (ISC_R_SUCCESS
);
390 for (p
= authors
; *p
!= NULL
; p
++) {
391 result
= put_txt(lookup
, *p
);
392 if (result
!= ISC_R_SUCCESS
)
395 return (ISC_R_SUCCESS
);
399 do_id_lookup(dns_sdblookup_t
*lookup
) {
401 if (ns_g_server
->server_usehostname
) {
403 isc_result_t result
= ns_os_gethostname(buf
, sizeof(buf
));
404 if (result
!= ISC_R_SUCCESS
)
406 return (put_txt(lookup
, buf
));
409 if (ns_g_server
->server_id
== NULL
)
410 return (ISC_R_SUCCESS
);
412 return (put_txt(lookup
, ns_g_server
->server_id
));
416 do_dns64_lookup(dns_sdblookup_t
*lookup
) {
418 return (ISC_R_SUCCESS
);
422 do_empty_lookup(dns_sdblookup_t
*lookup
) {
425 return (ISC_R_SUCCESS
);
429 builtin_authority(const char *zone
, void *dbdata
, dns_sdblookup_t
*lookup
) {
431 const char *contact
= "hostmaster";
432 const char *server
= "@";
433 builtin_t
*b
= (builtin_t
*) dbdata
;
438 if (b
== &empty_builtin
) {
442 if (b
->server
!= NULL
)
444 if (b
->contact
!= NULL
)
445 contact
= b
->contact
;
448 result
= dns_sdb_putsoa(lookup
, server
, contact
, 0);
449 if (result
!= ISC_R_SUCCESS
)
450 return (ISC_R_FAILURE
);
452 result
= dns_sdb_putrr(lookup
, "ns", 0, server
);
453 if (result
!= ISC_R_SUCCESS
)
454 return (ISC_R_FAILURE
);
456 return (ISC_R_SUCCESS
);
460 builtin_create(const char *zone
, int argc
, char **argv
,
461 void *driverdata
, void **dbdata
)
468 if (strcmp(argv
[0], "empty") == 0 || strcmp(argv
[0], "dns64") == 0) {
470 return (DNS_R_SYNTAX
);
471 } else if (argc
!= 1)
472 return (DNS_R_SYNTAX
);
474 if (strcmp(argv
[0], "version") == 0)
475 *dbdata
= &version_builtin
;
476 else if (strcmp(argv
[0], "hostname") == 0)
477 *dbdata
= &hostname_builtin
;
478 else if (strcmp(argv
[0], "authors") == 0)
479 *dbdata
= &authors_builtin
;
480 else if (strcmp(argv
[0], "id") == 0)
481 *dbdata
= &id_builtin
;
482 else if (strcmp(argv
[0], "empty") == 0 ||
483 strcmp(argv
[0], "dns64") == 0) {
488 * We don't want built-in zones to fail. Fallback to
489 * the static configuration if memory allocation fails.
491 empty
= isc_mem_get(ns_g_mctx
, sizeof(*empty
));
492 server
= isc_mem_strdup(ns_g_mctx
, argv
[1]);
493 contact
= isc_mem_strdup(ns_g_mctx
, argv
[2]);
494 if (empty
== NULL
|| server
== NULL
|| contact
== NULL
) {
495 if (strcmp(argv
[0], "empty") == 0)
496 *dbdata
= &empty_builtin
;
498 *dbdata
= &dns64_builtin
;
500 isc_mem_free(ns_g_mctx
, server
);
502 isc_mem_free(ns_g_mctx
, contact
);
504 isc_mem_put(ns_g_mctx
, empty
, sizeof (*empty
));
506 if (strcmp(argv
[0], "empty") == 0)
507 memmove(empty
, &empty_builtin
,
508 sizeof (empty_builtin
));
510 memmove(empty
, &dns64_builtin
,
511 sizeof (empty_builtin
));
512 empty
->server
= server
;
513 empty
->contact
= contact
;
517 return (ISC_R_NOTIMPLEMENTED
);
518 return (ISC_R_SUCCESS
);
522 builtin_destroy(const char *zone
, void *driverdata
, void **dbdata
) {
523 builtin_t
*b
= (builtin_t
*) *dbdata
;
529 * Don't free the static versions.
531 if (*dbdata
== &version_builtin
|| *dbdata
== &hostname_builtin
||
532 *dbdata
== &authors_builtin
|| *dbdata
== &id_builtin
||
533 *dbdata
== &empty_builtin
|| *dbdata
== &dns64_builtin
)
536 isc_mem_free(ns_g_mctx
, b
->server
);
537 isc_mem_free(ns_g_mctx
, b
->contact
);
538 isc_mem_put(ns_g_mctx
, b
, sizeof (*b
));
541 static dns_sdbmethods_t builtin_methods
= {
550 static dns_sdbmethods_t dns64_methods
= {
560 ns_builtin_init(void) {
561 RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods
, NULL
,
562 DNS_SDBFLAG_RELATIVEOWNER
|
563 DNS_SDBFLAG_RELATIVERDATA
,
564 ns_g_mctx
, &builtin_impl
)
566 RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods
, NULL
,
567 DNS_SDBFLAG_RELATIVEOWNER
|
568 DNS_SDBFLAG_RELATIVERDATA
|
570 ns_g_mctx
, &dns64_impl
)
572 return (ISC_R_SUCCESS
);
576 ns_builtin_deinit(void) {
577 dns_sdb_unregister(&builtin_impl
);
578 dns_sdb_unregister(&dns64_impl
);