Home | History | Annotate | Line # | Download | only in named
builtin.c revision 1.2.2.2
      1 /*	$NetBSD: builtin.c,v 1.2.2.2 2018/09/06 06:53:56 pgoyette Exp $	*/
      2 
      3 /*
      4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
      5  *
      6  * This Source Code Form is subject to the terms of the Mozilla Public
      7  * License, v. 2.0. If a copy of the MPL was not distributed with this
      8  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
      9  *
     10  * See the COPYRIGHT file distributed with this work for additional
     11  * information regarding copyright ownership.
     12  */
     13 
     14 
     15 /*! \file
     16  * \brief
     17  * The built-in "version", "hostname", "id", "authors" and "empty" databases.
     18  */
     19 
     20 #include <config.h>
     21 
     22 #include <string.h>
     23 #include <stdio.h>
     24 
     25 #include <isc/mem.h>
     26 #include <isc/print.h>
     27 #include <isc/result.h>
     28 #include <isc/util.h>
     29 
     30 #include <dns/result.h>
     31 #include <dns/sdb.h>
     32 
     33 #include <named/builtin.h>
     34 #include <named/globals.h>
     35 #include <named/server.h>
     36 #include <named/os.h>
     37 
     38 typedef struct builtin builtin_t;
     39 
     40 static isc_result_t do_version_lookup(dns_sdblookup_t *lookup);
     41 static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup);
     42 static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup);
     43 static isc_result_t do_id_lookup(dns_sdblookup_t *lookup);
     44 static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup);
     45 static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
     46 
     47 /*
     48  * We can't use function pointers as the db_data directly
     49  * because ANSI C does not guarantee that function pointers
     50  * can safely be cast to void pointers and back.
     51  */
     52 
     53 struct builtin {
     54 	isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
     55 	char *server;
     56 	char *contact;
     57 };
     58 
     59 static builtin_t version_builtin = { do_version_lookup,  NULL, NULL };
     60 static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL };
     61 static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL };
     62 static builtin_t id_builtin = { do_id_lookup, NULL, NULL };
     63 static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
     64 static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
     65 
     66 static dns_sdbimplementation_t *builtin_impl;
     67 static dns_sdbimplementation_t *dns64_impl;
     68 
     69 /*
     70  * Pre computed HEX * 16 or 1 table.
     71  */
     72 static const unsigned char hex16[256] = {
     73 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*00*/
     74 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,	/*10*/
     75 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*20*/
     76 	 0, 16, 32, 48, 64, 80, 96,112,128,144,  1,  1,  1,  1,  1,  1,	/*30*/
     77 	 1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*40*/
     78 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*50*/
     79 	 1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*60*/
     80 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*70*/
     81 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*80*/
     82 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*90*/
     83 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*A0*/
     84 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*B0*/
     85 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*C0*/
     86 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*D0*/
     87 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*E0*/
     88 	 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1  /*F0*/
     89 };
     90 
     91 const unsigned char decimal[] = "0123456789";
     92 
     93 static size_t
     94 dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
     95 	size_t i, j = 0;
     96 
     97 	for (i = 0; i < 4U; i++) {
     98 		unsigned char c = v[start++];
     99 		if (start == 7U)
    100 			start++;
    101 		if (c > 99) {
    102 			rdata[j++] = 3;
    103 			rdata[j++] = decimal[c/100]; c = c % 100;
    104 			rdata[j++] = decimal[c/10]; c = c % 10;
    105 			rdata[j++] = decimal[c];
    106 		} else if (c > 9) {
    107 			rdata[j++] = 2;
    108 			rdata[j++] = decimal[c/10]; c = c % 10;
    109 			rdata[j++] = decimal[c];
    110 		} else {
    111 			rdata[j++] = 1;
    112 			rdata[j++] = decimal[c];
    113 		}
    114 	}
    115 	memmove(&rdata[j], "\07in-addr\04arpa", 14);
    116 	return (j + 14);
    117 }
    118 
    119 static isc_result_t
    120 dns64_cname(const dns_name_t *zone, const dns_name_t *name,
    121 	    dns_sdblookup_t *lookup)
    122 {
    123 	size_t zlen, nlen, j, len;
    124 	unsigned char v[16], n;
    125 	unsigned int i;
    126 	unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
    127 	unsigned char *ndata;
    128 
    129 	/*
    130 	 * The combined length of the zone and name is 74.
    131 	 *
    132 	 * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
    133 	 *
    134 	 * The length of name should always be even as we are expecting
    135 	 * a series of nibbles.
    136 	 */
    137 	zlen = zone->length;
    138 	nlen = name->length;
    139 	if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
    140 		return (ISC_R_NOTFOUND);
    141 
    142 	/*
    143 	 * We assume the zone name is well formed.
    144 	 */
    145 
    146 	/*
    147 	 * XXXMPA We could check the dns64 suffix here if we need to.
    148 	 */
    149 	/*
    150 	 * Check that name is a series of nibbles.
    151 	 * Compute the byte values that correspond to the nibbles as we go.
    152 	 *
    153 	 * Shift the final result 4 bits, by setting 'i' to 1, if we if we
    154 	 * have a odd number of nibbles so that "must be zero" tests below
    155 	 * are byte aligned and we correctly return ISC_R_NOTFOUND or
    156 	 * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
    157 	 */
    158 	ndata = name->ndata;
    159 	i = (nlen % 4) == 2U ? 1 : 0;
    160 	j = nlen;
    161 	memset(v, 0, sizeof(v));
    162 	while (j != 0U) {
    163 		INSIST((i/2) < sizeof(v));
    164 		if (ndata[0] != 1)
    165 			return (ISC_R_NOTFOUND);
    166 		n = hex16[ndata[1]&0xff];
    167 		if (n == 1)
    168 			return (ISC_R_NOTFOUND);
    169 		v[i/2] = n | (v[i/2]>>4);
    170 		j -= 2;
    171 		ndata += 2;
    172 		i++;
    173 	}
    174 
    175 	/*
    176 	 * If we get here then we know name only consisted of nibbles.
    177 	 * Now we need to determine if the name exists or not and whether
    178 	 * it corresponds to a empty node in the zone or there should be
    179 	 * a CNAME.
    180 	 */
    181 #define ZLEN(x) (10 + (x)/2)
    182 	switch (zlen) {
    183 	case ZLEN(32):	/* prefix len 32 */
    184 		/*
    185 		 * The nibbles that map to this byte must be zero for 'name'
    186 		 * to exist in the zone.
    187 		 */
    188 		if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
    189 			return (ISC_R_NOTFOUND);
    190 		/*
    191 		 * If the total length is not 74 then this is a empty node
    192 		 * so return success.
    193 		 */
    194 		if (nlen + zlen != 74U)
    195 			return (ISC_R_SUCCESS);
    196 		len = dns64_rdata(v, 8, rdata);
    197 		break;
    198 	case ZLEN(40):	/* prefix len 40 */
    199 		/*
    200 		 * The nibbles that map to this byte must be zero for 'name'
    201 		 * to exist in the zone.
    202 		 */
    203 		if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
    204 			return (ISC_R_NOTFOUND);
    205 		/*
    206 		 * If the total length is not 74 then this is a empty node
    207 		 * so return success.
    208 		 */
    209 		if (nlen + zlen != 74U)
    210 			return (ISC_R_SUCCESS);
    211 		len = dns64_rdata(v, 6, rdata);
    212 		break;
    213 	case ZLEN(48):	/* prefix len 48 */
    214 		/*
    215 		 * The nibbles that map to this byte must be zero for 'name'
    216 		 * to exist in the zone.
    217 		 */
    218 		if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
    219 			return (ISC_R_NOTFOUND);
    220 		/*
    221 		 * If the total length is not 74 then this is a empty node
    222 		 * so return success.
    223 		 */
    224 		if (nlen + zlen != 74U)
    225 			return (ISC_R_SUCCESS);
    226 		len = dns64_rdata(v, 5, rdata);
    227 		break;
    228 	case ZLEN(56):	/* prefix len 56 */
    229 		/*
    230 		 * The nibbles that map to this byte must be zero for 'name'
    231 		 * to exist in the zone.
    232 		 */
    233 		if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
    234 			return (ISC_R_NOTFOUND);
    235 		/*
    236 		 * If the total length is not 74 then this is a empty node
    237 		 * so return success.
    238 		 */
    239 		if (nlen + zlen != 74U)
    240 			return (ISC_R_SUCCESS);
    241 		len = dns64_rdata(v, 4, rdata);
    242 		break;
    243 	case ZLEN(64):	/* prefix len 64 */
    244 		/*
    245 		 * The nibbles that map to this byte must be zero for 'name'
    246 		 * to exist in the zone.
    247 		 */
    248 		if (v[(nlen-1)/4] != 0)
    249 			return (ISC_R_NOTFOUND);
    250 		/*
    251 		 * If the total length is not 74 then this is a empty node
    252 		 * so return success.
    253 		 */
    254 		if (nlen + zlen != 74U)
    255 			return (ISC_R_SUCCESS);
    256 		len = dns64_rdata(v, 3, rdata);
    257 		break;
    258 	case ZLEN(96):	/* prefix len 96 */
    259 		/*
    260 		 * If the total length is not 74 then this is a empty node
    261 		 * so return success.
    262 		 */
    263 		if (nlen + zlen != 74U)
    264 			return (ISC_R_SUCCESS);
    265 		len = dns64_rdata(v, 0, rdata);
    266 		break;
    267 	default:
    268 		/*
    269 		 * This should never be reached unless someone adds a
    270 		 * zone declaration with this internal type to named.conf.
    271 		 */
    272 		return (ISC_R_NOTFOUND);
    273 	}
    274 	return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600,
    275 				 rdata, (unsigned int)len));
    276 }
    277 
    278 static isc_result_t
    279 builtin_lookup(const char *zone, const char *name, void *dbdata,
    280 	       dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
    281 	       dns_clientinfo_t *clientinfo)
    282 {
    283 	builtin_t *b = (builtin_t *) dbdata;
    284 
    285 	UNUSED(zone);
    286 	UNUSED(methods);
    287 	UNUSED(clientinfo);
    288 
    289 	if (strcmp(name, "@") == 0)
    290 		return (b->do_lookup(lookup));
    291 	else
    292 		return (ISC_R_NOTFOUND);
    293 }
    294 
    295 static isc_result_t
    296 dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
    297 	     dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
    298 	     dns_clientinfo_t *clientinfo)
    299 {
    300 	builtin_t *b = (builtin_t *) dbdata;
    301 
    302 	UNUSED(methods);
    303 	UNUSED(clientinfo);
    304 
    305 	if (name->labels == 0 && name->length == 0)
    306 		return (b->do_lookup(lookup));
    307 	else
    308 		return (dns64_cname(zone, name, lookup));
    309 }
    310 
    311 static isc_result_t
    312 put_txt(dns_sdblookup_t *lookup, const char *text) {
    313 	unsigned char buf[256];
    314 	unsigned int len = strlen(text);
    315 	if (len > 255)
    316 		len = 255; /* Silently truncate */
    317 	buf[0] = len;
    318 	memmove(&buf[1], text, len);
    319 	return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
    320 }
    321 
    322 static isc_result_t
    323 do_version_lookup(dns_sdblookup_t *lookup) {
    324 	if (named_g_server->version_set) {
    325 		if (named_g_server->version == NULL)
    326 			return (ISC_R_SUCCESS);
    327 		else
    328 			return (put_txt(lookup, named_g_server->version));
    329 	} else {
    330 		return (put_txt(lookup, named_g_version));
    331 	}
    332 }
    333 
    334 static isc_result_t
    335 do_hostname_lookup(dns_sdblookup_t *lookup) {
    336 	if (named_g_server->hostname_set) {
    337 		if (named_g_server->hostname == NULL)
    338 			return (ISC_R_SUCCESS);
    339 		else
    340 			return (put_txt(lookup, named_g_server->hostname));
    341 	} else {
    342 		char buf[256];
    343 		isc_result_t result = named_os_gethostname(buf, sizeof(buf));
    344 		if (result != ISC_R_SUCCESS)
    345 			return (result);
    346 		return (put_txt(lookup, buf));
    347 	}
    348 }
    349 
    350 static isc_result_t
    351 do_authors_lookup(dns_sdblookup_t *lookup) {
    352 	isc_result_t result;
    353 	const char **p;
    354 	static const char *authors[] = {
    355 		"Mark Andrews",
    356 		"Curtis Blackburn",
    357 		"James Brister",
    358 		"Ben Cottrell",
    359 		"John H. DuBois III",
    360 		"Francis Dupont",
    361 		"Michael Graff",
    362 		"Andreas Gustafsson",
    363 		"Bob Halley",
    364 		"Evan Hunt",
    365 		"JINMEI Tatuya",
    366 		"Witold Krecicki",
    367 		"David Lawrence",
    368 		"Scott Mann",
    369 		"Danny Mayer",
    370 		"Damien Neil",
    371 		"Matt Nelson",
    372 		"Jeremy C. Reed",
    373 		"Michael Sawyer",
    374 		"Brian Wellington",
    375 		NULL
    376 	};
    377 
    378 	/*
    379 	 * If a version string is specified, disable the authors.bind zone.
    380 	 */
    381 	if (named_g_server->version_set)
    382 		return (ISC_R_SUCCESS);
    383 
    384 	for (p = authors; *p != NULL; p++) {
    385 		result = put_txt(lookup, *p);
    386 		if (result != ISC_R_SUCCESS)
    387 			return (result);
    388 	}
    389 	return (ISC_R_SUCCESS);
    390 }
    391 
    392 static isc_result_t
    393 do_id_lookup(dns_sdblookup_t *lookup) {
    394 	if (named_g_server->sctx->gethostname != NULL) {
    395 		char buf[256];
    396 		isc_result_t result;
    397 
    398 		result = named_g_server->sctx->gethostname(buf, sizeof(buf));
    399 		if (result != ISC_R_SUCCESS)
    400 			return (result);
    401 		return (put_txt(lookup, buf));
    402 	} else if (named_g_server->sctx->server_id != NULL)
    403 		return (put_txt(lookup, named_g_server->sctx->server_id));
    404 	else
    405 		return (ISC_R_SUCCESS);
    406 }
    407 
    408 static isc_result_t
    409 do_dns64_lookup(dns_sdblookup_t *lookup) {
    410 	UNUSED(lookup);
    411 	return (ISC_R_SUCCESS);
    412 }
    413 
    414 static isc_result_t
    415 do_empty_lookup(dns_sdblookup_t *lookup) {
    416 
    417 	UNUSED(lookup);
    418 	return (ISC_R_SUCCESS);
    419 }
    420 
    421 static isc_result_t
    422 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
    423 	isc_result_t result;
    424 	const char *contact = "hostmaster";
    425 	const char *server = "@";
    426 	builtin_t *b = (builtin_t *) dbdata;
    427 
    428 	UNUSED(zone);
    429 	UNUSED(dbdata);
    430 
    431 	if (b == &empty_builtin) {
    432 		server = ".";
    433 		contact = ".";
    434 	} else {
    435 		if (b->server != NULL)
    436 			server = b->server;
    437 		if (b->contact != NULL)
    438 			contact = b->contact;
    439 	}
    440 
    441 	result = dns_sdb_putsoa(lookup, server, contact, 0);
    442 	if (result != ISC_R_SUCCESS)
    443 		return (ISC_R_FAILURE);
    444 
    445 	result = dns_sdb_putrr(lookup, "ns", 0, server);
    446 	if (result != ISC_R_SUCCESS)
    447 		return (ISC_R_FAILURE);
    448 
    449 	return (ISC_R_SUCCESS);
    450 }
    451 
    452 static isc_result_t
    453 builtin_create(const char *zone, int argc, char **argv,
    454 	       void *driverdata, void **dbdata)
    455 {
    456 	REQUIRE(argc >= 1);
    457 
    458 	UNUSED(zone);
    459 	UNUSED(driverdata);
    460 
    461 	if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
    462 		if (argc != 3)
    463 			return (DNS_R_SYNTAX);
    464 	} else if (argc != 1)
    465 		return (DNS_R_SYNTAX);
    466 
    467 	if (strcmp(argv[0], "version") == 0)
    468 		*dbdata = &version_builtin;
    469 	else if (strcmp(argv[0], "hostname") == 0)
    470 		*dbdata = &hostname_builtin;
    471 	else if (strcmp(argv[0], "authors") == 0)
    472 		*dbdata = &authors_builtin;
    473 	else if (strcmp(argv[0], "id") == 0)
    474 		*dbdata = &id_builtin;
    475 	else if (strcmp(argv[0], "empty") == 0 ||
    476 		 strcmp(argv[0], "dns64") == 0) {
    477 		builtin_t *empty;
    478 		char *server;
    479 		char *contact;
    480 		/*
    481 		 * We don't want built-in zones to fail.  Fallback to
    482 		 * the static configuration if memory allocation fails.
    483 		 */
    484 		empty = isc_mem_get(named_g_mctx, sizeof(*empty));
    485 		server = isc_mem_strdup(named_g_mctx, argv[1]);
    486 		contact = isc_mem_strdup(named_g_mctx, argv[2]);
    487 		if (empty == NULL || server == NULL || contact == NULL) {
    488 			if (strcmp(argv[0], "empty") == 0)
    489 				*dbdata = &empty_builtin;
    490 			else
    491 				*dbdata = &dns64_builtin;
    492 			if (server != NULL)
    493 				isc_mem_free(named_g_mctx, server);
    494 			if (contact != NULL)
    495 				isc_mem_free(named_g_mctx, contact);
    496 			if (empty != NULL)
    497 				isc_mem_put(named_g_mctx, empty,
    498 					    sizeof (*empty));
    499 		} else {
    500 			if (strcmp(argv[0], "empty") == 0)
    501 				memmove(empty, &empty_builtin,
    502 					sizeof (empty_builtin));
    503 			else
    504 				memmove(empty, &dns64_builtin,
    505 					sizeof (empty_builtin));
    506 			empty->server = server;
    507 			empty->contact = contact;
    508 			*dbdata = empty;
    509 		}
    510 	} else
    511 		return (ISC_R_NOTIMPLEMENTED);
    512 	return (ISC_R_SUCCESS);
    513 }
    514 
    515 static void
    516 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
    517 	builtin_t *b = (builtin_t *) *dbdata;
    518 
    519 	UNUSED(zone);
    520 	UNUSED(driverdata);
    521 
    522 	/*
    523 	 * Don't free the static versions.
    524 	 */
    525 	if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
    526 	    *dbdata == &authors_builtin || *dbdata == &id_builtin ||
    527 	    *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
    528 		return;
    529 
    530 	isc_mem_free(named_g_mctx, b->server);
    531 	isc_mem_free(named_g_mctx, b->contact);
    532 	isc_mem_put(named_g_mctx, b, sizeof (*b));
    533 }
    534 
    535 static dns_sdbmethods_t builtin_methods = {
    536 	builtin_lookup,
    537 	builtin_authority,
    538 	NULL,		/* allnodes */
    539 	builtin_create,
    540 	builtin_destroy,
    541 	NULL
    542 };
    543 
    544 static dns_sdbmethods_t dns64_methods = {
    545 	NULL,
    546 	builtin_authority,
    547 	NULL,		/* allnodes */
    548 	builtin_create,
    549 	builtin_destroy,
    550 	dns64_lookup,
    551 };
    552 
    553 isc_result_t
    554 named_builtin_init(void) {
    555 	RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
    556 				       DNS_SDBFLAG_RELATIVEOWNER |
    557 				       DNS_SDBFLAG_RELATIVERDATA,
    558 				       named_g_mctx, &builtin_impl)
    559 		      == ISC_R_SUCCESS);
    560 	RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
    561 				       DNS_SDBFLAG_RELATIVEOWNER |
    562 				       DNS_SDBFLAG_RELATIVERDATA |
    563 				       DNS_SDBFLAG_DNS64,
    564 				       named_g_mctx, &dns64_impl)
    565 		      == ISC_R_SUCCESS);
    566 	return (ISC_R_SUCCESS);
    567 }
    568 
    569 void
    570 named_builtin_deinit(void) {
    571 	dns_sdb_unregister(&builtin_impl);
    572 	dns_sdb_unregister(&dns64_impl);
    573 }
    574