]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
move dns64 SDB zone implementation into module
authorEvan Hunt <each@isc.org>
Thu, 1 Nov 2018 17:11:26 +0000 (10:11 -0700)
committerEvan Hunt <each@isc.org>
Fri, 30 Aug 2019 22:25:56 +0000 (15:25 -0700)
- remove _dns64 SDB implementation from bin/named/builtin.c
  and add it to the dbs64 module implementation. load and unload a copy
  of the implementation for each instance of the dyndb module.

bin/named/builtin.c
bin/named/server.c
bin/plugins/dns64.c
lib/dns/include/dns/sdb.h
lib/dns/sdb.c
lib/ns/include/ns/hooks.h

index be0409f3f6057677b19c19fda08cfe5c6976abc2..374e3e18a1bef787042d333af6c83c79cdab95d4 100644 (file)
@@ -23,6 +23,7 @@
 #include <isc/result.h>
 #include <isc/util.h>
 
+#include <dns/db.h>
 #include <dns/result.h>
 #include <dns/sdb.h>
 
 #include <named/server.h>
 #include <named/os.h>
 
+#define CHECK(op)                                              \
+       do {                                                    \
+               result = (op);                                  \
+               if (result != ISC_R_SUCCESS) {                  \
+                       goto cleanup;                           \
+               }                                               \
+       } while (0)
+
 typedef struct builtin builtin_t;
 
 static isc_result_t do_version_lookup(dns_sdblookup_t *lookup);
@@ -38,7 +47,6 @@ static isc_result_t do_hostname_lookup(dns_sdblookup_t *lookup);
 static isc_result_t do_authors_lookup(dns_sdblookup_t *lookup);
 static isc_result_t do_id_lookup(dns_sdblookup_t *lookup);
 static isc_result_t do_empty_lookup(dns_sdblookup_t *lookup);
