dns: server side implementation of record aging
authorAaron Haslett <aaronhaslett@catalyst.net.nz>
Mon, 2 Jul 2018 01:43:33 +0000 (13:43 +1200)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 12 Jul 2018 02:31:54 +0000 (04:31 +0200)
Code for retrieving aging properties from a zone and using them for timestamp
setting logic during processing of DNS requests.

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-scavenging
source4/dns_server/dns_update.c
source4/dns_server/dnsserver_common.c
source4/dns_server/dnsserver_common.h
source4/rpc_server/dnsserver/dnsutils.c

index 722b75ce81b8b87fefcfaf8c46fac01337eb124b..800ce576dec9f2fb6195bfbcbca535e3a7b112ab 100644 (file)
@@ -1104,6 +1104,7 @@ class TestZones(DNSTest):
             self.assertTrue(rec.dwTimeStamp > 0)
             rec.dwTimeStamp -= interval*5
         self.ldap_modify_dnsrecs(name, mod_ts)
+        self.assertTrue(callable(getattr(dsdb, '_scavenge_dns_records', None)))
         dsdb._scavenge_dns_records(self.samdb)
 
         recs = self.ldap_get_dns_records(name)
index 715e14527c9a2e16534a3be1b547dab431712fed..fe71f17c03cf27559dc6b432e859ba9adff1c130 100644 (file)
@@ -3,9 +3,4 @@
 #
 # Will be removed once the tests are implemented.
 #
-samba.tests.dns.__main__.TestZones.test_aging_refresh\(fl2003dc:local\)
-samba.tests.dns.__main__.TestZones.test_aging_update\(fl2003dc:local\)
-samba.tests.dns.__main__.TestZones.test_aging_update_disabled\(fl2003dc:local\)
 samba.tests.dns.__main__.TestZones.test_basic_scavenging\(fl2003dc:local\)
