From f0210f5d17f27641bccb651313f30087d53c6ef0 Mon Sep 17 00:00:00 2001 From: Aaron Haslett Date: Thu, 7 Jun 2018 16:51:37 +1200 Subject: [PATCH] dns: static records 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 Reviewed-by: Gary Lockyer Reviewed-by: Andrew Bartlett --- python/samba/tests/dns.py | 36 +++++++++++++++++++++++++ selftest/knownfail.d/dns | 4 +++ source4/dns_server/dlz_bind9.c | 20 +++++++------- source4/dns_server/dns_update.c | 38 ++++++++++++++++++--------- source4/dns_server/dnsserver_common.c | 17 ++++++++++++ source4/dns_server/dnsserver_common.h | 2 ++ 6 files changed, 94 insertions(+), 23 deletions(-) diff --git a/python/samba/tests/dns.py b/python/samba/tests/dns.py index faf4c5240768..508d49f47d8b 100644 --- a/python/samba/tests/dns.py +++ b/python/samba/tests/dns.py @@ -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, diff --git a/selftest/knownfail.d/dns b/selftest/knownfail.d/dns index 7ae19f65e333..99b0f1d63a08 100644 --- a/selftest/knownfail.d/dns +++ b/selftest/knownfail.d/dns @@ -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\) diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index e55d73ba50f4..5f9a71dd7412 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -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; diff --git a/source4/dns_server/dns_update.c b/source4/dns_server/dns_update.c index ebed4495dbd9..f98666111197 100644 --- a/source4/dns_server/dns_update.c +++ b/source4/dns_server/dns_update.c @@ -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++) { diff --git a/source4/dns_server/dnsserver_common.c b/source4/dns_server/dnsserver_common.c index 2551240fca48..2a493702ed2c 100644 --- a/source4/dns_server/dnsserver_common.c +++ b/source4/dns_server/dnsserver_common.c @@ -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, diff --git a/source4/dns_server/dnsserver_common.h b/source4/dns_server/dnsserver_common.h index 9067e2234e72..380f61b8dbc5 100644 --- a/source4/dns_server/dnsserver_common.h +++ b/source4/dns_server/dnsserver_common.h @@ -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, -- 2.34.1