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