-static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
 
 /*
  * We can't use function pointers as the db_data directly
@@ -48,232 +56,23 @@ static isc_result_t do_dns64_lookup(dns_sdblookup_t *lookup);
 
 struct builtin {
        isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
+       isc_mem_t *mctx;
        char *server;
        char *contact;
 };
 
-static builtin_t version_builtin = { do_version_lookup,  NULL, NULL };
-static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL };
-static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL };
-static builtin_t id_builtin = { do_id_lookup, NULL, NULL };
-static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL };
-static builtin_t dns64_builtin = { do_dns64_lookup, NULL, NULL };
+static builtin_t version_builtin = { do_version_lookup, NULL, NULL, NULL };
+static builtin_t hostname_builtin = { do_hostname_lookup, NULL, NULL, NULL };
+static builtin_t authors_builtin = { do_authors_lookup, NULL, NULL, NULL };
+static builtin_t id_builtin = { do_id_lookup, NULL, NULL, NULL };
+static builtin_t empty_builtin = { do_empty_lookup, NULL, NULL, NULL };
 
 static dns_sdbimplementation_t *builtin_impl;
-static dns_sdbimplementation_t *dns64_impl;
-
-/*
- * Pre computed HEX * 16 or 1 table.
- */
-static const unsigned char hex16[256] = {
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*00*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*10*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*20*/
-        0, 16, 32, 48, 64, 80, 96,112,128,144,  1,  1,  1,  1,  1,  1, /*30*/
-        1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*40*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*50*/
-        1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*60*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*70*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*80*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*90*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*A0*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*B0*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*C0*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*D0*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*E0*/
-        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1  /*F0*/
-};
-
-const unsigned char decimal[] = "0123456789";
-
-static size_t
-dns64_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
-       size_t i, j = 0;
-
-       for (i = 0; i < 4U; i++) {
-               unsigned char c = v[start++];
-               if (start == 7U)
-                       start++;
-               if (c > 99) {
-                       rdata[j++] = 3;
-                       rdata[j++] = decimal[c/100]; c = c % 100;
-                       rdata[j++] = decimal[c/10]; c = c % 10;
-                       rdata[j++] = decimal[c];
-               } else if (c > 9) {
-                       rdata[j++] = 2;
-                       rdata[j++] = decimal[c/10]; c = c % 10;
-                       rdata[j++] = decimal[c];
-               } else {
-                       rdata[j++] = 1;
-                       rdata[j++] = decimal[c];
-               }
-       }
-       memmove(&rdata[j], "\07in-addr\04arpa", 14);
-       return (j + 14);
-}
-
-static isc_result_t
-dns64_cname(const dns_name_t *zone, const dns_name_t *name,
-           dns_sdblookup_t *lookup)
-{
-       size_t zlen, nlen, j, len;
-       unsigned char v[16], n;
-       unsigned int i;
-       unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
-       unsigned char *ndata;
-
-       /*
-        * The combined length of the zone and name is 74.
-        *
-        * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
-        *
-        * The length of name should always be even as we are expecting
-        * a series of nibbles.
-        */
-       zlen = zone->length;
-       nlen = name->length;
-       if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U)
-               return (ISC_R_NOTFOUND);
-
-       /*
-        * We assume the zone name is well formed.
-        */
-
-       /*
-        * XXXMPA We could check the dns64 suffix here if we need to.
-        */
-       /*
-        * Check that name is a series of nibbles.
-        * Compute the byte values that correspond to the nibbles as we go.
-        *
-        * Shift the final result 4 bits, by setting 'i' to 1, if we if we
-        * have a odd number of nibbles so that "must be zero" tests below
-        * are byte aligned and we correctly return ISC_R_NOTFOUND or
-        * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
-        */
-       ndata = name->ndata;
-       i = (nlen % 4) == 2U ? 1 : 0;
-       j = nlen;
-       memset(v, 0, sizeof(v));
-       while (j != 0U) {
-               INSIST((i/2) < sizeof(v));
-               if (ndata[0] != 1)
-                       return (ISC_R_NOTFOUND);
-               n = hex16[ndata[1]&0xff];
-               if (n == 1)
-                       return (ISC_R_NOTFOUND);
-               v[i/2] = n | (v[i/2]>>4);
-               j -= 2;
-               ndata += 2;
-               i++;
-       }
-
-       /*
-        * If we get here then we know name only consisted of nibbles.
-        * Now we need to determine if the name exists or not and whether
-        * it corresponds to a empty node in the zone or there should be
-        * a CNAME.
-        */
-#define ZLEN(x) (10 + (x)/2)
-       switch (zlen) {
-       case ZLEN(32):  /* prefix len 32 */
-               /*
-                * The nibbles that map to this byte must be zero for 'name'
-                * to exist in the zone.
-                */
-               if (nlen > 16U && v[(nlen-1)/4 - 4] != 0)
-                       return (ISC_R_NOTFOUND);
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 8, rdata);
-               break;
-       case ZLEN(40):  /* prefix len 40 */
-               /*
-                * The nibbles that map to this byte must be zero for 'name'
-                * to exist in the zone.
-                */
-               if (nlen > 12U && v[(nlen-1)/4 - 3] != 0)
-                       return (ISC_R_NOTFOUND);
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 6, rdata);
-               break;
-       case ZLEN(48):  /* prefix len 48 */
-               /*
-                * The nibbles that map to this byte must be zero for 'name'
-                * to exist in the zone.
-                */
-               if (nlen > 8U && v[(nlen-1)/4 - 2] != 0)
-                       return (ISC_R_NOTFOUND);
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 5, rdata);
-               break;
-       case ZLEN(56):  /* prefix len 56 */
-               /*
-                * The nibbles that map to this byte must be zero for 'name'
-                * to exist in the zone.
-                */
-               if (nlen > 4U && v[(nlen-1)/4 - 1] != 0)
-                       return (ISC_R_NOTFOUND);
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 4, rdata);
-               break;
-       case ZLEN(64):  /* prefix len 64 */
-               /*
-                * The nibbles that map to this byte must be zero for 'name'
-                * to exist in the zone.
-                */
-               if (v[(nlen-1)/4] != 0)
-                       return (ISC_R_NOTFOUND);
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 3, rdata);
-               break;
-       case ZLEN(96):  /* prefix len 96 */
-               /*
-                * If the total length is not 74 then this is a empty node
-                * so return success.
-                */
-               if (nlen + zlen != 74U)
-                       return (ISC_R_SUCCESS);
-               len = dns64_rdata(v, 0, rdata);
-               break;
-       default:
-               /*
-                * This should never be reached unless someone adds a
-                * zone declaration with this internal type to named.conf.
-                */
-               return (ISC_R_NOTFOUND);
-       }
-       return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600,
-                                rdata, (unsigned int)len));
-}
 
 static isc_result_t
