The branch, master has been updated via 4bba5fc samba-tool: dns: Update the copyright via 61d4d74 samba-tool: dns: Fix the output display of DNS records via b45d6a6 samba-tool: dns: Add extra references for string objects as workaround via a8a6b27 samba-tool: dns: Add support to add/update/delete MX and SRV records via 28b1282 samba-tool: dns: Convert dns data into a dns record for comparison via 4272a76 samba-tool: dns: Convert dns data in a string to DNS record via 1fc2fb5 samba-tool: dns: Add MXRecord type to add/update mx records via 169db33 dlz_bind9: Do not remove LDB record in subrdataset and delrdataset from 89586ed lib/tdb2: 2.0.0 ABI
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 4bba5fcecd1f7071aa0529527a11f0082f8d625f Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Feb 16 10:17:25 2012 +1100 samba-tool: dns: Update the copyright Autobuild-User: Amitay Isaacs <ami...@samba.org> Autobuild-Date: Tue Feb 21 09:55:07 CET 2012 on sn-devel-104 commit 61d4d7414585149ff0b703c139201d74c7800cd1 Author: Amitay Isaacs <ami...@gmail.com> Date: Wed Feb 15 20:56:38 2012 +1100 samba-tool: dns: Fix the output display of DNS records commit b45d6a6d690b20e348336b9d5db678f3e574ad62 Author: Amitay Isaacs <ami...@gmail.com> Date: Wed Feb 15 20:45:48 2012 +1100 samba-tool: dns: Add extra references for string objects as workaround This is a workaround for bug in pidl generated python bindings, where C object hold a pointer to python string without increasing reference count in python. So when the python string goes out of scope, the C pointer loses the value. commit a8a6b27e06b97edb70f171cd881f0dd24c82b92e Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Feb 14 13:41:45 2012 +1100 samba-tool: dns: Add support to add/update/delete MX and SRV records commit 28b12827b67a758652e9cc86b059a9af44e548f6 Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Feb 14 13:32:57 2012 +1100 samba-tool: dns: Convert dns data into a dns record for comparison and compare two dns records directly. Refactor dns name comparision as dns_name_equal(). commit 4272a76075063a212c9a3b0454f69270799b3142 Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Feb 14 13:19:36 2012 +1100 samba-tool: dns: Convert dns data in a string to DNS record commit 1fc2fb5de1862de36235c896d1c7c4000e3c0349 Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Feb 14 13:00:35 2012 +1100 samba-tool: dns: Add MXRecord type to add/update mx records commit 169db333033b72b6f9ac1e7b23f0f2c151218c1f Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Feb 9 10:17:02 2012 +1100 dlz_bind9: Do not remove LDB record in subrdataset and delrdataset This fixes the problem of large number of deleted records in DNS partitions due to frequent dynamic dns updates from windows clients. The typical pattern for dynamic update get converted into subrdataset() followed by addrdataset(). If there are no dnsRecord attributes left as a result of sub/delrdataset(), leave the LDB entry for dns name as is. The subsequent addrdataset() would add the dnsRecord attribute without re-creating the same entry. ----------------------------------------------------------------------- Summary of changes: source4/dns_server/dlz_bind9.c | 21 +-- source4/scripting/python/samba/netcmd/dns.py | 219 +++++++++++++++++++------- 2 files changed, 169 insertions(+), 71 deletions(-) Changeset truncated at 500 lines: diff --git a/source4/dns_server/dlz_bind9.c b/source4/dns_server/dlz_bind9.c index 6f6b1da..7bb7a34 100644 --- a/source4/dns_server/dlz_bind9.c +++ b/source4/dns_server/dlz_bind9.c @@ -1614,14 +1614,11 @@ _PUBLIC_ isc_result_t dlz_subrdataset(const char *name, const char *rdatastr, vo } if (el->num_values == 0) { - /* delete the record */ - ret = ldb_delete(state->samdb, dn); - b9_reset_session_info(state); - } else { - /* modify the record */ - el->flags = LDB_FLAG_MOD_REPLACE; - ret = ldb_modify(state->samdb, res->msgs[0]); + ldb_msg_remove_element(res->msgs[0], el); } + el->flags = LDB_FLAG_MOD_REPLACE; + ret = ldb_modify(state->samdb, res->msgs[0]); + b9_reset_session_info(state); if (ret != LDB_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to modify %s - %s", @@ -1722,13 +1719,11 @@ _PUBLIC_ isc_result_t dlz_delrdataset(const char *name, const char *type, void * } if (el->num_values == 0) { - /* delete the record */ - ret = ldb_delete(state->samdb, dn); - } else { - /* modify the record */ - el->flags = LDB_FLAG_MOD_REPLACE; - ret = ldb_modify(state->samdb, res->msgs[0]); + ldb_msg_remove_element(res->msgs[0], el); } + el->flags = LDB_FLAG_MOD_REPLACE; + ret = ldb_modify(state->samdb, res->msgs[0]); + b9_reset_session_info(state); if (ret != LDB_SUCCESS) { state->log(ISC_LOG_ERROR, "samba_dlz: failed to delete type %s in %s - %s", diff --git a/source4/scripting/python/samba/netcmd/dns.py b/source4/scripting/python/samba/netcmd/dns.py index 6d07db4..b84f29b 100644 --- a/source4/scripting/python/samba/netcmd/dns.py +++ b/source4/scripting/python/samba/netcmd/dns.py @@ -2,7 +2,7 @@ # # DNS management tool # -# Copyright (C) Amitay Isaacs 2011 +# Copyright (C) Amitay Isaacs 2011-2012 # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -345,9 +345,10 @@ def print_dns_record(outf, rec): rec.data.NamePrimaryServer.str, rec.data.ZoneAdministratorEmail.str) elif rec.wType == dnsp.DNS_TYPE_MX: - mesg = 'MX: %s' % (rec.data.str) + mesg = 'MX: %s (%d)' % (rec.data.nameExchange.str, rec.data.wPreference) elif rec.wType == dnsp.DNS_TYPE_SRV: - mesg = 'SRV: %s (%d)' % (rec.data.nameTarget.str, rec.data.wPort) + mesg = 'SRV: %s (%d, %d, %d)' % (rec.data.nameTarget.str, rec.data.wPort, + rec.data.wPriority, rec.data.wWeight) outf.write(' %s (flags=%x, serial=%d, ttl=%d)\n' % ( mesg, rec.dwFlags, rec.dwSerial, rec.dwTtlSeconds)) @@ -421,6 +422,26 @@ class NSRecord(dnsserver.DNS_RPC_RECORD): ns.len = len(dns_server) self.data = ns +# +# FIXME: In MXRecord, SOARecord, SRVRecord keep a reference to strings +# to overcome the bug in pidl generated python bindings. +# + +class MXRecord(dnsserver.DNS_RPC_RECORD): + def __init__(self, mail_server, preference, serial=1, ttl=900, + rank=dnsp.DNS_RANK_ZONE, node_flag=0): + super(MXRecord, self).__init__() + self.wType = dnsp.DNS_TYPE_MX + self.dwFlags = rank | node_flag + self.dwSerial = serial + self.dwTtlSeconds = ttl + mx = dnsserver.DNS_RPC_RECORD_NAME_PREFERENCE() + mx.wPreference = preference + self._mail_server = mail_server + mx.nameExchange.str = self._mail_server + mx.nameExchange.len = len(self._mail_server) + self.data = mx + class SOARecord(dnsserver.DNS_RPC_RECORD): def __init__(self, mname, rname, serial=1, refresh=900, retry=600, expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE, @@ -435,10 +456,12 @@ class SOARecord(dnsserver.DNS_RPC_RECORD): soa.dwRefresh = refresh soa.dwRetry = retry soa.dwExpire = expire - soa.NamePrimaryServer.str = mname - soa.NamePrimaryServer.len = len(mname) - soa.ZoneAdministratorEmail.str = rname - soa.ZoneAdministratorEmail.len = len(rname) + self._mname = mname + soa.NamePrimaryServer.str = self._mname + soa.NamePrimaryServer.len = len(self._mname) + self._rname = rname + soa.ZoneAdministratorEmail.str = self._rname + soa.ZoneAdministratorEmail.len = len(self._rname) self.data = soa class SRVRecord(dnsserver.DNS_RPC_RECORD): @@ -453,12 +476,68 @@ class SRVRecord(dnsserver.DNS_RPC_RECORD): srv.wPriority = priority srv.wWeight = weight srv.wPort = port - srv.nameTarget.str = target - srv.nameTarget.len = len(target) + self._target = target + srv.nameTarget.str = self._target + srv.nameTarget.len = len(self._target) self.data = srv + +# Convert data into a dns record +def data_to_dns_record(record_type, data): + if record_type == dnsp.DNS_TYPE_A: + rec = ARecord(data) + elif record_type == dnsp.DNS_TYPE_AAAA: + rec = AAAARecord(data) + elif record_type == dnsp.DNS_TYPE_PTR: + rec = PTRRecord(data) + elif record_type == dnsp.DNS_TYPE_CNAME: + rec = CNameRecord(data) + elif record_type == dnsp.DNS_TYPE_NS: + rec = NSRecord(data) + elif record_type == dnsp.DNS_TYPE_MX: + tmp = data.split(' ') + if len(tmp) != 2: + raise CommandError('Data requires 2 elements - mail_server, preference') + mail_server = tmp[0] + preference = int(tmp[1]) + rec = MXRecord(mail_server, preference) + elif record_type == dnsp.DNS_TYPE_SRV: + tmp = data.split(' ') + if len(tmp) != 4: + raise CommandError('Data requires 4 elements - server, port, priority, weight') + server = tmp[0] + port = int(tmp[1]) + priority = int(tmp[2]) + weight = int(tmp[3]) + rec = SRVRecord(server, port, priority=priority, weight=weight) + elif record_type == dnsp.DNS_TYPE_SOA: + tmp = data.split(' ') + if len(tmp) != 7: + raise CommandError('Data requires 7 elements - nameserver, email, serial, ' + 'refresh, retry, expire, minimumttl') + nameserver = tmp[0] + email = tmp[1] + serial = int(tmp[2]) + refresh = int(tmp[3]) + retry = int(tmp[4]) + expire = int(tmp[5]) + minimum = int(tmp[6]) + rec = SOARecord(nameserver, email, serial=serial, refresh=refresh, + retry=retry, expire=expire, minimum=minimum) + else: + raise CommandError('Unsupported record type') + return rec + + +# Match dns name (of type DNS_RPC_NAME) +def dns_name_equal(n1, n2): + return n1.str.rstrip('.').lower() == n2.str.rstrip('.').lower() + + # Match a dns record with specified data def dns_record_match(dns_conn, server, zone, name, record_type, data): + urec = data_to_dns_record(record_type, data) + select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA try: @@ -485,19 +564,40 @@ def dns_record_match(dns_conn, server, zone, name, record_type, data): found = False if record_type == dnsp.DNS_TYPE_A: - if rec.data == data: + if rec.data == urec.data: found = True elif record_type == dnsp.DNS_TYPE_AAAA: - if rec.data == data: + if rec.data == urec.data: found = True elif record_type == dnsp.DNS_TYPE_PTR: - if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower(): + if dns_name_equal(rec.data, urec.data): found = True elif record_type == dnsp.DNS_TYPE_CNAME: - if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower(): + if dns_name_equal(rec.data, urec.data): found = True elif record_type == dnsp.DNS_TYPE_NS: - if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower(): + if dns_name_equal(rec.data, urec.data): + found = True + elif record_type == dnsp.DNS_TYPE_MX: + if dns_name_equal(rec.data.nameExchange, urec.data.nameExchange) and \ + rec.data.wPreference == urec.data.wPreference: + found = True + elif record_type == dnsp.DNS_TYPE_SRV: + if rec.data.wPriority == urec.data.wPriority and \ + rec.data.wWeight == urec.data.wWeight and \ + rec.data.wPort == urec.data.wPort and \ + dns_name_equal(rec.data.nameTarget, urec.data.nameTarget): + found = True + elif record_type == dnsp.DNS_TYPE_SOA: + if rec.data.dwSerialNo == urec.data.dwSerialNo and \ + rec.data.dwRefresh == urec.data.dwRefresh and \ + rec.data.dwRetry == urec.data.dwRetry and \ + rec.data.dwExpire == urec.data.dwExpire and \ + rec.data.dwMinimumTtl == urec.data.dwMinimumTtl and \ + dns_name_equal(rec.data.NamePrimaryServer, + urec.data.NamePrimaryServer) and \ + dns_name_equal(rec.data.ZoneAdministratorEmail, + urec.data.ZoneAdministratorEmail): found = True if found: rec_match = rec @@ -862,9 +962,19 @@ class cmd_roothints(Command): class cmd_add_record(Command): - """Add a DNS record""" + """Add a DNS record + + For each type data contents are as follows: + A ipv4_address_string + AAAA ipv6_address_string + PTR fqdn_string + CNAME fqdn_string + NS fqdn_string + MX "fqdn_string preference" + SRV "fqdn_string port priority weight" + """ - synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>' + synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV> <data>' takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ] @@ -876,21 +986,12 @@ class cmd_add_record(Command): def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None): - record_type = dns_type_flag(rtype) - - if record_type == dnsp.DNS_TYPE_A: - rec = ARecord(data) - elif record_type == dnsp.DNS_TYPE_AAAA: - rec = AAAARecord(data) - elif record_type == dnsp.DNS_TYPE_PTR: - rec = PTRRecord(data) - elif record_type == dnsp.DNS_TYPE_CNAME: - rec = CNameRecord(data) - elif record_type == dnsp.DNS_TYPE_NS: - rec = NSRecord(data) - else: + if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV'): raise CommandError('Adding record of type %s is not supported' % rtype) + record_type = dns_type_flag(rtype) + rec = data_to_dns_record(record_type, data) + self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp) dns_conn = dns_connect(server, self.lp, self.creds) @@ -913,9 +1014,19 @@ class cmd_add_record(Command): class cmd_update_record(Command): - """Update a DNS record""" + """Update a DNS record - synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <olddata> <newdata>' + For each type data contents are as follows: + A ipv4_address_string + AAAA ipv6_address_string + PTR fqdn_string + CNAME fqdn_string + NS fqdn_string + MX "fqdn_string preference" + SRV "fqdn_string port priority weight" + """ + + synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV> <olddata> <newdata>' takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ] @@ -928,20 +1039,12 @@ class cmd_update_record(Command): def run(self, server, zone, name, rtype, olddata, newdata, sambaopts=None, credopts=None, versionopts=None): - record_type = dns_type_flag(rtype) - if record_type == dnsp.DNS_TYPE_A: - rec = ARecord(newdata) - elif record_type == dnsp.DNS_TYPE_AAAA: - rec = AAAARecord(newdata) - elif record_type == dnsp.DNS_TYPE_PTR: - rec = PTRRecord(newdata) - elif record_type == dnsp.DNS_TYPE_CNAME: - rec = CNameRecord(newdata) - elif record_type == dnsp.DNS_TYPE_NS: - rec = NSRecord(newdata) - else: + if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV'): raise CommandError('Updating record of type %s is not supported' % rtype) + record_type = dns_type_flag(rtype) + rec = data_to_dns_record(record_type, newdata) + self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp) dns_conn = dns_connect(server, self.lp, self.creds) @@ -973,9 +1076,19 @@ class cmd_update_record(Command): class cmd_delete_record(Command): - """Delete a DNS record""" + """Delete a DNS record + + For each type data contents are as follows: + A ipv4_address_string + AAAA ipv6_address_string + PTR fqdn_string + CNAME fqdn_string + NS fqdn_string + MX "fqdn_string preference" + SRV "fqdn_string port priority weight" + """ - synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>' + synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV> <data>' takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ] @@ -987,21 +1100,11 @@ class cmd_delete_record(Command): def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None): - record_type = dns_type_flag(rtype) - - if record_type == dnsp.DNS_TYPE_A: - rec = ARecord(data) - elif record_type == dnsp.DNS_TYPE_AAAA: - rec = AAAARecord(data) - elif record_type == dnsp.DNS_TYPE_PTR: - rec = PTRRecord(data) - elif record_type == dnsp.DNS_TYPE_CNAME: - rec = CNameRecord(data) - elif record_type == dnsp.DNS_TYPE_NS: - rec = NSRecord(data) - else: + if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV'): raise CommandError('Deleting record of type %s is not supported' % rtype) + record_type = dns_type_flag(rtype) + self.lp = sambaopts.get_loadparm() self.creds = credopts.get_credentials(self.lp) dns_conn = dns_connect(server, self.lp, self.creds) -- Samba Shared Repository