3 # Copyright (C) Amitay Isaacs 2011-2012
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 import samba.getopt as options
20 from struct import pack
21 from socket import inet_ntoa
22 from socket import inet_ntop
23 from socket import AF_INET
24 from socket import AF_INET6
27 from samba.netcmd import (
33 from samba.dcerpc import dnsp, dnsserver
36 def dns_connect(server, lp, creds):
37 if server.lower() == 'localhost':
39 binding_str = "ncacn_ip_tcp:%s[sign]" % server
41 dns_conn = dnsserver.dnsserver(binding_str, lp, creds)
42 except RuntimeError, e:
43 raise CommandError('Connecting to DNS RPC server %s failed with %s' % (server, e))
48 def bool_string(flag):
54 ret = 'UNKNOWN (0x%x)' % flag
58 def enum_string(module, enum_defs, value):
61 if value == getattr(module, e):
65 ret = 'UNKNOWN (0x%x)' % value
69 def bitmap_string(module, bitmap_defs, value):
72 if value & getattr(module, b):
79 def boot_method_string(boot_method):
80 enum_defs = [ 'DNS_BOOT_METHOD_UNINITIALIZED', 'DNS_BOOT_METHOD_FILE',
81 'DNS_BOOT_METHOD_REGISTRY', 'DNS_BOOT_METHOD_DIRECTORY' ]
82 return enum_string(dnsserver, enum_defs, boot_method)
85 def name_check_flag_string(check_flag):
86 enum_defs = [ 'DNS_ALLOW_RFC_NAMES_ONLY', 'DNS_ALLOW_NONRFC_NAMES',
87 'DNS_ALLOW_MULTIBYTE_NAMES', 'DNS_ALLOW_ALL_NAMES' ]
88 return enum_string(dnsserver, enum_defs, check_flag)
91 def zone_type_string(zone_type):
92 enum_defs = [ 'DNS_ZONE_TYPE_CACHE', 'DNS_ZONE_TYPE_PRIMARY',
93 'DNS_ZONE_TYPE_SECONDARY', 'DNS_ZONE_TYPE_STUB',
94 'DNS_ZONE_TYPE_FORWARDER', 'DNS_ZONE_TYPE_SECONDARY_CACHE' ]
95 return enum_string(dnsp, enum_defs, zone_type)
98 def zone_update_string(zone_update):
99 enum_defs = [ 'DNS_ZONE_UPDATE_OFF', 'DNS_ZONE_UPDATE_UNSECURE',
100 'DNS_ZONE_UPDATE_SECURE' ]
101 return enum_string(dnsp, enum_defs, zone_update)
104 def zone_secondary_security_string(security):
105 enum_defs = [ 'DNS_ZONE_SECSECURE_NO_SECURITY', 'DNS_ZONE_SECSECURE_NS_ONLY',
106 'DNS_ZONE_SECSECURE_LIST_ONLY', 'DNS_ZONE_SECSECURE_NO_XFER' ]
107 return enum_string(dnsserver, enum_defs, security)
110 def zone_notify_level_string(notify_level):
111 enum_defs = [ 'DNS_ZONE_NOTIFY_OFF', 'DNS_ZONE_NOTIFY_ALL_SECONDARIES',
112 'DNS_ZONE_NOTIFY_LIST_ONLY' ]
113 return enum_string(dnsserver, enum_defs, notify_level)
116 def dp_flags_string(dp_flags):
117 bitmap_defs = [ 'DNS_DP_AUTOCREATED', 'DNS_DP_LEGACY', 'DNS_DP_DOMAIN_DEFAULT',
118 'DNS_DP_FOREST_DEFAULT', 'DNS_DP_ENLISTED', 'DNS_DP_DELETED' ]
119 return bitmap_string(dnsserver, bitmap_defs, dp_flags)
122 def zone_flags_string(flags):
123 bitmap_defs = [ 'DNS_RPC_ZONE_PAUSED', 'DNS_RPC_ZONE_SHUTDOWN',
124 'DNS_RPC_ZONE_REVERSE', 'DNS_RPC_ZONE_AUTOCREATED',
125 'DNS_RPC_ZONE_DSINTEGRATED', 'DNS_RPC_ZONE_AGING',
126 'DNS_RPC_ZONE_UPDATE_UNSECURE', 'DNS_RPC_ZONE_UPDATE_SECURE',
127 'DNS_RPC_ZONE_READONLY']
128 return bitmap_string(dnsserver, bitmap_defs, flags)
131 def ip4_array_string(array):
135 for i in xrange(array.AddrCount):
136 addr = inet_ntop(AF_INET, pack('I', array.AddrArray[i]))
141 def dns_addr_array_string(array):
145 for i in xrange(array.AddrCount):
146 if array.AddrArray[i].MaxSa[0] == 0x02:
147 x = "".join([chr(b) for b in array.AddrArray[i].MaxSa])[4:8]
148 addr = inet_ntop(AF_INET, x)
149 elif array.AddrArray[i].MaxSa[0] == 0x17:
150 x = "".join([chr(b) for b in array.AddrArray[i].MaxSa])[8:24]
151 addr = inet_ntop(AF_INET6, x)
158 def dns_type_flag(rec_type):
159 rtype = rec_type.upper()
161 record_type = dnsp.DNS_TYPE_A
162 elif rtype == 'AAAA':
163 record_type = dnsp.DNS_TYPE_AAAA
165 record_type = dnsp.DNS_TYPE_PTR
167 record_type = dnsp.DNS_TYPE_NS
168 elif rtype == 'CNAME':
169 record_type = dnsp.DNS_TYPE_CNAME
171 record_type = dnsp.DNS_TYPE_SOA
173 record_type = dnsp.DNS_TYPE_MX
175 record_type = dnsp.DNS_TYPE_SRV
177 record_type = dnsp.DNS_TYPE_TXT
179 record_type = dnsp.DNS_TYPE_ALL
181 raise CommandError('Unknown type of DNS record %s' % rec_type)
185 def dns_client_version(cli_version):
186 version = cli_version.upper()
188 client_version = dnsserver.DNS_CLIENT_VERSION_W2K
189 elif version == 'DOTNET':
190 client_version = dnsserver.DNS_CLIENT_VERSION_DOTNET
191 elif version == 'LONGHORN':
192 client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
194 raise CommandError('Unknown client version %s' % cli_version)
195 return client_version
198 def print_serverinfo(outf, typeid, serverinfo):
199 outf.write(' dwVersion : 0x%x\n' % serverinfo.dwVersion)
200 outf.write(' fBootMethod : %s\n' % boot_method_string(serverinfo.fBootMethod))
201 outf.write(' fAdminConfigured : %s\n' % bool_string(serverinfo.fAdminConfigured))
202 outf.write(' fAllowUpdate : %s\n' % bool_string(serverinfo.fAllowUpdate))
203 outf.write(' fDsAvailable : %s\n' % bool_string(serverinfo.fDsAvailable))
204 outf.write(' pszServerName : %s\n' % serverinfo.pszServerName)
205 outf.write(' pszDsContainer : %s\n' % serverinfo.pszDsContainer)
207 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO:
208 outf.write(' aipServerAddrs : %s\n' %
209 ip4_array_string(serverinfo.aipServerAddrs))
210 outf.write(' aipListenAddrs : %s\n' %
211 ip4_array_string(serverinfo.aipListenAddrs))
212 outf.write(' aipForwarders : %s\n' %
213 ip4_array_string(serverinfo.aipForwarders))
215 outf.write(' aipServerAddrs : %s\n' %
216 dns_addr_array_string(serverinfo.aipServerAddrs))
217 outf.write(' aipListenAddrs : %s\n' %
218 dns_addr_array_string(serverinfo.aipListenAddrs))
219 outf.write(' aipForwarders : %s\n' %
220 dns_addr_array_string(serverinfo.aipForwarders))
222 outf.write(' dwLogLevel : %d\n' % serverinfo.dwLogLevel)
223 outf.write(' dwDebugLevel : %d\n' % serverinfo.dwDebugLevel)
224 outf.write(' dwForwardTimeout : %d\n' % serverinfo.dwForwardTimeout)
225 outf.write(' dwRpcPrototol : 0x%x\n' % serverinfo.dwRpcProtocol)
226 outf.write(' dwNameCheckFlag : %s\n' % name_check_flag_string(serverinfo.dwNameCheckFlag))
227 outf.write(' cAddressAnswerLimit : %d\n' % serverinfo.cAddressAnswerLimit)
228 outf.write(' dwRecursionRetry : %d\n' % serverinfo.dwRecursionRetry)
229 outf.write(' dwRecursionTimeout : %d\n' % serverinfo.dwRecursionTimeout)
230 outf.write(' dwMaxCacheTtl : %d\n' % serverinfo.dwMaxCacheTtl)
231 outf.write(' dwDsPollingInterval : %d\n' % serverinfo.dwDsPollingInterval)
232 outf.write(' dwScavengingInterval : %d\n' % serverinfo.dwScavengingInterval)
233 outf.write(' dwDefaultRefreshInterval : %d\n' % serverinfo.dwDefaultRefreshInterval)
234 outf.write(' dwDefaultNoRefreshInterval : %d\n' % serverinfo.dwDefaultNoRefreshInterval)
235 outf.write(' fAutoReverseZones : %s\n' % bool_string(serverinfo.fAutoReverseZones))
236 outf.write(' fAutoCacheUpdate : %s\n' % bool_string(serverinfo.fAutoCacheUpdate))
237 outf.write(' fRecurseAfterForwarding : %s\n' % bool_string(serverinfo.fRecurseAfterForwarding))
238 outf.write(' fForwardDelegations : %s\n' % bool_string(serverinfo.fForwardDelegations))
239 outf.write(' fNoRecursion : %s\n' % bool_string(serverinfo.fNoRecursion))
240 outf.write(' fSecureResponses : %s\n' % bool_string(serverinfo.fSecureResponses))
241 outf.write(' fRoundRobin : %s\n' % bool_string(serverinfo.fRoundRobin))
242 outf.write(' fLocalNetPriority : %s\n' % bool_string(serverinfo.fLocalNetPriority))
243 outf.write(' fBindSecondaries : %s\n' % bool_string(serverinfo.fBindSecondaries))
244 outf.write(' fWriteAuthorityNs : %s\n' % bool_string(serverinfo.fWriteAuthorityNs))
245 outf.write(' fStrictFileParsing : %s\n' % bool_string(serverinfo.fStrictFileParsing))
246 outf.write(' fLooseWildcarding : %s\n' % bool_string(serverinfo.fLooseWildcarding))
247 outf.write(' fDefaultAgingState : %s\n' % bool_string(serverinfo.fDefaultAgingState))
249 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO_W2K:
250 outf.write(' dwRpcStructureVersion : 0x%x\n' % serverinfo.dwRpcStructureVersion)
251 outf.write(' aipLogFilter : %s\n' % dns_addr_array_string(serverinfo.aipLogFilter))
252 outf.write(' pwszLogFilePath : %s\n' % serverinfo.pwszLogFilePath)
253 outf.write(' pszDomainName : %s\n' % serverinfo.pszDomainName)
254 outf.write(' pszForestName : %s\n' % serverinfo.pszForestName)
255 outf.write(' pszDomainDirectoryPartition : %s\n' % serverinfo.pszDomainDirectoryPartition)
256 outf.write(' pszForestDirectoryPartition : %s\n' % serverinfo.pszForestDirectoryPartition)
258 outf.write(' dwLocalNetPriorityNetMask : 0x%x\n' % serverinfo.dwLocalNetPriorityNetMask)
259 outf.write(' dwLastScavengeTime : %d\n' % serverinfo.dwLastScavengeTime)
260 outf.write(' dwEventLogLevel : %d\n' % serverinfo.dwEventLogLevel)
261 outf.write(' dwLogFileMaxSize : %d\n' % serverinfo.dwLogFileMaxSize)
262 outf.write(' dwDsForestVersion : %d\n' % serverinfo.dwDsForestVersion)
263 outf.write(' dwDsDomainVersion : %d\n' % serverinfo.dwDsDomainVersion)
264 outf.write(' dwDsDsaVersion : %d\n' % serverinfo.dwDsDsaVersion)
266 if typeid == dnsserver.DNSSRV_TYPEID_SERVER_INFO:
267 outf.write(' fReadOnlyDC : %s\n' % bool_string(serverinfo.fReadOnlyDC))
270 def print_zoneinfo(outf, typeid, zoneinfo):
271 outf.write(' pszZoneName : %s\n' % zoneinfo.pszZoneName)
272 outf.write(' dwZoneType : %s\n' % zone_type_string(zoneinfo.dwZoneType))
273 outf.write(' fReverse : %s\n' % bool_string(zoneinfo.fReverse))
274 outf.write(' fAllowUpdate : %s\n' % zone_update_string(zoneinfo.fAllowUpdate))
275 outf.write(' fPaused : %s\n' % bool_string(zoneinfo.fPaused))
276 outf.write(' fShutdown : %s\n' % bool_string(zoneinfo.fShutdown))
277 outf.write(' fAutoCreated : %s\n' % bool_string(zoneinfo.fAutoCreated))
278 outf.write(' fUseDatabase : %s\n' % bool_string(zoneinfo.fUseDatabase))
279 outf.write(' pszDataFile : %s\n' % zoneinfo.pszDataFile)
280 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
281 outf.write(' aipMasters : %s\n' %
282 ip4_array_string(zoneinfo.aipMasters))
284 outf.write(' aipMasters : %s\n' %
285 dns_addr_array_string(zoneinfo.aipMasters))
286 outf.write(' fSecureSecondaries : %s\n' % zone_secondary_security_string(zoneinfo.fSecureSecondaries))
287 outf.write(' fNotifyLevel : %s\n' % zone_notify_level_string(zoneinfo.fNotifyLevel))
288 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
289 outf.write(' aipSecondaries : %s\n' %
290 ip4_array_string(zoneinfo.aipSecondaries))
291 outf.write(' aipNotify : %s\n' %
292 ip4_array_string(zoneinfo.aipNotify))
294 outf.write(' aipSecondaries : %s\n' %
295 dns_addr_array_string(zoneinfo.aipSecondaries))
296 outf.write(' aipNotify : %s\n' %
297 dns_addr_array_string(zoneinfo.aipNotify))
298 outf.write(' fUseWins : %s\n' % bool_string(zoneinfo.fUseWins))
299 outf.write(' fUseNbstat : %s\n' % bool_string(zoneinfo.fUseNbstat))
300 outf.write(' fAging : %s\n' % bool_string(zoneinfo.fAging))
301 outf.write(' dwNoRefreshInterval : %d\n' % zoneinfo.dwNoRefreshInterval)
302 outf.write(' dwRefreshInterval : %d\n' % zoneinfo.dwRefreshInterval)
303 outf.write(' dwAvailForScavengeTime : %d\n' % zoneinfo.dwAvailForScavengeTime)
304 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
305 outf.write(' aipScavengeServers : %s\n' %
306 ip4_array_string(zoneinfo.aipScavengeServers))
308 outf.write(' aipScavengeServers : %s\n' %
309 dns_addr_array_string(zoneinfo.aipScavengeServers))
311 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO_W2K:
312 outf.write(' dwRpcStructureVersion : 0x%x\n' % zoneinfo.dwRpcStructureVersion)
313 outf.write(' dwForwarderTimeout : %d\n' % zoneinfo.dwForwarderTimeout)
314 outf.write(' fForwarderSlave : %d\n' % zoneinfo.fForwarderSlave)
315 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
316 outf.write(' aipLocalMasters : %s\n' %
317 ip4_array_string(zoneinfo.aipLocalMasters))
319 outf.write(' aipLocalMasters : %s\n' %
320 dns_addr_array_string(zoneinfo.aipLocalMasters))
321 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zoneinfo.dwDpFlags))
322 outf.write(' pszDpFqdn : %s\n' % zoneinfo.pszDpFqdn)
323 outf.write(' pwszZoneDn : %s\n' % zoneinfo.pwszZoneDn)
324 outf.write(' dwLastSuccessfulSoaCheck : %d\n' % zoneinfo.dwLastSuccessfulSoaCheck)
325 outf.write(' dwLastSuccessfulXfr : %d\n' % zoneinfo.dwLastSuccessfulXfr)
327 if typeid == dnsserver.DNSSRV_TYPEID_ZONE_INFO:
328 outf.write(' fQueuedForBackgroundLoad : %s\n' % bool_string(zoneinfo.fQueuedForBackgroundLoad))
329 outf.write(' fBackgroundLoadInProgress : %s\n' % bool_string(zoneinfo.fBackgroundLoadInProgress))
330 outf.write(' fReadOnlyZone : %s\n' % bool_string(zoneinfo.fReadOnlyZone))
331 outf.write(' dwLastXfrAttempt : %d\n' % zoneinfo.dwLastXfrAttempt)
332 outf.write(' dwLastXfrResult : %d\n' % zoneinfo.dwLastXfrResult)
335 def print_zone(outf, typeid, zone):
336 outf.write(' pszZoneName : %s\n' % zone.pszZoneName)
337 outf.write(' Flags : %s\n' % zone_flags_string(zone.Flags))
338 outf.write(' ZoneType : %s\n' % zone_type_string(zone.ZoneType))
339 outf.write(' Version : %s\n' % zone.Version)
341 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_W2K:
342 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zone.dwDpFlags))
343 outf.write(' pszDpFqdn : %s\n' % zone.pszDpFqdn)
346 def print_enumzones(outf, typeid, zones):
347 outf.write(' %d zone(s) found\n' % zones.dwZoneCount)
348 for zone in zones.ZoneArray:
350 print_zone(outf, typeid, zone)
353 def print_dns_record(outf, rec):
354 if rec.wType == dnsp.DNS_TYPE_A:
355 mesg = 'A: %s' % (rec.data)
356 elif rec.wType == dnsp.DNS_TYPE_AAAA:
357 mesg = 'AAAA: %s' % (rec.data)
358 elif rec.wType == dnsp.DNS_TYPE_PTR:
359 mesg = 'PTR: %s' % (rec.data.str)
360 elif rec.wType == dnsp.DNS_TYPE_NS:
361 mesg = 'NS: %s' % (rec.data.str)
362 elif rec.wType == dnsp.DNS_TYPE_CNAME:
363 mesg = 'CNAME: %s' % (rec.data.str)
364 elif rec.wType == dnsp.DNS_TYPE_SOA:
365 mesg = 'SOA: serial=%d, refresh=%d, retry=%d, expire=%d, minttl=%d, ns=%s, email=%s' % (
370 rec.data.dwMinimumTtl,
371 rec.data.NamePrimaryServer.str,
372 rec.data.ZoneAdministratorEmail.str)
373 elif rec.wType == dnsp.DNS_TYPE_MX:
374 mesg = 'MX: %s (%d)' % (rec.data.nameExchange.str, rec.data.wPreference)
375 elif rec.wType == dnsp.DNS_TYPE_SRV:
376 mesg = 'SRV: %s (%d, %d, %d)' % (rec.data.nameTarget.str, rec.data.wPort,
377 rec.data.wPriority, rec.data.wWeight)
378 elif rec.wType == dnsp.DNS_TYPE_TXT:
379 slist = ['"%s"' % name.str for name in rec.data.str]
380 mesg = 'TXT: %s' % ','.join(slist)
383 outf.write(' %s (flags=%x, serial=%d, ttl=%d)\n' % (
384 mesg, rec.dwFlags, rec.dwSerial, rec.dwTtlSeconds))
387 def print_dnsrecords(outf, records):
388 for rec in records.rec:
389 outf.write(' Name=%s, Records=%d, Children=%d\n' % (
393 for dns_rec in rec.records:
394 print_dns_record(outf, dns_rec)
398 # Always create a copy of strings when creating DNS_RPC_RECORDs
399 # to overcome the bug in pidl generated python bindings.
402 class ARecord(dnsserver.DNS_RPC_RECORD):
403 def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
405 super(ARecord, self).__init__()
406 self.wType = dnsp.DNS_TYPE_A
407 self.dwFlags = rank | node_flag
408 self.dwSerial = serial
409 self.dwTtlSeconds = ttl
410 self._ip_addr = ip_addr[:]
411 self.data = self._ip_addr
414 class AAAARecord(dnsserver.DNS_RPC_RECORD):
416 def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
418 super(AAAARecord, self).__init__()
419 self.wType = dnsp.DNS_TYPE_AAAA
420 self.dwFlags = rank | node_flag
421 self.dwSerial = serial
422 self.dwTtlSeconds = ttl
423 self._ip6_addr = ip6_addr[:]
424 self.data = self._ip6_addr
427 class PTRRecord(dnsserver.DNS_RPC_RECORD):
429 def __init__(self, ptr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
431 super(PTRRecord, self).__init__()
432 self.wType = dnsp.DNS_TYPE_PTR
433 self.dwFlags = rank | node_flag
434 self.dwSerial = serial
435 self.dwTtlSeconds = ttl
437 ptr_name = dnsserver.DNS_RPC_NAME()
438 ptr_name.str = self._ptr
439 ptr_name.len = len(ptr)
443 class CNameRecord(dnsserver.DNS_RPC_RECORD):
445 def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
447 super(CNameRecord, self).__init__()
448 self.wType = dnsp.DNS_TYPE_CNAME
449 self.dwFlags = rank | node_flag
450 self.dwSerial = serial
451 self.dwTtlSeconds = ttl
452 self._cname = cname[:]
453 cname_name = dnsserver.DNS_RPC_NAME()
454 cname_name.str = self._cname
455 cname_name.len = len(cname)
456 self.data = cname_name
459 class NSRecord(dnsserver.DNS_RPC_RECORD):
461 def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
463 super(NSRecord, self).__init__()
464 self.wType = dnsp.DNS_TYPE_NS
465 self.dwFlags = rank | node_flag
466 self.dwSerial = serial
467 self.dwTtlSeconds = ttl
468 self._dns_server = dns_server[:]
469 ns = dnsserver.DNS_RPC_NAME()
470 ns.str = self._dns_server
471 ns.len = len(dns_server)
475 class MXRecord(dnsserver.DNS_RPC_RECORD):
477 def __init__(self, mail_server, preference, serial=1, ttl=900,
478 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
479 super(MXRecord, self).__init__()
480 self.wType = dnsp.DNS_TYPE_MX
481 self.dwFlags = rank | node_flag
482 self.dwSerial = serial
483 self.dwTtlSeconds = ttl
484 self._mail_server = mail_server[:]
485 mx = dnsserver.DNS_RPC_RECORD_NAME_PREFERENCE()
486 mx.wPreference = preference
487 mx.nameExchange.str = self._mail_server
488 mx.nameExchange.len = len(mail_server)
492 class SOARecord(dnsserver.DNS_RPC_RECORD):
494 def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
495 expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE,
496 node_flag=dnsp.DNS_RPC_FLAG_AUTH_ZONE_ROOT):
497 super(SOARecord, self).__init__()
498 self.wType = dnsp.DNS_TYPE_SOA
499 self.dwFlags = rank | node_flag
500 self.dwSerial = serial
501 self.dwTtlSeconds = ttl
502 self._mname = mname[:]
503 self._rname = rname[:]
504 soa = dnsserver.DNS_RPC_RECORD_SOA()
505 soa.dwSerialNo = serial
506 soa.dwRefresh = refresh
508 soa.dwExpire = expire
509 soa.dwMinimumTtl = minimum
510 soa.NamePrimaryServer.str = self._mname
511 soa.NamePrimaryServer.len = len(mname)
512 soa.ZoneAdministratorEmail.str = self._rname
513 soa.ZoneAdministratorEmail.len = len(rname)
517 class SRVRecord(dnsserver.DNS_RPC_RECORD):
519 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
520 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
521 super(SRVRecord, self).__init__()
522 self.wType = dnsp.DNS_TYPE_SRV
523 self.dwFlags = rank | node_flag
524 self.dwSerial = serial
525 self.dwTtlSeconds = ttl
526 self._target = target[:]
527 srv = dnsserver.DNS_RPC_RECORD_SRV()
528 srv.wPriority = priority
531 srv.nameTarget.str = self._target
532 srv.nameTarget.len = len(target)
536 class TXTRecord(dnsserver.DNS_RPC_RECORD):
538 def __init__(self, slist, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
540 super(TXTRecord, self).__init__()
541 self.wType = dnsp.DNS_TYPE_TXT
542 self.dwFlags = rank | node_flag
543 self.dwSerial = serial
544 self.dwTtlSeconds = ttl
547 self._slist.append(s[:])
549 for s in self._slist:
550 name = dnsserver.DNS_RPC_NAME()
554 txt = dnsserver.DNS_RPC_RECORD_STRING()
555 txt.count = len(slist)
560 # Convert data into a dns record
561 def data_to_dns_record(record_type, data):
562 if record_type == dnsp.DNS_TYPE_A:
564 elif record_type == dnsp.DNS_TYPE_AAAA:
565 rec = AAAARecord(data)
566 elif record_type == dnsp.DNS_TYPE_PTR:
567 rec = PTRRecord(data)
568 elif record_type == dnsp.DNS_TYPE_CNAME:
569 rec = CNameRecord(data)
570 elif record_type == dnsp.DNS_TYPE_NS:
572 elif record_type == dnsp.DNS_TYPE_MX:
573 tmp = data.split(' ')
575 raise CommandError('Data requires 2 elements - mail_server, preference')
577 preference = int(tmp[1])
578 rec = MXRecord(mail_server, preference)
579 elif record_type == dnsp.DNS_TYPE_SRV:
580 tmp = data.split(' ')
582 raise CommandError('Data requires 4 elements - server, port, priority, weight')
585 priority = int(tmp[2])
587 rec = SRVRecord(server, port, priority=priority, weight=weight)
588 elif record_type == dnsp.DNS_TYPE_SOA:
589 tmp = data.split(' ')
591 raise CommandError('Data requires 7 elements - nameserver, email, serial, '
592 'refresh, retry, expire, minimumttl')
596 refresh = int(tmp[3])
599 minimum = int(tmp[6])
600 rec = SOARecord(nameserver, email, serial=serial, refresh=refresh,
601 retry=retry, expire=expire, minimum=minimum)
602 elif record_type == dnsp.DNS_TYPE_TXT:
603 slist = shlex.split(data)
604 rec = TXTRecord(slist)
606 raise CommandError('Unsupported record type')
610 # Match dns name (of type DNS_RPC_NAME)
611 def dns_name_equal(n1, n2):
612 return n1.str.rstrip('.').lower() == n2.str.rstrip('.').lower()
615 # Match a dns record with specified data
616 def dns_record_match(dns_conn, server, zone, name, record_type, data):
617 urec = data_to_dns_record(record_type, data)
619 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
622 buflen, res = dns_conn.DnssrvEnumRecords2(
623 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name, None,
624 record_type, select_flags, None, None)
625 except RuntimeError, e:
628 if not res or res.count == 0:
632 for rec in res.rec[0].records:
633 if rec.wType != record_type:
637 if record_type == dnsp.DNS_TYPE_A:
638 if rec.data == urec.data:
640 elif record_type == dnsp.DNS_TYPE_AAAA:
641 if rec.data == urec.data:
643 elif record_type == dnsp.DNS_TYPE_PTR:
644 if dns_name_equal(rec.data, urec.data):
646 elif record_type == dnsp.DNS_TYPE_CNAME:
647 if dns_name_equal(rec.data, urec.data):
649 elif record_type == dnsp.DNS_TYPE_NS:
650 if dns_name_equal(rec.data, urec.data):
652 elif record_type == dnsp.DNS_TYPE_MX:
653 if dns_name_equal(rec.data.nameExchange, urec.data.nameExchange) and \
654 rec.data.wPreference == urec.data.wPreference:
656 elif record_type == dnsp.DNS_TYPE_SRV:
657 if rec.data.wPriority == urec.data.wPriority and \
658 rec.data.wWeight == urec.data.wWeight and \
659 rec.data.wPort == urec.data.wPort and \
660 dns_name_equal(rec.data.nameTarget, urec.data.nameTarget):
662 elif record_type == dnsp.DNS_TYPE_SOA:
663 if rec.data.dwSerialNo == urec.data.dwSerialNo and \
664 rec.data.dwRefresh == urec.data.dwRefresh and \
665 rec.data.dwRetry == urec.data.dwRetry and \
666 rec.data.dwExpire == urec.data.dwExpire and \
667 rec.data.dwMinimumTtl == urec.data.dwMinimumTtl and \
668 dns_name_equal(rec.data.NamePrimaryServer,
669 urec.data.NamePrimaryServer) and \
670 dns_name_equal(rec.data.ZoneAdministratorEmail,
671 urec.data.ZoneAdministratorEmail):
673 elif record_type == dnsp.DNS_TYPE_TXT:
674 if rec.data.count == urec.data.count:
676 for i in xrange(rec.data.count):
678 (rec.data.str[i].str == urec.data.str[i].str)
687 class cmd_serverinfo(Command):
688 """Query for Server information."""
690 synopsis = '%prog <server> [options]'
692 takes_args = [ 'server' ]
694 takes_optiongroups = {
695 "sambaopts": options.SambaOptions,
696 "versionopts": options.VersionOptions,
697 "credopts": options.CredentialsOptions,
701 Option('--client-version', help='Client Version',
702 default='longhorn', metavar='w2k|dotnet|longhorn',
703 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
706 def run(self, server, cli_ver, sambaopts=None, credopts=None,
708 self.lp = sambaopts.get_loadparm()
709 self.creds = credopts.get_credentials(self.lp)
710 dns_conn = dns_connect(server, self.lp, self.creds)
712 client_version = dns_client_version(cli_ver)
714 typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server,
716 print_serverinfo(self.outf, typeid, res)
719 class cmd_zoneinfo(Command):
720 """Query for zone information."""
722 synopsis = '%prog <server> <zone> [options]'
724 takes_args = [ 'server', 'zone' ]
726 takes_optiongroups = {
727 "sambaopts": options.SambaOptions,
728 "versionopts": options.VersionOptions,
729 "credopts": options.CredentialsOptions,
733 Option('--client-version', help='Client Version',
734 default='longhorn', metavar='w2k|dotnet|longhorn',
735 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
738 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
740 self.lp = sambaopts.get_loadparm()
741 self.creds = credopts.get_credentials(self.lp)
742 dns_conn = dns_connect(server, self.lp, self.creds)
744 client_version = dns_client_version(cli_ver)
746 typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server, zone,
748 print_zoneinfo(self.outf, typeid, res)
751 class cmd_zonelist(Command):
752 """Query for zones."""
754 synopsis = '%prog <server> [options]'
756 takes_args = [ 'server' ]
758 takes_optiongroups = {
759 "sambaopts": options.SambaOptions,
760 "versionopts": options.VersionOptions,
761 "credopts": options.CredentialsOptions,
765 Option('--client-version', help='Client Version',
766 default='longhorn', metavar='w2k|dotnet|longhorn',
767 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
768 Option('--primary', help='List primary zones (default)',
769 action='store_true', dest='primary'),
770 Option('--secondary', help='List secondary zones',
771 action='store_true', dest='secondary'),
772 Option('--cache', help='List cached zones',
773 action='store_true', dest='cache'),
774 Option('--auto', help='List automatically created zones',
775 action='store_true', dest='auto'),
776 Option('--forward', help='List forward zones',
777 action='store_true', dest='forward'),
778 Option('--reverse', help='List reverse zones',
779 action='store_true', dest='reverse'),
780 Option('--ds', help='List directory integrated zones',
781 action='store_true', dest='ds'),
782 Option('--non-ds', help='List non-directory zones',
783 action='store_true', dest='nonds')
786 def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
787 auto=False, forward=False, reverse=False, ds=False, nonds=False,
788 sambaopts=None, credopts=None, versionopts=None):
792 request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
794 request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
796 request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
798 request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
800 request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
802 request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
804 request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
806 request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
808 if request_filter == 0:
809 request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
811 self.lp = sambaopts.get_loadparm()
812 self.creds = credopts.get_credentials(self.lp)
813 dns_conn = dns_connect(server, self.lp, self.creds)
815 client_version = dns_client_version(cli_ver)
817 typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
820 dnsserver.DNSSRV_TYPEID_DWORD,
823 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
824 typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
826 typeid = dnsserver.DNSSRV_TYPEID_ZONE
827 print_enumzones(self.outf, typeid, res)
830 class cmd_zonecreate(Command):
833 synopsis = '%prog <server> <zone> [options]'
835 takes_args = [ 'server', 'zone' ]
837 takes_optiongroups = {
838 "sambaopts": options.SambaOptions,
839 "versionopts": options.VersionOptions,
840 "credopts": options.CredentialsOptions,
844 Option('--client-version', help='Client Version',
845 default='longhorn', metavar='w2k|dotnet|longhorn',
846 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
849 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
852 self.lp = sambaopts.get_loadparm()
853 self.creds = credopts.get_credentials(self.lp)
854 dns_conn = dns_connect(server, self.lp, self.creds)
858 client_version = dns_client_version(cli_ver)
859 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
860 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
861 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
862 zone_create_info.pszZoneName = zone
863 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
864 zone_create_info.fAging = 0
865 zone_create_info.fDsIntegrated = 1
866 zone_create_info.fLoadExisting = 1
867 elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
868 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
869 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
870 zone_create_info.pszZoneName = zone
871 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
872 zone_create_info.fAging = 0
873 zone_create_info.fDsIntegrated = 1
874 zone_create_info.fLoadExisting = 1
875 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
877 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
878 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
879 zone_create_info.pszZoneName = zone
880 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
881 zone_create_info.fAging = 0
882 zone_create_info.fDsIntegrated = 1
883 zone_create_info.fLoadExisting = 1
884 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
886 res = dns_conn.DnssrvOperation2(client_version, 0, server, None,
887 0, 'ZoneCreate', typeid,
890 typeid = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM
891 name_and_param = dnsserver.DNS_RPC_NAME_AND_PARAM()
892 name_and_param.pszNodeName = 'AllowUpdate'
893 name_and_param.dwParam = dnsp.DNS_ZONE_UPDATE_SECURE
895 res = dns_conn.DnssrvOperation2(client_version, 0, server, zone,
896 0, 'ResetDwordProperty', typeid,
898 self.outf.write('Zone %s created successfully\n' % zone)
901 class cmd_zonedelete(Command):
904 synopsis = '%prog <server> <zone> [options]'
906 takes_args = [ 'server', 'zone' ]
908 takes_optiongroups = {
909 "sambaopts": options.SambaOptions,
910 "versionopts": options.VersionOptions,
911 "credopts": options.CredentialsOptions,
914 def run(self, server, zone, sambaopts=None, credopts=None,
917 self.lp = sambaopts.get_loadparm()
918 self.creds = credopts.get_credentials(self.lp)
919 dns_conn = dns_connect(server, self.lp, self.creds)
922 res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
923 0, server, zone, 0, 'DeleteZoneFromDs',
924 dnsserver.DNSSRV_TYPEID_NULL,
926 self.outf.write('Zone %s delete successfully\n' % zone)
929 class cmd_query(Command):
932 synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|TXT|ALL> [options]'
934 takes_args = [ 'server', 'zone', 'name', 'rtype' ]
936 takes_optiongroups = {
937 "sambaopts": options.SambaOptions,
938 "versionopts": options.VersionOptions,
939 "credopts": options.CredentialsOptions,
943 Option('--authority', help='Search authoritative records (default)',
944 action='store_true', dest='authority'),
945 Option('--cache', help='Search cached records',
946 action='store_true', dest='cache'),
947 Option('--glue', help='Search glue records',
948 action='store_true', dest='glue'),
949 Option('--root', help='Search root hints',
950 action='store_true', dest='root'),
951 Option('--additional', help='List additional records',
952 action='store_true', dest='additional'),
953 Option('--no-children', help='Do not list children',
954 action='store_true', dest='no_children'),
955 Option('--only-children', help='List only children',
956 action='store_true', dest='only_children')
959 def run(self, server, zone, name, rtype, authority=False, cache=False,
960 glue=False, root=False, additional=False, no_children=False,
961 only_children=False, sambaopts=None, credopts=None,
963 record_type = dns_type_flag(rtype)
965 if name.find('*') != -1:
966 raise CommandError('Wildcard searches not supported. To dump entire zone use "@"')
970 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
972 select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
974 select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
976 select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
978 select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
980 select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
982 select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
984 if select_flags == 0:
985 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
987 if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
988 self.outf.write('Specify either --authority or --root along with --additional.\n')
989 self.outf.write('Assuming --authority.\n')
990 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
992 self.lp = sambaopts.get_loadparm()
993 self.creds = credopts.get_credentials(self.lp)
994 dns_conn = dns_connect(server, self.lp, self.creds)
996 buflen, res = dns_conn.DnssrvEnumRecords2(
997 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name,
998 None, record_type, select_flags, None, None)
999 print_dnsrecords(self.outf, res)
1002 class cmd_roothints(Command):
1003 """Query root hints."""
1005 synopsis = '%prog <server> [<name>] [options]'
1007 takes_args = [ 'server', 'name?' ]
1009 takes_optiongroups = {
1010 "sambaopts": options.SambaOptions,
1011 "versionopts": options.VersionOptions,
1012 "credopts": options.CredentialsOptions,
1015 def run(self, server, name='.', sambaopts=None, credopts=None,
1017 record_type = dnsp.DNS_TYPE_NS
1018 select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
1019 dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
1021 self.lp = sambaopts.get_loadparm()
1022 self.creds = credopts.get_credentials(self.lp)
1023 dns_conn = dns_connect(server, self.lp, self.creds)
1025 buflen, res = dns_conn.DnssrvEnumRecords2(
1026 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, '..RootHints',
1027 name, None, record_type, select_flags, None, None)
1028 print_dnsrecords(self.outf, res)
1031 class cmd_add_record(Command):
1034 For each type data contents are as follows:
1035 A ipv4_address_string
1036 AAAA ipv6_address_string
1040 MX "fqdn_string preference"
1041 SRV "fqdn_string port priority weight"
1042 TXT "'string1' 'string2' ..."
1045 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>'
1047 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
1049 takes_optiongroups = {
1050 "sambaopts": options.SambaOptions,
1051 "versionopts": options.VersionOptions,
1052 "credopts": options.CredentialsOptions,
1055 def run(self, server, zone, name, rtype, data, sambaopts=None,
1056 credopts=None, versionopts=None):
1058 if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV','TXT'):
1059 raise CommandError('Adding record of type %s is not supported' % rtype)
1061 record_type = dns_type_flag(rtype)
1062 rec = data_to_dns_record(record_type, data)
1064 self.lp = sambaopts.get_loadparm()
1065 self.creds = credopts.get_credentials(self.lp)
1066 dns_conn = dns_connect(server, self.lp, self.creds)
1068 rec_match = dns_record_match(dns_conn, server, zone, name, record_type,
1070 if rec_match is not None:
1071 raise CommandError('Record already exists')
1073 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1074 add_rec_buf.rec = rec
1076 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1077 0, server, zone, name, add_rec_buf, None)
1078 self.outf.write('Record added successfully\n')
1081 class cmd_update_record(Command):
1082 """Update a DNS record
1084 For each type data contents are as follows:
1085 A ipv4_address_string
1086 AAAA ipv6_address_string
1090 MX "fqdn_string preference"
1091 SOA "fqdn_dns fqdn_email serial refresh retry expire minimumttl"
1092 SRV "fqdn_string port priority weight"
1093 TXT "'string1' 'string2' ..."
1096 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SOA|SRV|TXT> <olddata> <newdata>'
1098 takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
1100 takes_optiongroups = {
1101 "sambaopts": options.SambaOptions,
1102 "versionopts": options.VersionOptions,
1103 "credopts": options.CredentialsOptions,
1106 def run(self, server, zone, name, rtype, olddata, newdata,
1107 sambaopts=None, credopts=None, versionopts=None):
1109 if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SOA','SRV','TXT'):
1110 raise CommandError('Updating record of type %s is not supported' % rtype)
1112 record_type = dns_type_flag(rtype)
1113 rec = data_to_dns_record(record_type, newdata)
1115 self.lp = sambaopts.get_loadparm()
1116 self.creds = credopts.get_credentials(self.lp)
1117 dns_conn = dns_connect(server, self.lp, self.creds)
1119 rec_match = dns_record_match(dns_conn, server, zone, name, record_type,
1122 raise CommandError('Record does not exist')
1124 # Copy properties from existing record to new record
1125 rec.dwFlags = rec_match.dwFlags
1126 rec.dwSerial = rec_match.dwSerial
1127 rec.dwTtlSeconds = rec_match.dwTtlSeconds
1128 rec.dwTimeStamp = rec_match.dwTimeStamp
1130 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1131 add_rec_buf.rec = rec
1133 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1134 del_rec_buf.rec = rec_match
1136 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1143 self.outf.write('Record updated successfully\n')
1146 class cmd_delete_record(Command):
1147 """Delete a DNS record
1149 For each type data contents are as follows:
1150 A ipv4_address_string
1151 AAAA ipv6_address_string
1155 MX "fqdn_string preference"
1156 SRV "fqdn_string port priority weight"
1157 TXT "'string1' 'string2' ..."
1160 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>'
1162 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
1164 takes_optiongroups = {
1165 "sambaopts": options.SambaOptions,
1166 "versionopts": options.VersionOptions,
1167 "credopts": options.CredentialsOptions,
1170 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
1172 if rtype.upper() not in ('A','AAAA','PTR','CNAME','NS','MX','SRV','TXT'):
1173 raise CommandError('Deleting record of type %s is not supported' % rtype)
1175 record_type = dns_type_flag(rtype)
1177 self.lp = sambaopts.get_loadparm()
1178 self.creds = credopts.get_credentials(self.lp)
1179 dns_conn = dns_connect(server, self.lp, self.creds)
1181 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
1183 raise CommandError('Record does not exist')
1185 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1186 del_rec_buf.rec = rec_match
1188 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1195 self.outf.write('Record deleted successfully\n')
1198 class cmd_dns(SuperCommand):
1199 """Domain Name Service (DNS) management."""
1202 subcommands['serverinfo'] = cmd_serverinfo()
1203 subcommands['zoneinfo'] = cmd_zoneinfo()
1204 subcommands['zonelist'] = cmd_zonelist()
1205 subcommands['zonecreate'] = cmd_zonecreate()
1206 subcommands['zonedelete'] = cmd_zonedelete()
1207 subcommands['query'] = cmd_query()
1208 subcommands['roothints'] = cmd_roothints()
1209 subcommands['add'] = cmd_add_record()
1210 subcommands['update'] = cmd_update_record()
1211 subcommands['delete'] = cmd_delete_record()