builtin.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2009-2014  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2001-2003  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id: builtin.c,v 1.26 2012/01/21 19:44:18 each Exp $ */
00019 
00020 /*! \file
00021  * \brief
00022  * The built-in "version", "hostname", "id", "authors" and "empty" databases.
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include <string.h>
00028 #include <stdio.h>
00029 
00030 #include <isc/mem.h>
00031 #include <isc/print.h>
00032 #include <isc/result.h>
00033 #include <isc/util.h>
00034 
00035 #include <dns/result.h>
00036 #include <dns/sdb.h>
00037 
00038 #include <named/builtin.h>
00039 #include <named/globals.h>
00040 #include <named/server.h>
00041 #include <named/os.h>
00042 
00043 typedef struct builtin builtin_t;
00044 
00045 static isc_result_t do_version_lookup(dns_sdblookup_t *lookup);
00046 static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup);
00047 static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup);
00048 static isc_result_t do_id_lookup(dns_sdblookup_t *lookup);
00049 static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup);
00050 static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
00051 
00052 /*
00053  * We can't use function pointers as the db_data directly
00054  * because ANSI C does not guarantee that function pointers
00055  * can safely be cast to void pointers and back.
00056  */
00057 
00058 struct builtin {
00059         isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
00060         char *server;
00061         char *contact;
00062 };
00063 
00064 static builtin_t version_builtin = { do_version_lookup,  NULL, NULL };
00065 static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL };
00066 static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL };
00067 static builtin_t id_builtin = { do_id_lookup, NULL, NULL };
00068 static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
00069 static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
00070 
00071 static dns_sdbimplementation_t *builtin_impl;
00072 static dns_sdbimplementation_t *dns64_impl;
00073 
00074 /*
00075  * Pre computed HEX * 16 or 1 table.
00076  */
00077 static const unsigned char hex16[256] = {
00078          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*00*/
00079          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*10*/
00080          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*20*/
00081          0, 16, 32, 48, 64, 80, 96,112,128,144,  1,  1,  1,  1,  1,  1, /*30*/
00082          1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*40*/
00083          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*50*/
00084          1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*60*/
00085          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*70*/
00086          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*80*/
00087          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*90*/
00088          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*A0*/
00089          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*B0*/
00090          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*C0*/
00091          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*D0*/
00092          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*E0*/
00093          1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1  /*F0*/
00094 };
00095 
00096 const unsigned char decimal[] = "0123456789";
00097 
00098 static size_t
00099 dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
00100         size_t i, j = 0;
00101 
00102         for (i = 0; i < 4U; i++) {
00103                 unsigned char c = v[start++];
00104                 if (start == 7U)
00105                         start++;
00106                 if (c > 99) {
00107                         rdata[j++] = 3;
00108                         rdata[j++] = decimal[c/100]; c = c % 100;
00109                         rdata[j++] = decimal[c/10]; c = c % 10;
00110                         rdata[j++] = decimal[c];
00111                 } else if (c > 9) {
00112                         rdata[j++] = 2;
00113                         rdata[j++] = decimal[c/10]; c = c % 10;
00114                         rdata[j++] = decimal[c];
00115                 } else {
00116                         rdata[j++] = 1;
00117                         rdata[j++] = decimal[c];
00118                 }
00119         }
00120         memmove(&rdata[j], "\07in-addr\04arpa", 14);
00121         return (j + 14);
00122 }
00123 
00124 static isc_result_t
00125 dns64_cname(const dns_name_t *zone, const dns_name_t *name,
00126             dns_sdblookup_t *lookup)
00127 {
00128         size_t zlen, nlen, j, len;
00129         unsigned char v[16], n;
00130         unsigned int i;
00131         unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
00132         unsigned char *ndata;
00133 
00134         /*
00135          * The combined length of the zone and name is 74.
00136          *
00137          * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
00138          *
00139          * The length of name should always be even as we are expecting
00140          * a series of nibbles.
00141          */
00142         zlen = zone->length;
00143         nlen = name->length;
00144         if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
00145                 return (ISC_R_NOTFOUND);
00146 
00147         /*
00148          * We assume the zone name is well formed.
00149          */
00150 
00151         /*
00152          * XXXMPA We could check the dns64 suffix here if we need to.
00153          */
00154         /*
00155          * Check that name is a series of nibbles.
00156          * Compute the byte values that correspond to the nibbles as we go.
00157          *
00158          * Shift the final result 4 bits, by setting 'i' to 1, if we if we
00159          * have a odd number of nibbles so that "must be zero" tests below
00160          * are byte aligned and we correctly return ISC_R_NOTFOUND or
00161          * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
00162          */
00163         ndata = name->ndata;
00164         i = (nlen % 4) == 2U ? 1 : 0;
00165         j = nlen;
00166         memset(v, 0, sizeof(v));
00167         while (j != 0U) {
00168                 INSIST((i/2) < sizeof(v));
00169                 if (ndata[0] != 1)
00170                         return (ISC_R_NOTFOUND);
00171                 n = hex16[ndata[1]&0xff];
00172                 if (n == 1)
00173                         return (ISC_R_NOTFOUND);
00174                 v[i/2] = n | (v[i/2]>>4);
00175                 j -= 2;
00176                 ndata += 2;
00177                 i++;
00178         }
00179 
00180         /*
00181          * If we get here then we know name only consisted of nibbles.
00182          * Now we need to determine if the name exists or not and whether
00183          * it corresponds to a empty node in the zone or there should be
00184          * a CNAME.
00185          */
00186 #define ZLEN(x) (10 + (x)/2)
00187         switch (zlen) {
00188         case ZLEN(32):  /* prefix len 32 */
00189                 /*
00190                  * The nibbles that map to this byte must be zero for 'name'
00191                  * to exist in the zone.
00192                  */
00193                 if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
00194                         return (ISC_R_NOTFOUND);
00195                 /*
00196                  * If the total length is not 74 then this is a empty node
00197                  * so return success.
00198                  */
00199                 if (nlen + zlen != 74U)
00200                         return (ISC_R_SUCCESS);
00201                 len = dns64_rdata(v, 8, rdata);
00202                 break;
00203         case ZLEN(40):  /* prefix len 40 */
00204                 /*
00205                  * The nibbles that map to this byte must be zero for 'name'
00206                  * to exist in the zone.
00207                  */
00208                 if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
00209                         return (ISC_R_NOTFOUND);
00210                 /*
00211                  * If the total length is not 74 then this is a empty node
00212                  * so return success.
00213                  */
00214                 if (nlen + zlen != 74U)
00215                         return (ISC_R_SUCCESS);
00216                 len = dns64_rdata(v, 6, rdata);
00217                 break;
00218         case ZLEN(48):  /* prefix len 48 */
00219                 /*
00220                  * The nibbles that map to this byte must be zero for 'name'
00221                  * to exist in the zone.
00222                  */
00223                 if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
00224                         return (ISC_R_NOTFOUND);
00225                 /*
00226                  * If the total length is not 74 then this is a empty node
00227                  * so return success.
00228                  */
00229                 if (nlen + zlen != 74U)
00230                         return (ISC_R_SUCCESS);
00231                 len = dns64_rdata(v, 5, rdata);
00232                 break;
00233         case ZLEN(56):  /* prefix len 56 */
00234                 /*
00235                  * The nibbles that map to this byte must be zero for 'name'
00236                  * to exist in the zone.
00237                  */
00238                 if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
00239                         return (ISC_R_NOTFOUND);
00240                 /*
00241                  * If the total length is not 74 then this is a empty node
00242                  * so return success.
00243                  */
00244                 if (nlen + zlen != 74U)
00245                         return (ISC_R_SUCCESS);
00246                 len = dns64_rdata(v, 4, rdata);
00247                 break;
00248         case ZLEN(64):  /* prefix len 64 */
00249                 /*
00250                  * The nibbles that map to this byte must be zero for 'name'
00251                  * to exist in the zone.
00252                  */
00253                 if (v[(nlen-1)/4] != 0)
00254                         return (ISC_R_NOTFOUND);
00255                 /*
00256                  * If the total length is not 74 then this is a empty node
00257                  * so return success.
00258                  */
00259                 if (nlen + zlen != 74U)
00260                         return (ISC_R_SUCCESS);
00261                 len = dns64_rdata(v, 3, rdata);
00262                 break;
00263         case ZLEN(96):  /* prefix len 96 */
00264                 /*
00265                  * If the total length is not 74 then this is a empty node
00266                  * so return success.
00267                  */
00268                 if (nlen + zlen != 74U)
00269                         return (ISC_R_SUCCESS);
00270                 len = dns64_rdata(v, 0, rdata);
00271                 break;
00272         default:
00273                 /*
00274                  * This should never be reached unless someone adds a
00275                  * zone declaration with this internal type to named.conf.
00276                  */
00277                 return (ISC_R_NOTFOUND);
00278         }
00279         return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600,
00280                                  rdata, (unsigned int)len));
00281 }
00282 
00283 static isc_result_t
00284 builtin_lookup(const char *zone, const char *name, void *dbdata,
00285                dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
00286                dns_clientinfo_t *clientinfo)
00287 {
00288         builtin_t *b = (builtin_t *) dbdata;
00289 
00290         UNUSED(zone);
00291         UNUSED(methods);
00292         UNUSED(clientinfo);
00293 
00294         if (strcmp(name, "@") == 0)
00295                 return (b->do_lookup(lookup));
00296         else
00297                 return (ISC_R_NOTFOUND);
00298 }
00299 
00300 static isc_result_t
00301 dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
00302              dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
00303              dns_clientinfo_t *clientinfo)
00304 {
00305         builtin_t *b = (builtin_t *) dbdata;
00306 
00307         UNUSED(methods);
00308         UNUSED(clientinfo);
00309 
00310         if (name->labels == 0 && name->length == 0)
00311                 return (b->do_lookup(lookup));
00312         else
00313                 return (dns64_cname(zone, name, lookup));
00314 }
00315 
00316 static isc_result_t
00317 put_txt(dns_sdblookup_t *lookup, const char *text) {
00318         unsigned char buf[256];
00319         unsigned int len = strlen(text);
00320         if (len > 255)
00321                 len = 255; /* Silently truncate */
00322         buf[0] = len;
00323         memmove(&buf[1], text, len);
00324         return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
00325 }
00326 
00327 static isc_result_t
00328 do_version_lookup(dns_sdblookup_t *lookup) {
00329         if (ns_g_server->version_set) {
00330                 if (ns_g_server->version == NULL)
00331                         return (ISC_R_SUCCESS);
00332                 else
00333                         return (put_txt(lookup, ns_g_server->version));
00334         } else {
00335                 return (put_txt(lookup, ns_g_version));
00336         }
00337 }
00338 
00339 static isc_result_t
00340 do_hostname_lookup(dns_sdblookup_t *lookup) {
00341         if (ns_g_server->hostname_set) {
00342                 if (ns_g_server->hostname == NULL)
00343                         return (ISC_R_SUCCESS);
00344                 else
00345                         return (put_txt(lookup, ns_g_server->hostname));
00346         } else {
00347                 char buf[256];
00348                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
00349                 if (result != ISC_R_SUCCESS)
00350                         return (result);
00351                 return (put_txt(lookup, buf));
00352         }
00353 }
00354 
00355 static isc_result_t
00356 do_authors_lookup(dns_sdblookup_t *lookup) {
00357         isc_result_t result;
00358         const char **p;
00359         static const char *authors[] = {
00360                 "Mark Andrews",
00361                 "Curtis Blackburn",
00362                 "James Brister",
00363                 "Ben Cottrell",
00364                 "John H. DuBois III",
00365                 "Francis Dupont",
00366                 "Michael Graff",
00367                 "Andreas Gustafsson",
00368                 "Bob Halley",
00369                 "Evan Hunt",
00370                 "JINMEI Tatuya",
00371                 "David Lawrence",
00372                 "Scott Mann",
00373                 "Danny Mayer",
00374                 "Damien Neil",
00375                 "Matt Nelson",
00376                 "Jeremy C. Reed",
00377                 "Michael Sawyer",
00378                 "Brian Wellington",
00379                 NULL
00380         };
00381 
00382         /*
00383          * If a version string is specified, disable the authors.bind zone.
00384          */
00385         if (ns_g_server->version_set)
00386                 return (ISC_R_SUCCESS);
00387 
00388         for (p = authors; *p != NULL; p++) {
00389                 result = put_txt(lookup, *p);
00390                 if (result != ISC_R_SUCCESS)
00391                         return (result);
00392         }
00393         return (ISC_R_SUCCESS);
00394 }
00395 
00396 static isc_result_t
00397 do_id_lookup(dns_sdblookup_t *lookup) {
00398 
00399         if (ns_g_server->server_usehostname) {
00400                 char buf[256];
00401                 isc_result_t result = ns_os_gethostname(buf, sizeof(buf));
00402                 if (result != ISC_R_SUCCESS)
00403                         return (result);
00404                 return (put_txt(lookup, buf));
00405         }
00406 
00407         if (ns_g_server->server_id == NULL)
00408                 return (ISC_R_SUCCESS);
00409         else
00410                 return (put_txt(lookup, ns_g_server->server_id));
00411 }
00412 
00413 static isc_result_t
00414 do_dns64_lookup(dns_sdblookup_t *lookup) {
00415         UNUSED(lookup);
00416         return (ISC_R_SUCCESS);
00417 }
00418 
00419 static isc_result_t
00420 do_empty_lookup(dns_sdblookup_t *lookup) {
00421 
00422         UNUSED(lookup);
00423         return (ISC_R_SUCCESS);
00424 }
00425 
00426 static isc_result_t
00427 builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
00428         isc_result_t result;
00429         const char *contact = "hostmaster";
00430         const char *server = "@";
00431         builtin_t *b = (builtin_t *) dbdata;
00432 
00433         UNUSED(zone);
00434         UNUSED(dbdata);
00435 
00436         if (b == &empty_builtin) {
00437                 server = ".";
00438                 contact = ".";
00439         } else {
00440                 if (b->server != NULL)
00441                         server = b->server;
00442                 if (b->contact != NULL)
00443                         contact = b->contact;
00444         }
00445 
00446         result = dns_sdb_putsoa(lookup, server, contact, 0);
00447         if (result != ISC_R_SUCCESS)
00448                 return (ISC_R_FAILURE);
00449 
00450         result = dns_sdb_putrr(lookup, "ns", 0, server);
00451         if (result != ISC_R_SUCCESS)
00452                 return (ISC_R_FAILURE);
00453 
00454         return (ISC_R_SUCCESS);
00455 }
00456 
00457 static isc_result_t
00458 builtin_create(const char *zone, int argc, char **argv,
00459                void *driverdata, void **dbdata)
00460 {
00461         REQUIRE(argc >= 1);
00462 
00463         UNUSED(zone);
00464         UNUSED(driverdata);
00465 
00466         if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
00467                 if (argc != 3)
00468                         return (DNS_R_SYNTAX);
00469         } else if (argc != 1)
00470                 return (DNS_R_SYNTAX);
00471 
00472         if (strcmp(argv[0], "version") == 0)
00473                 *dbdata = &version_builtin;
00474         else if (strcmp(argv[0], "hostname") == 0)
00475                 *dbdata = &hostname_builtin;
00476         else if (strcmp(argv[0], "authors") == 0)
00477                 *dbdata = &authors_builtin;
00478         else if (strcmp(argv[0], "id") == 0)
00479                 *dbdata = &id_builtin;
00480         else if (strcmp(argv[0], "empty") == 0 ||
00481                  strcmp(argv[0], "dns64") == 0) {
00482                 builtin_t *empty;
00483                 char *server;
00484                 char *contact;
00485                 /*
00486                  * We don't want built-in zones to fail.  Fallback to
00487                  * the static configuration if memory allocation fails.
00488                  */
00489                 empty = isc_mem_get(ns_g_mctx, sizeof(*empty));
00490                 server = isc_mem_strdup(ns_g_mctx, argv[1]);
00491                 contact = isc_mem_strdup(ns_g_mctx, argv[2]);
00492                 if (empty == NULL || server == NULL || contact == NULL) {
00493                         if (strcmp(argv[0], "empty") == 0)
00494                                 *dbdata = &empty_builtin;
00495                         else
00496                                 *dbdata = &dns64_builtin;
00497                         if (server != NULL)
00498                                 isc_mem_free(ns_g_mctx, server);
00499                         if (contact != NULL)
00500                                 isc_mem_free(ns_g_mctx, contact);
00501                         if (empty != NULL)
00502                                 isc_mem_put(ns_g_mctx, empty, sizeof (*empty));
00503                 } else {
00504                         if (strcmp(argv[0], "empty") == 0)
00505                                 memmove(empty, &empty_builtin,
00506                                         sizeof (empty_builtin));
00507                         else
00508                                 memmove(empty, &dns64_builtin,
00509                                         sizeof (empty_builtin));
00510                         empty->server = server;
00511                         empty->contact = contact;
00512                         *dbdata = empty;
00513                 }
00514         } else
00515                 return (ISC_R_NOTIMPLEMENTED);
00516         return (ISC_R_SUCCESS);
00517 }
00518 
00519 static void
00520 builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
00521         builtin_t *b = (builtin_t *) *dbdata;
00522 
00523         UNUSED(zone);
00524         UNUSED(driverdata);
00525 
00526         /*
00527          * Don't free the static versions.
00528          */
00529         if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
00530             *dbdata == &authors_builtin || *dbdata == &id_builtin ||
00531             *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
00532                 return;
00533 
00534         isc_mem_free(ns_g_mctx, b->server);
00535         isc_mem_free(ns_g_mctx, b->contact);
00536         isc_mem_put(ns_g_mctx, b, sizeof (*b));
00537 }
00538 
00539 static dns_sdbmethods_t builtin_methods = {
00540         builtin_lookup,
00541         builtin_authority,
00542         NULL,           /* allnodes */
00543         builtin_create,
00544         builtin_destroy,
00545         NULL
00546 };
00547 
00548 static dns_sdbmethods_t dns64_methods = {
00549         NULL,
00550         builtin_authority,
00551         NULL,           /* allnodes */
00552         builtin_create,
00553         builtin_destroy,
00554         dns64_lookup,
00555 };
00556 
00557 isc_result_t
00558 ns_builtin_init(void) {
00559         RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
00560                                        DNS_SDBFLAG_RELATIVEOWNER |
00561                                        DNS_SDBFLAG_RELATIVERDATA,
00562                                        ns_g_mctx, &builtin_impl)
00563                       == ISC_R_SUCCESS);
00564         RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
00565                                        DNS_SDBFLAG_RELATIVEOWNER |
00566                                        DNS_SDBFLAG_RELATIVERDATA |
00567                                        DNS_SDBFLAG_DNS64,
00568                                        ns_g_mctx, &dns64_impl)
00569                       == ISC_R_SUCCESS);
00570         return (ISC_R_SUCCESS);
00571 }
00572 
00573 void
00574 ns_builtin_deinit(void) {
00575         dns_sdb_unregister(&builtin_impl);
00576         dns_sdb_unregister(&dns64_impl);
00577 }

Generated on Tue Apr 28 17:40:53 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha