dns: static records
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Thu, 7 Jun 2018 04:51:37 +0000 (16:51 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 12 Jul 2018 02:31:56 +0000 (04:31 +0200)
Modifies bind9 and internal dns to match windows static records behaviour.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=10812

Signed-off-by: Aaron Haslett <aaronhaslett@catalyst.net.nz>
Reviewed-by: Gary Lockyer <gary@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
python/samba/tests/dns.py
selftest/knownfail.d/dns
source4/dns_server/dlz_bind9.c
source4/dns_server/dns_update.c
source4/dns_server/dnsserver_common.c
source4/dns_server/dnsserver_common.h

index faf4c5240768bbefe0a9aa723a86f44d5dd6fc0b..508d49f47d8bb34241e44ea76ed195f37726fa61 100644 (file)
@@ -1093,6 +1093,42 @@ class TestZones(DNSTest):
         self.assertEqual(len(recs), 1)
         self.assertEqual(recs[0].dwTimeStamp, 0)
 
+    def test_static_record_dynamic_update(self):
+        name,txt = 'agingtest', ['test txt']
+        txt2 = ['test txt2']
+        self.set_aging(enable=True)
+        rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+        rec_buf.rec = TXTRecord(txt)
+        self.rpc_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+                                          0, self.server_ip,
+                                          self.zone, name, rec_buf, None)
+
+        rec2 = self.dns_update_record(name, txt2)
+        self.assertEqual(rec2.dwTimeStamp, 0)
+
+    def test_dynamic_record_static_update(self):
+        name,txt = 'agingtest', ['test txt']
+        txt2 = ['test txt2']
+        txt3 = ['test txt3']
+        self.set_aging(enable=True)
+
+        self.dns_update_record(name, txt)
+
+        rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
+        rec_buf.rec = TXTRecord(txt2)
+        self.rpc_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
+                                          0, self.server_ip,
+                                          self.zone, name, rec_buf, None)
+
+        self.dns_update_record(name, txt3)
+
+        recs = self.ldap_get_dns_records(name)
+        # Put in dict because ldap recs might be out of order
+        recs = {str(r.data.str):r for r in recs}
+        self.assertNotEqual(recs[str(txt)].dwTimeStamp, 0)
+        self.assertEqual(recs[str(txt2)].dwTimeStamp, 0)
+        self.assertEqual(recs[str(txt3)].dwTimeStamp, 0)
+
     def test_dns_tombstone_custom_match_rule(self):
         lp = self.get_loadparm()
         self.samdb = SamDB(url = lp.samdb_url(), lp = lp,
index 7ae19f65e333746e94c1ffd7bdb2a70401d72b4c..99b0f1d63a08e785414e3ac4afbea170f5f071b7 100644 (file)
@@ -46,6 +46,8 @@ samba.tests.dns.__main__.TestZones.test_rpc_add_no_timestamp\(rodc:local\)
 samba.tests.dns.__main__.TestZones.test_basic_scavenging\(rodc:local\)
 samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule\(rodc:local\)
 samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule_fail\(rodc:local\)
+samba.tests.dns.__main__.TestZones.test_dynamic_record_static_update\(rodc:local\)
+samba.tests.dns.__main__.TestZones.test_static_record_dynamic_update\(rodc:local\)
 
 samba.tests.dns.__main__.TestZones.test_set_aging\(vampire_dc:local\)
 samba.tests.dns.__main__.TestZones.test_aging_update\(vampire_dc:local\)
@@ -53,6 +55,8 @@ samba.tests.dns.__main__.TestZones.test_aging_update_disabled\(vampire_dc:local\
 samba.tests.dns.__main__.TestZones.test_aging_refresh\(vampire_dc:local\)
 samba.tests.dns.__main__.TestZones.test_basic_scavenging\(vampire_dc:local\)
 samba.tests.dns.__main__.TestZones.test_dns_tombstone_custom_match_rule\(vampire_dc:local\)
+samba.tests.dns.__main__.TestZones.test_dynamic_record_static_update\(vampire_dc:local\)
+samba.tests.dns.__main__.TestZones.test_static_record_dynamic_update\(vampire_dc:local\)
 
 samba.tests.dns.__main__.TestComplexQueries.test_cname_two_chain\(vampire_dc:local\)
 samba.tests.dns.__main__.TestComplexQueries.test_one_a_query\(vampire_dc:local\)
index e55d73ba50f494adb1adba7f6865d0ded494d334..5f9a71dd7412c0034fc6317369de1776d90c0ce2 100644 (file)
@@ -1631,18 +1631,7 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
                return ISC_R_NOMEMORY;
        }
 
-       unix_to_nt_time(&t, time(NULL));
-       /*
-        * convert to seconds (NT time is in 100ns units)
-        */
-       t /= 10 * 1000 * 1000;
-       /*
-        * convert to hours
-        */
-       t /= 3600;
-
        rec->rank        = DNS_RANK_ZONE;
-       rec->dwTimeStamp = (uint32_t)t;
 
        if (!b9_parse(state, rdatastr, rec)) {
                state->log(ISC_LOG_INFO, "samba_dlz: failed to parse rdataset '%s'", rdatastr);
@@ -1704,6 +1693,15 @@ _PUBLIC_ isc_result_t dlz_addrdataset(const char *name, const char *rdatastr, vo
                        return ISC_R_NOMEMORY;
                }
                num_recs++;
+
+               if (dns_name_is_static(recs, num_recs)) {
+                       rec->dwTimeStamp = 0;
+               } else {
+                       unix_to_nt_time(&t, time(NULL));
+                       t /= 10 * 1000 * 1000; /* convert to seconds */
+                       t /= 3600;           /* convert to hours */
+                       rec->dwTimeStamp = (uint32_t)t;
+               }
        }
 
        recs[i] = *rec;
index ebed4495dbd9cfb44a779249e7054e4e5bb692ae..f9866611119739df42701ffb42db0f83aeb6cc87 100644 (file)
@@ -38,7 +38,8 @@
 
 static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                             const struct dns_res_rec *rrec,
-                            struct dnsp_DnssrvRpcRecord *r);
+                            struct dnsp_DnssrvRpcRecord *r,
+                            bool name_is_static);
 
 static WERROR check_one_prerequisite(struct dns_server *dns,
                                     TALLOC_CTX *mem_ctx,
@@ -181,7 +182,7 @@ static WERROR check_one_prerequisite(struct dns_server *dns,
        rec = talloc_zero(mem_ctx, struct dnsp_DnssrvRpcRecord);
        W_ERROR_HAVE_NO_MEMORY(rec);
 
-       werror = dns_rr_to_dnsp(rec, pr, rec);
+       werror = dns_rr_to_dnsp(rec, pr, rec, dns_name_is_static(ans, acount));
        W_ERROR_NOT_OK_RETURN(werror);
 
        for (i = 0; i < acount; i++) {
@@ -297,7 +298,8 @@ static WERROR update_prescan(const struct dns_name_question *zone,
 
 static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                             const struct dns_res_rec *rrec,
-                            struct dnsp_DnssrvRpcRecord *r)
+                            struct dnsp_DnssrvRpcRecord *r,
+                            bool name_is_static)
 {
        enum ndr_err_code ndr_err;
        NTTIME t;
@@ -311,10 +313,14 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
        r->wType = (enum dns_record_type) rrec->rr_type;
        r->dwTtlSeconds = rrec->ttl;
        r->rank = DNS_RANK_ZONE;
-       unix_to_nt_time(&t, time(NULL));
-       t /= 10 * 1000 * 1000;
-       t /= 3600;
-       r->dwTimeStamp = t;
+       if (name_is_static) {
+               r->dwTimeStamp = 0;
+       } else {
+               unix_to_nt_time(&t, time(NULL));
+               t /= 10 * 1000 * 1000;
+               t /= 3600;
+               r->dwTimeStamp = t;
+       }
 
        /* If we get QCLASS_ANY, we're done here */
        if (rrec->rr_class == DNS_QCLASS_ANY) {
@@ -390,6 +396,7 @@ static WERROR handle_one_update(struct dns_server *dns,
        WERROR werror;
        bool tombstoned = false;
        bool needs_add = false;
+       bool name_is_static;
 
        DEBUG(2, ("Looking at record: \n"));
        if (DEBUGLVL(2)) {
@@ -432,6 +439,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                first = rcount;
        }
 
+       name_is_static = dns_name_is_static(recs, rcount);
+
        if (update->rr_class == zone->question_class) {
                if (update->rr_type == DNS_QTYPE_CNAME) {
                        /*
@@ -456,7 +465,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                                        struct dnsp_DnssrvRpcRecord, rcount + 1);
                        W_ERROR_HAVE_NO_MEMORY(recs);
 
-                       werror = dns_rr_to_dnsp(recs, update, &recs[rcount]);
+                       werror = dns_rr_to_dnsp(
+                           recs, update, &recs[rcount], name_is_static);
                        W_ERROR_NOT_OK_RETURN(werror);
                        rcount += 1;
 
@@ -508,7 +518,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                                return WERR_OK;
                        }
 
-                       werror = dns_rr_to_dnsp(mem_ctx, update, &recs[i]);
+                       werror = dns_rr_to_dnsp(
+                           mem_ctx, update, &recs[i], name_is_static);
                        W_ERROR_NOT_OK_RETURN(werror);
 
                        for (i++; i < rcount; i++) {
@@ -532,7 +543,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                                struct dnsp_DnssrvRpcRecord, rcount+1);
                W_ERROR_HAVE_NO_MEMORY(recs);
 
-               werror = dns_rr_to_dnsp(recs, update, &recs[rcount]);
+               werror =
+                   dns_rr_to_dnsp(recs, update, &recs[rcount], name_is_static);
                W_ERROR_NOT_OK_RETURN(werror);
 
                for (i = first; i < rcount; i++) {
@@ -618,7 +630,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                                                struct dnsp_DnssrvRpcRecord);
                        W_ERROR_HAVE_NO_MEMORY(ns_rec);
 
-                       werror = dns_rr_to_dnsp(ns_rec, update, ns_rec);
+                       werror = dns_rr_to_dnsp(
+                           ns_rec, update, ns_rec, name_is_static);
                        W_ERROR_NOT_OK_RETURN(werror);
 
                        for (i = first; i < rcount; i++) {
@@ -635,7 +648,8 @@ static WERROR handle_one_update(struct dns_server *dns,
                del_rec = talloc(mem_ctx, struct dnsp_DnssrvRpcRecord);
                W_ERROR_HAVE_NO_MEMORY(del_rec);
 
-               werror = dns_rr_to_dnsp(del_rec, update, del_rec);
+               werror =
+                   dns_rr_to_dnsp(del_rec, update, del_rec, name_is_static);
                W_ERROR_NOT_OK_RETURN(werror);
 
                for (i = first; i < rcount; i++) {
index 2551240fca48961f2ca0eaa0d33334c0e6c1c960..2a493702ed2c2f39a96697a6a13c4f920a796ebd 100644 (file)
@@ -724,6 +724,23 @@ static WERROR check_name_list(TALLOC_CTX *mem_ctx, uint16_t rec_count,
        return WERR_OK;
 }
 
+bool dns_name_is_static(struct dnsp_DnssrvRpcRecord *records,
+                       uint16_t rec_count)
+{
+       int i = 0;
+       for (i = 0; i < rec_count; i++) {
+               if (records[i].wType == DNS_TYPE_TOMBSTONE) {
+                       continue;
+               }
+
+               if (records[i].wType == DNS_TYPE_SOA ||
+                   records[i].dwTimeStamp == 0) {
+                       return true;
+               }
+       }
+       return false;
+}
+
 WERROR dns_get_zone_properties(struct ldb_context *samdb,
                               TALLOC_CTX *mem_ctx,
                               struct ldb_dn *zone_dn,
index 9067e2234e722bd7c5d49a49219561db5644aede..380f61b8dbc53f7454b9eb4eeedb63993c216c55 100644 (file)
@@ -61,6 +61,8 @@ WERROR dns_get_zone_properties(struct ldb_context *samdb,
                               TALLOC_CTX *mem_ctx,
                               struct ldb_dn *zone_dn,
                               struct dnsserver_zoneinfo *zoneinfo);
+bool dns_name_is_static(struct dnsp_DnssrvRpcRecord *records,
+                       uint16_t rec_count);
 WERROR dns_common_replace(struct ldb_context *samdb,
                          TALLOC_CTX *mem_ctx,
                          struct ldb_dn *dn,