-samba.tests.dns.__main__.TestZones.test_set_aging\(fl2003dc:local\)
-samba.tests.dns.__main__.TestZones.test_set_aging_disabled\(fl2003dc:local\)
index ac3c3e11bae5da6c5be6bcc72ed3965a22edb09c..ebed4495dbd9cfb44a779249e7054e4e5bb692ae 100644 (file)
@@ -300,6 +300,7 @@ static WERROR dns_rr_to_dnsp(TALLOC_CTX *mem_ctx,
                             struct dnsp_DnssrvRpcRecord *r)
 {
        enum ndr_err_code ndr_err;
+       NTTIME t;
 
        if (rrec->rr_type == DNS_QTYPE_ALL) {
                return DNS_ERR(FORMAT_ERROR);
@@ -310,6 +311,10 @@ 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 we get QCLASS_ANY, we're done here */
        if (rrec->rr_class == DNS_QCLASS_ANY) {
@@ -535,7 +540,10 @@ static WERROR handle_one_update(struct dns_server *dns,
                                continue;
                        }
 
-                       recs[i] = recs[rcount];
+                       recs[i].data = recs[rcount].data;
+                       recs[i].wType = recs[rcount].wType;
+                       recs[i].dwTtlSeconds = recs[rcount].dwTtlSeconds;
+                       recs[i].rank = recs[rcount].rank;
 
                        werror = dns_replace_records(dns, mem_ctx, dn,
                                                     needs_add, recs, rcount);
index 20eaf125ada7e42e9b9be7d5d1b489b8ae67d4d9..2551240fca48961f2ca0eaa0d33334c0e6c1c960 100644 (file)
@@ -31,6 +31,7 @@
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/common/util.h"
 #include "dns_server/dnsserver_common.h"
+#include "rpc_server/dnsserver/dnsserver.h"
 #include "lib/util/dlinklist.h"
 
 #undef DBGC_CLASS
@@ -723,6 +724,93 @@ static WERROR check_name_list(TALLOC_CTX *mem_ctx, uint16_t rec_count,
        return WERR_OK;
 }
 
+WERROR dns_get_zone_properties(struct ldb_context *samdb,
+                              TALLOC_CTX *mem_ctx,
+                              struct ldb_dn *zone_dn,
+                              struct dnsserver_zoneinfo *zoneinfo)
+{
+
+       int ret, i;
+       struct dnsp_DnsProperty *prop = NULL;
+       struct ldb_message_element *element = NULL;
+       const char *const attrs[] = {"dNSProperty", NULL};
+       struct ldb_result *res = NULL;
+       enum ndr_err_code err;
+
+       ret = ldb_search(samdb,
+                        mem_ctx,
+                        &res,
+                        zone_dn,
+                        LDB_SCOPE_BASE,
+                        attrs,
+                        "(objectClass=dnsZone)");
+       if (ret != LDB_SUCCESS) {
+               DBG_ERR("dnsserver: Failed to find DNS zone: %s\n",
+                       ldb_dn_get_linearized(zone_dn));
+               return DNS_ERR(SERVER_FAILURE);
+       }
+
+       element = ldb_msg_find_element(res->msgs[0], "dNSProperty");
+       if (element == NULL) {
+               return DNS_ERR(NOTZONE);
+       }
+
+       for (i = 0; i < element->num_values; i++) {
+               prop = talloc_zero(mem_ctx, struct dnsp_DnsProperty);
+               if (prop == NULL) {
+                       return WERR_NOT_ENOUGH_MEMORY;
+               }
+               err = ndr_pull_struct_blob(
+                   &(element->values[i]),
+                   mem_ctx,
+                   prop,
+                   (ndr_pull_flags_fn_t)ndr_pull_dnsp_DnsProperty);
+               if (!NDR_ERR_CODE_IS_SUCCESS(err)) {
+                       return DNS_ERR(SERVER_FAILURE);
+               }
+
+               switch (prop->id) {
+               case DSPROPERTY_ZONE_AGING_STATE:
+                       zoneinfo->fAging = prop->data.aging_enabled;
+                       break;
+               case DSPROPERTY_ZONE_NOREFRESH_INTERVAL:
+                       zoneinfo->dwNoRefreshInterval =
+                           prop->data.norefresh_hours;
+                       break;
+               case DSPROPERTY_ZONE_REFRESH_INTERVAL:
+                       zoneinfo->dwRefreshInterval = prop->data.refresh_hours;
+                       break;
+               case DSPROPERTY_ZONE_ALLOW_UPDATE:
+                       zoneinfo->fAllowUpdate = prop->data.allow_update_flag;
+                       break;
+               case DSPROPERTY_ZONE_AGING_ENABLED_TIME:
+                       zoneinfo->dwAvailForScavengeTime =
+                           prop->data.next_scavenging_cycle_hours;
+                       break;
+               case DSPROPERTY_ZONE_SCAVENGING_SERVERS:
+                       zoneinfo->aipScavengeServers->AddrCount =
+                           prop->data.servers.addrCount;
+                       zoneinfo->aipScavengeServers->AddrArray =
+                           prop->data.servers.addr;
+                       break;
+               case DSPROPERTY_ZONE_EMPTY:
+               case DSPROPERTY_ZONE_TYPE:
+               case DSPROPERTY_ZONE_SECURE_TIME:
+               case DSPROPERTY_ZONE_DELETED_FROM_HOSTNAME:
+               case DSPROPERTY_ZONE_MASTER_SERVERS:
+               case DSPROPERTY_ZONE_AUTO_NS_SERVERS:
+               case DSPROPERTY_ZONE_DCPROMO_CONVERT:
+               case DSPROPERTY_ZONE_SCAVENGING_SERVERS_DA:
+               case DSPROPERTY_ZONE_MASTER_SERVERS_DA:
+               case DSPROPERTY_ZONE_NS_SERVERS_DA:
+               case DSPROPERTY_ZONE_NODE_DBFLAGS:
+                       break;
+               }
+       }
+
+       return WERR_OK;
+}
+
 WERROR dns_common_replace(struct ldb_context *samdb,
                          TALLOC_CTX *mem_ctx,
                          struct ldb_dn *dn,
@@ -738,12 +826,37 @@ WERROR dns_common_replace(struct ldb_context *samdb,
        struct ldb_message *msg = NULL;
        bool was_tombstoned = false;
        bool become_tombstoned = false;
+       struct ldb_dn *zone_dn = NULL;
+       struct dnsserver_zoneinfo *zoneinfo = NULL;
+       NTTIME t;
 
        msg = ldb_msg_new(mem_ctx);
        W_ERROR_HAVE_NO_MEMORY(msg);
 
        msg->dn = dn;
 
+       zone_dn = ldb_dn_copy(mem_ctx, dn);
+       if (zone_dn == NULL) {
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
+       if (!ldb_dn_remove_child_components(zone_dn, 1)) {
+               return DNS_ERR(SERVER_FAILURE);
+       }
+       zoneinfo = talloc(mem_ctx, struct dnsserver_zoneinfo);
+       if (zoneinfo == NULL) {
+               return WERR_NOT_ENOUGH_MEMORY;
+       }
+       werr = dns_get_zone_properties(samdb, mem_ctx, zone_dn, zoneinfo);
+       if (W_ERROR_EQUAL(DNS_ERR(NOTZONE), werr)) {
+               /*
+                * We only got zoneinfo for aging so if we didn't find any
+                * properties then just disable aging and keep going.
+                */
+               zoneinfo->fAging = 0;
+       } else if (!W_ERROR_IS_OK(werr)) {
+               return werr;
+       }
+
        werr = check_name_list(mem_ctx, rec_count, records);
        if (!W_ERROR_IS_OK(werr)) {
                return werr;
@@ -781,6 +894,16 @@ WERROR dns_common_replace(struct ldb_context *samdb,
                        continue;
                }
 
+               if (zoneinfo->fAging == 1 && records[i].dwTimeStamp != 0) {
+                       unix_to_nt_time(&t, time(NULL));
+                       t /= 10 * 1000 * 1000;
+                       t /= 3600;
+                       if (t - records[i].dwTimeStamp >
+                           zoneinfo->dwNoRefreshInterval) {
+                               records[i].dwTimeStamp = t;
+                       }
+               }
+
                records[i].dwSerial = serial;
                ndr_err = ndr_push_struct_blob(v, el->values, &records[i],
                                (ndr_push_flags_fn_t)ndr_push_dnsp_DnssrvRpcRecord);
index e37c7b8f9ab39f94488ce8279e6f8cc22d88f7c9..9067e2234e722bd7c5d49a49219561db5644aede 100644 (file)
@@ -19,6 +19,8 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 
+#include "rpc_server/dnsserver/dnsserver.h"
+
 #ifndef __DNSSERVER_COMMON_H__
 #define __DNSSERVER_COMMON_H__
 
@@ -55,6 +57,10 @@ WERROR dns_common_wildcard_lookup(struct ldb_context *samdb,
 WERROR dns_name_check(TALLOC_CTX *mem_ctx,
                      size_t len,
                      const char *name);
+WERROR dns_get_zone_properties(struct ldb_context *samdb,
+                              TALLOC_CTX *mem_ctx,
+                              struct ldb_dn *zone_dn,
+                              struct dnsserver_zoneinfo *zoneinfo);
 WERROR dns_common_replace(struct ldb_context *samdb,
                          TALLOC_CTX *mem_ctx,
                          struct ldb_dn *dn,
index 5eb95f8f339c1e7ecc0499358409c6b48ab574a8..a1c749074af8555715b2b9e71c26136aa31b4d21 100644 (file)
@@ -178,9 +178,12 @@ struct dnsserver_serverinfo *dnsserver_init_serverinfo(TALLOC_CTX *mem_ctx,
        serverinfo->dwDsPollingInterval = 0xB4; /* 3 minutes (default) */
        serverinfo->dwLocalNetPriorityNetMask = 0x000000FF;
 
-       serverinfo->dwScavengingInterval = 0;
-       serverinfo->dwDefaultRefreshInterval = 0xA8;   /* 7 days in hours */
-       serverinfo->dwDefaultNoRefreshInterval = 0xA8; /* 7 days in hours */
+       serverinfo->dwScavengingInterval = lpcfg_parm_int(
+           lp_ctx, NULL, "dnsserver", "ScavengingInterval", 24 * 7);
+       serverinfo->dwDefaultRefreshInterval = lpcfg_parm_int(
+           lp_ctx, NULL, "dnsserver", "DefaultRefreshInterval", 24 * 3);
+       serverinfo->dwDefaultNoRefreshInterval = lpcfg_parm_int(
+           lp_ctx, NULL, "dnsserver", "DefaultNoRefreshInterval", 24 * 3);
 
        serverinfo->dwLastScavengeTime = 0;