-builtin_lookup(const char *zone, const char *name, void *dbdata,
-              dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
+builtin_lookup(const char *zone, const char *name,
+              void *dbdata, dns_sdblookup_t *lookup,
+              dns_clientinfomethods_t *methods,
               dns_clientinfo_t *clientinfo)
 {
        builtin_t *b = (builtin_t *) dbdata;
@@ -282,34 +81,20 @@ builtin_lookup(const char *zone, const char *name, void *dbdata,
        UNUSED(methods);
        UNUSED(clientinfo);
 
-       if (strcmp(name, "@") == 0)
+       if (strcmp(name, "@") == 0) {
                return (b->do_lookup(lookup));
-       else
+       } else {
                return (ISC_R_NOTFOUND);
-}
-
-static isc_result_t
-dns64_lookup(const dns_name_t *zone, const dns_name_t *name, void *dbdata,
-            dns_sdblookup_t *lookup, dns_clientinfomethods_t *methods,
-            dns_clientinfo_t *clientinfo)
-{
-       builtin_t *b = (builtin_t *) dbdata;
-
-       UNUSED(methods);
-       UNUSED(clientinfo);
-
-       if (name->labels == 0 && name->length == 0)
-               return (b->do_lookup(lookup));
-       else
-               return (dns64_cname(zone, name, lookup));
+       }
 }
 
 static isc_result_t
 put_txt(dns_sdblookup_t *lookup, const char *text) {
        unsigned char buf[256];
        unsigned int len = strlen(text);
-       if (len > 255)
+       if (len > 255) {
                len = 255; /* Silently truncate */
+       }
        buf[0] = len;
        memmove(&buf[1], text, len);
        return (dns_sdb_putrdata(lookup, dns_rdatatype_txt, 0, buf, len + 1));
@@ -318,10 +103,11 @@ put_txt(dns_sdblookup_t *lookup, const char *text) {
 static isc_result_t
 do_version_lookup(dns_sdblookup_t *lookup) {
        if (named_g_server->version_set) {
-               if (named_g_server->version == NULL)
+               if (named_g_server->version == NULL) {
                        return (ISC_R_SUCCESS);
-               else
+               } else {
                        return (put_txt(lookup, named_g_server->version));
+               }
        } else {
                return (put_txt(lookup, named_g_version));
        }
@@ -330,15 +116,17 @@ do_version_lookup(dns_sdblookup_t *lookup) {
 static isc_result_t
 do_hostname_lookup(dns_sdblookup_t *lookup) {
        if (named_g_server->hostname_set) {
-               if (named_g_server->hostname == NULL)
+               if (named_g_server->hostname == NULL) {
                        return (ISC_R_SUCCESS);
-               else
+               } else {
                        return (put_txt(lookup, named_g_server->hostname));
+               }
        } else {
                char buf[256];
                isc_result_t result = named_os_gethostname(buf, sizeof(buf));
-               if (result != ISC_R_SUCCESS)
+               if (result != ISC_R_SUCCESS) {
                        return (result);
+               }
                return (put_txt(lookup, buf));
        }
 }
@@ -374,13 +162,15 @@ do_authors_lookup(dns_sdblookup_t *lookup) {
        /*
         * If a version string is specified, disable the authors.bind zone.
         */
-       if (named_g_server->version_set)
+       if (named_g_server->version_set) {
                return (ISC_R_SUCCESS);
+       }
 
        for (p = authors; *p != NULL; p++) {
                result = put_txt(lookup, *p);
-               if (result != ISC_R_SUCCESS)
+               if (result != ISC_R_SUCCESS) {
                        return (result);
+               }
        }
        return (ISC_R_SUCCESS);
 }
@@ -392,24 +182,19 @@ do_id_lookup(dns_sdblookup_t *lookup) {
                isc_result_t result;
 
                result = named_g_server->sctx->gethostname(buf, sizeof(buf));
-               if (result != ISC_R_SUCCESS)
+               if (result != ISC_R_SUCCESS) {
                        return (result);
+               }
                return (put_txt(lookup, buf));
-       } else if (named_g_server->sctx->server_id != NULL)
+       } else if (named_g_server->sctx->server_id != NULL) {
                return (put_txt(lookup, named_g_server->sctx->server_id));
-       else
+       } else {
                return (ISC_R_SUCCESS);
-}
-
-static isc_result_t
-do_dns64_lookup(dns_sdblookup_t *lookup) {
-       UNUSED(lookup);
-       return (ISC_R_SUCCESS);
+       }
 }
 
 static isc_result_t
 do_empty_lookup(dns_sdblookup_t *lookup) {
-
        UNUSED(lookup);
        return (ISC_R_SUCCESS);
 }
@@ -428,48 +213,54 @@ builtin_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
                server = ".";
                contact = ".";
        } else {
-               if (b->server != NULL)
+               if (b->server != NULL) {
                        server = b->server;
-               if (b->contact != NULL)
+               }
+               if (b->contact != NULL) {
                        contact = b->contact;
+               }
        }
 
        result = dns_sdb_putsoa(lookup, server, contact, 0);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
                return (ISC_R_FAILURE);
+       }
 
        result = dns_sdb_putrr(lookup, "ns", 0, server);
-       if (result != ISC_R_SUCCESS)
+       if (result != ISC_R_SUCCESS) {
                return (ISC_R_FAILURE);
+       }
 
        return (ISC_R_SUCCESS);
 }
 
 static isc_result_t
-builtin_create(const char *zone, int argc, char **argv,
+builtin_create(const char *zone, isc_mem_t *mctx, int argc, char **argv,
               void *driverdata, void **dbdata)
 {
        REQUIRE(argc >= 1);
 
        UNUSED(zone);
+       UNUSED(mctx);
        UNUSED(driverdata);
 
-       if (strcmp(argv[0], "empty") == 0 || strcmp(argv[0], "dns64") == 0) {
-               if (argc != 3)
+       if (strcmp(argv[0], "empty") == 0) {
+               if (argc != 3) {
                        return (DNS_R_SYNTAX);
-       } else if (argc != 1)
+               }
+       } else if (argc != 1) {
                return (DNS_R_SYNTAX);
+       }
 
-       if (strcmp(argv[0], "version") == 0)
+       if (strcmp(argv[0], "version") == 0) {
                *dbdata = &version_builtin;
-       else if (strcmp(argv[0], "hostname") == 0)
+       } else if (strcmp(argv[0], "hostname") == 0) {
                *dbdata = &hostname_builtin;
-       else if (strcmp(argv[0], "authors") == 0)
+       } else if (strcmp(argv[0], "authors") == 0) {
                *dbdata = &authors_builtin;
-       else if (strcmp(argv[0], "id") == 0)
+       } else if (strcmp(argv[0], "id") == 0) {
                *dbdata = &id_builtin;
-       else if (strcmp(argv[0], "empty") == 0 ||
-                strcmp(argv[0], "dns64") == 0) {
+       } else if (strcmp(argv[0], "empty") == 0) {
                builtin_t *empty;
                char *server;
                char *contact;
@@ -481,30 +272,26 @@ builtin_create(const char *zone, int argc, char **argv,
                server = isc_mem_strdup(named_g_mctx, argv[1]);
                contact = isc_mem_strdup(named_g_mctx, argv[2]);
                if (empty == NULL || server == NULL || contact == NULL) {
-                       if (strcmp(argv[0], "empty") == 0)
-                               *dbdata = &empty_builtin;
-                       else
-                               *dbdata = &dns64_builtin;
-                       if (server != NULL)
+                       *dbdata = &empty_builtin;
+                       if (server != NULL) {
                                isc_mem_free(named_g_mctx, server);
-                       if (contact != NULL)
+                       }
+                       if (contact != NULL) {
                                isc_mem_free(named_g_mctx, contact);
-                       if (empty != NULL)
+                       }
+                       if (empty != NULL) {
                                isc_mem_put(named_g_mctx, empty,
                                            sizeof (*empty));
+                       }
                } else {
-                       if (strcmp(argv[0], "empty") == 0)
-                               memmove(empty, &empty_builtin,
-                                       sizeof (empty_builtin));
-                       else
-                               memmove(empty, &dns64_builtin,
-                                       sizeof (empty_builtin));
+                       memmove(empty, &empty_builtin, sizeof (empty_builtin));
                        empty->server = server;
                        empty->contact = contact;
                        *dbdata = empty;
                }
-       } else
+       } else {
                return (ISC_R_NOTIMPLEMENTED);
+       }
        return (ISC_R_SUCCESS);
 }
 
@@ -520,8 +307,10 @@ builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
         */
        if (*dbdata == &version_builtin || *dbdata == &hostname_builtin ||
            *dbdata == &authors_builtin || *dbdata == &id_builtin ||
-           *dbdata == &empty_builtin || *dbdata == &dns64_builtin)
+           *dbdata == &empty_builtin)
+       {
                return;
+       }
 
        isc_mem_free(named_g_mctx, b->server);
        isc_mem_free(named_g_mctx, b->contact);
@@ -531,21 +320,12 @@ builtin_destroy(const char *zone, void *driverdata, void **dbdata) {
 static dns_sdbmethods_t builtin_methods = {
        builtin_lookup,
        builtin_authority,
-       NULL,           /* allnodes */
+       NULL,           /* allnodes */
        builtin_create,
        builtin_destroy,
        NULL
 };
 
-static dns_sdbmethods_t dns64_methods = {
-       NULL,
-       builtin_authority,
-       NULL,           /* allnodes */
-       builtin_create,
-       builtin_destroy,
-       dns64_lookup,
-};
-
 isc_result_t
 named_builtin_init(void) {
        RUNTIME_CHECK(dns_sdb_register("_builtin", &builtin_methods, NULL,
@@ -553,17 +333,10 @@ named_builtin_init(void) {
                                       DNS_SDBFLAG_RELATIVERDATA,
                                       named_g_mctx, &builtin_impl)
                      == ISC_R_SUCCESS);
-       RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
-                                      DNS_SDBFLAG_RELATIVEOWNER |
-                                      DNS_SDBFLAG_RELATIVERDATA |
-                                      DNS_SDBFLAG_DNS64,
-                                      named_g_mctx, &dns64_impl)
-                     == ISC_R_SUCCESS);
        return (ISC_R_SUCCESS);
 }
 
 void
 named_builtin_deinit(void) {
        dns_sdb_unregister(&builtin_impl);
-       dns_sdb_unregister(&dns64_impl);
 }
index d63d32f97d418fa433a42c448be331bafb625e08..e20cbd9bb98ed605e65d37c3e491bbc58a810da3 100644 (file)
@@ -85,6 +85,7 @@
 #include <dns/resolver.h>
 #include <dns/rootns.h>
 #include <dns/rriterator.h>
+#include <dns/sdb.h>
 #include <dns/secalg.h>
 #include <dns/soa.h>
 #include <dns/stats.h>
index 7e37deffac294c0fb5ea599305f6c3b853206315..45df0bb2db2a7e93aacef0a8c0874c5c282dd319 100644 (file)
@@ -48,6 +48,7 @@
 #include <dns/rdataset.h>
 #include <dns/rdatalist.h>
 #include <dns/result.h>
+#include <dns/sdb.h>
 #include <dns/types.h>
 #include <dns/view.h>
 #include <dns/zone.h>
@@ -121,7 +122,6 @@ typedef enum {
  * accessible until the client object is detached.
  */
 
-
 typedef struct dns64_data {
        dns_rdataset_t *aaaa;
        dns_rdataset_t *sigaaaa;
@@ -145,6 +145,11 @@ typedef struct dns64_instance {
         */
        isc_ht_t *ht;
 
+       /*
+        * SDB DNS64 database implementation.
+        */
+       dns_sdbimplementation_t *dns64_impl;
+
        dns_acl_t *dns64_mapped;
        dns64list_t dns64list;
        unsigned int dns64cnt;
@@ -248,7 +253,6 @@ install_hooks(ns_hooktable_t *hooktable, isc_mem_t *mctx,
                    NS_QUERY_NODATA_BEGIN, &dns64_nodata);
        ns_hook_add(hooktable, mctx,
                    NS_QUERY_QCTX_DESTROYED, &dns64_destroy);
-
 }
 
 /**
@@ -543,6 +547,366 @@ parse_parameters(dns64_instance_t *inst, const char *parameters,
        return (result);
 }
 
+/**
+ ** DNS64 SDB zone implementation starts here
+ **/
+
+typedef struct builtin {
+       isc_result_t (*do_lookup)(dns_sdblookup_t *lookup);
+       isc_mem_t *mctx;
+       char *server;
+       char *contact;
+} builtin_t;
+
+static isc_result_t dns64_zone_dolookup(dns_sdblookup_t *lookup);
+static builtin_t dns64_builtin = { dns64_zone_dolookup, NULL, NULL, NULL };
+
+/*
+ * Pre computed HEX * 16 or 1 table.
+ */
+static const unsigned char hex16[256] = {
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*00*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*10*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*20*/
+        0, 16, 32, 48, 64, 80, 96,112,128,144,  1,  1,  1,  1,  1,  1, /*30*/
+        1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*40*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*50*/
+        1,160,176,192,208,224,240,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*60*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*70*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*80*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*90*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*A0*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*B0*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*C0*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*D0*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, /*E0*/
+        1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1  /*F0*/
+};
+
+const unsigned char decimal[] = "0123456789";
+
+static size_t
+dns64_zone_rdata(unsigned char *v, size_t start, unsigned char *rdata) {
+       size_t i, j = 0;
+
+       for (i = 0; i < 4U; i++) {
+               unsigned char c = v[start++];
+               if (start == 7U) {
+                       start++;
+               }
+               if (c > 99) {
+                       rdata[j++] = 3;
+                       rdata[j++] = decimal[c / 100]; c = c % 100;
+                       rdata[j++] = decimal[c / 10]; c = c % 10;
+                       rdata[j++] = decimal[c];
+               } else if (c > 9) {
+                       rdata[j++] = 2;
+                       rdata[j++] = decimal[c / 10]; c = c % 10;
+                       rdata[j++] = decimal[c];
+               } else {
+                       rdata[j++] = 1;
+                       rdata[j++] = decimal[c];
+               }
+       }
+       memmove(&rdata[j], "\07in-addr\04arpa", 14);
+       return (j + 14);
+}
+
+static isc_result_t
+dns64_zone_cname(const dns_name_t *zone,
+           const dns_name_t *name,
+           dns_sdblookup_t *lookup)
+{
+       size_t zlen, nlen, j, len;
+       unsigned char v[16], n;
+       unsigned int i;
+       unsigned char rdata[sizeof("123.123.123.123.in-addr.arpa.")];
+       unsigned char *ndata;
+
+       /*
+        * The combined length of the zone and name is 74.
+        *
+        * The minimum zone length is 10 ((3)ip6(4)arpa(0)).
+        *
+        * The length of name should always be even as we are expecting
+        * a series of nibbles.
+        */
+       zlen = zone->length;
+       nlen = name->length;
+       if ((zlen + nlen) > 74U || zlen < 10U || (nlen % 2) != 0U) {
+               return (ISC_R_NOTFOUND);
+       }
+
+       /*
+        * We assume the zone name is well formed.
+        */
+
+       /*
+        * XXXMPA We could check the dns64 suffix here if we need to.
+        */
+       /*
+        * Check that name is a series of nibbles.
+        * Compute the byte values that correspond to the nibbles as we go.
+        *
+        * Shift the final result 4 bits, by setting 'i' to 1, if we if we
+        * have a odd number of nibbles so that "must be zero" tests below
+        * are byte aligned and we correctly return ISC_R_NOTFOUND or
+        * ISC_R_SUCCESS.  We will not generate a CNAME in this case.
+        */
+       ndata = name->ndata;
+       i = (nlen % 4) == 2U ? 1 : 0;
+       j = nlen;
+       memset(v, 0, sizeof(v));
+       while (j != 0U) {
+               INSIST((i / 2) < sizeof(v));
+               if (ndata[0] != 1) {
+                       return (ISC_R_NOTFOUND);
+               }
+               n = hex16[ndata[1] & 0xff];
+               if (n == 1) {
+                       return (ISC_R_NOTFOUND);
+               }
+               v[i / 2] = n | (v[i / 2] >> 4);
+               j -= 2;
+               ndata += 2;
+               i++;
+       }
+
+       /*
+        * If we get here then we know name only consisted of nibbles.
+        * Now we need to determine if the name exists or not and whether
+        * it corresponds to a empty node in the zone or there should be
+        * a CNAME.
+        */
+#define ZLEN(x) (10 + (x) / 2)
+       switch (zlen) {
+       case ZLEN(32):  /* prefix len 32 */
+               /*
+                * The nibbles that map to this byte must be zero for 'name'
+                * to exist in the zone.
+                */
+               if (nlen > 16U && v[(nlen - 1) / 4 - 4] != 0) {
+                       return (ISC_R_NOTFOUND);
+               }
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 8, rdata);
+               break;
+       case ZLEN(40):  /* prefix len 40 */
+               /*
+                * The nibbles that map to this byte must be zero for 'name'
+                * to exist in the zone.
+                */
+               if (nlen > 12U && v[(nlen - 1) / 4 - 3] != 0) {
+                       return (ISC_R_NOTFOUND);
+               }
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 6, rdata);
+               break;
+       case ZLEN(48):  /* prefix len 48 */
+               /*
+                * The nibbles that map to this byte must be zero for 'name'
+                * to exist in the zone.
+                */
+               if (nlen > 8U && v[(nlen - 1) / 4 - 2] != 0) {
+                       return (ISC_R_NOTFOUND);
+               }
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 5, rdata);
+               break;
+       case ZLEN(56):  /* prefix len 56 */
+               /*
+                * The nibbles that map to this byte must be zero for 'name'
+                * to exist in the zone.
+                */
+               if (nlen > 4U && v[(nlen - 1) / 4 - 1] != 0) {
+                       return (ISC_R_NOTFOUND);
+               }
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 4, rdata);
+               break;
+       case ZLEN(64):  /* prefix len 64 */
+               /*
+                * The nibbles that map to this byte must be zero for 'name'
+                * to exist in the zone.
+                */
+               if (v[(nlen - 1) / 4] != 0) {
+                       return (ISC_R_NOTFOUND);
+               }
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 3, rdata);
+               break;
+       case ZLEN(96):  /* prefix len 96 */
+               /*
+                * If the total length is not 74 then this is a empty node
+                * so return success.
+                */
+               if (nlen + zlen != 74U) {
+                       return (ISC_R_SUCCESS);
+               }
+               len = dns64_zone_rdata(v, 0, rdata);
+               break;
+       default:
+               /*
+                * This should never be reached unless someone adds a
+                * zone declaration with this internal type to named.conf.
+                */
+               return (ISC_R_NOTFOUND);
+       }
+       return (dns_sdb_putrdata(lookup, dns_rdatatype_cname, 600,
+                                rdata, (unsigned int)len));
+}
+
+static isc_result_t
+dns64_zone_lookup(const dns_name_t *zone, const dns_name_t *name,
+            void *dbdata, dns_sdblookup_t *lookup,
+            dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo)
+{
+       builtin_t *b = (builtin_t *) dbdata;
+
+       UNUSED(methods);
+       UNUSED(clientinfo);
+
+       if (name->labels == 0 && name->length == 0) {
+               return (b->do_lookup(lookup));
+       } else {
+               return (dns64_zone_cname(zone, name, lookup));
+       }
+}
+
+static isc_result_t
+dns64_zone_dolookup(dns_sdblookup_t *lookup) {
+       UNUSED(lookup);
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dns64_zone_create(const char *zone, isc_mem_t *mctx, int argc, char **argv,
+            void *driverdata, void **dbdata)
+{
+       builtin_t *dns64;
+       char *server;
+       char *contact;
+
+       UNUSED(zone);
+       UNUSED(driverdata);
+
+       if (argc != 3) {
+               return (DNS_R_SYNTAX);
+       }
+
+       dns64 = isc_mem_get(mctx, sizeof(*dns64));
+       server = isc_mem_strdup(mctx, argv[1]);
+       contact = isc_mem_strdup(mctx, argv[2]);
+       if (dns64 == NULL || server == NULL || contact == NULL) {
+               *dbdata = &dns64_builtin;
+               if (server != NULL) {
+                       isc_mem_free(mctx, server);
+               }
+               if (contact != NULL) {
+                       isc_mem_free(mctx, contact);
+               }
+               if (dns64 != NULL) {
+                       isc_mem_put(mctx, dns64, sizeof (*dns64));
+               }
+       } else {
+               memmove(dns64, &dns64_builtin, sizeof (dns64_builtin));
+               isc_mem_attach(mctx, &dns64->mctx);
+               dns64->server = server;
+               dns64->contact = contact;
+               *dbdata = dns64;
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+dns64_zone_authority(const char *zone, void *dbdata, dns_sdblookup_t *lookup) {
+       isc_result_t result;
+       const char *contact = "hostmaster";
+       const char *server = "@";
+       builtin_t *b = (builtin_t *) dbdata;
+
+       UNUSED(zone);
+       UNUSED(dbdata);
+
+       if (b->server != NULL) {
+               server = b->server;
+       }
+       if (b->contact != NULL) {
+               contact = b->contact;
+       }
+
+       result = dns_sdb_putsoa(lookup, server, contact, 0);
+       if (result != ISC_R_SUCCESS) {
+               return (ISC_R_FAILURE);
+       }
+
+       result = dns_sdb_putrr(lookup, "ns", 0, server);
+       if (result != ISC_R_SUCCESS) {
+               return (ISC_R_FAILURE);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+dns64_zone_destroy(const char *zone, void *driverdata, void **dbdata) {
+       builtin_t *b = (builtin_t *) *dbdata;
+
+       UNUSED(zone);
+       UNUSED(driverdata);
+
+       /*
+        * Don't free the static versions.
+        */
+       if (*dbdata == &dns64_builtin) {
+               return;
+       }
+
+       isc_mem_free(b->mctx, b->server);
+       isc_mem_free(b->mctx, b->contact);
+       isc_mem_putanddetach(&b->mctx, b, sizeof(*b));
+}
+
+static dns_sdbmethods_t dns64_methods = {
+       NULL,
+       dns64_zone_authority,
+       NULL,           /* allnodes */
+       dns64_zone_create,
+       dns64_zone_destroy,
+       dns64_zone_lookup,
+};
+
 /**
  ** Mandatory plugin API functions:
  **
@@ -575,6 +939,19 @@ plugin_register(const char *parameters,
        memset(inst, 0, sizeof(*inst));
        isc_mem_attach(mctx, &inst->mctx);
 
+       /*
+        * Set up dns64 SDB implementation.
+        */
+       RUNTIME_CHECK(dns_sdb_register("_dns64", &dns64_methods, NULL,
+                                      DNS_SDBFLAG_RELATIVEOWNER |
+                                      DNS_SDBFLAG_RELATIVERDATA |
+                                      DNS_SDBFLAG_DNS64,
+                                      mctx, &inst->dns64_impl)
+                     == ISC_R_SUCCESS);
+
+       /*
+        * Parse parameters.
+        */
        if (parameters != NULL) {
                CHECK(parse_parameters(inst, parameters,
                                       cfg, cfg_file, cfg_line,
@@ -634,6 +1011,8 @@ plugin_destroy(void **instp) {
        dns64_instance_t *inst = (dns64_instance_t *) *instp;
        dns64_t *dns64 = NULL;
 
+       dns_sdb_unregister(&inst->dns64_impl);
+
        if (inst->ht != NULL) {
                isc_ht_destroy(&inst->ht);
        }
@@ -660,6 +1039,19 @@ plugin_destroy(void **instp) {
        return;
 }
 
+/*
+ * Returns plugin API version for compatibility checks.
+ */
+int
+plugin_version(void) {
+       return (NS_PLUGIN_VERSION);
+}
+
+
+/*
+ * Helper function to get persistent state information based on
+ * the client address.
+ */
 static dns64_data_t *
 client_state_get(const ns_client_t *client, dns64_instance_t *inst) {
        dns64_data_t *client_state = NULL;
@@ -671,6 +1063,10 @@ client_state_get(const ns_client_t *client, dns64_instance_t *inst) {
        return (result == ISC_R_SUCCESS ? client_state : NULL);
 }
 
+/*
+ * Helper function to create persistent state information based on
+ * the client address.
+ */
 static void
 client_state_create(const ns_client_t *client, dns64_instance_t *inst) {
        dns64_data_t *client_state;
@@ -694,6 +1090,10 @@ client_state_create(const ns_client_t *client, dns64_instance_t *inst) {
        RUNTIME_CHECK(result == ISC_R_SUCCESS);
 }
 
+/*
+ * Helper function to delete persistent state information based on
+ * the client address.
+ */
 static void
 client_state_destroy(const ns_client_t *client, dns64_instance_t *inst) {
        dns64_data_t *client_state = client_state_get(client, inst);
@@ -710,14 +1110,6 @@ client_state_destroy(const ns_client_t *client, dns64_instance_t *inst) {
        isc_mempool_put(inst->datapool, client_state);
 }
 
-/*
- * Returns plugin API version for compatibility checks.
- */
-int
-plugin_version(void) {
-       return (NS_PLUGIN_VERSION);
-}
-
 /**
  ** DNS64 data structure implementation starts here
  **/
index c033b60d40c82d245cd921a3bbbe23c072bd0150..72bde1c7ab89625f68c901b1f151bf97e12fd612 100644 (file)
@@ -71,7 +71,8 @@ typedef isc_result_t
                         dns_sdballnodes_t *allnodes);
 
 typedef isc_result_t
-(*dns_sdbcreatefunc_t)(const char *zone, int argc, char **argv,
+(*dns_sdbcreatefunc_t)(const char *zone, isc_mem_t *mctx,
+                      int argc, char **argv,
                       void *driverdata, void **dbdata);
 
 typedef void
@@ -98,6 +99,13 @@ ISC_LANG_BEGINDECLS
 #define DNS_SDBFLAG_THREADSAFE 0x00000004U
 #define DNS_SDBFLAG_DNS64 0x00000008U
 
+typedef isc_result_t
+(*dns_sdbregister_t)(const char *drivername, const dns_sdbmethods_t *methods,
+                    void *driverdata, unsigned int flags, isc_mem_t *mctx,
+                    dns_sdbimplementation_t **sdbimp);
+typedef void
+(*dns_sdbunregister_t)(dns_sdbimplementation_t **sdbimp);
+
 isc_result_t
 dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
                 void *driverdata, unsigned int flags, isc_mem_t *mctx,
index e7683a79184e9961cdb31b60370923e9cb4d3954..4f884b0e22a76a8f2947e006245afb09c9b949b1 100644 (file)
@@ -1367,7 +1367,7 @@ dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
        sdb->dbdata = NULL;
        if (imp->methods->create != NULL) {
                MAYBE_LOCK(sdb);
-               result = imp->methods->create(sdb->zone, argc, argv,
+               result = imp->methods->create(sdb->zone, mctx, argc, argv,
                                              imp->driverdata, &sdb->dbdata);
                MAYBE_UNLOCK(sdb);
                if (result != ISC_R_SUCCESS)
index 302c54da9344007fee32865ca74007d66710313e..669d18cfa2d634d9c3a7792da1f281184b54b5f8 100644 (file)
@@ -21,6 +21,7 @@
 #include <isc/result.h>
 
 #include <dns/rdatatype.h>
+#include <dns/sdb.h>
 
 #include <ns/client.h>
 #include <ns/query.h>