From 418cd93f4c9c90b0f5002e32203be8281af660cf Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Mon, 2 Jul 2018 13:43:33 +1200 Subject: [PATCH] dns: server side implementation of record aging 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 Reviewed-by: Gary Lockyer Reviewed-by: Andrew Bartlett --- python/samba/tests/dns.py | 1 + selftest/knownfail.d/dns-scavenging | 17 ++--- source4/dns_server/dns_update.c | 10 ++- source4/dns_server/dnsserver_common.c | 123 ++++++++++++++++++++++++++++++++ source4/dns_server/dnsserver_common.h | 6 ++ source4/rpc_server/dnsserver/dnsutils.c | 9 ++- 6 files changed, 151 insertions(+), 15 deletions(-) rewrite selftest/knownfail.d/dns-scavenging (67%) diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index 722b75ce81b..800ce576dec 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -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) diff --git a/selftest/knownfail.d/dns-scavenging b/selftest/knownfail.d/dns-scavenging dissimilarity index 67% index 715e14527c9..fe71f17c03c 100644 --- a/selftest/knownfail.d/dns-scavenging +++ b/selftest/knownfail.d/dns-scavenging @@ -1,11 +1,6 @@ -# -# Tests added for the dns scavenging changes -# -# 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\) +# +# Tests added for the dns scavenging changes +# +# Will be removed once the tests are implemented. +# +samba.tests.dns.__main__.TestZones.test_basic_scavenging\(fl2003dc:local\) diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index ac3c3e11bae..ebed4495dbd 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -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); diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 20eaf125ada..2551240fca4 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -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); diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index e37c7b8f9ab..9067e2234e7 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -19,6 +19,8 @@ along with this program. If not, see . */ +#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, diff --git a/source4/rpc_server/dnsserver/dnsutils.c b/source4/rpc_server/dnsserver/dnsutils.c index 5eb95f8f339..a1c749074af 100644 --- a/source4/rpc_server/dnsserver/dnsutils.c +++ b/source4/rpc_server/dnsserver/dnsutils.c @@ -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; -- 2.11.4.GIT