5 # Copyright (C) Amitay Isaacs 2011
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # You should have received a copy of the GNU General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
21 import samba.getopt as options
22 from struct import pack
23 from socket import inet_ntoa
25 from samba.netcmd import (
31 from samba.dcerpc import dnsp, dnsserver
34 def dns_connect(server, lp, creds):
35 binding_str = "ncacn_ip_tcp:%s[sign]" % server
36 dns_conn = dnsserver.dnsserver(binding_str, lp, creds)
39 def bool_string(flag):
45 ret = 'UNKNOWN (0x%x)' % flag
48 def enum_string(module, enum_defs, value):
51 if value == getattr(module, e):
55 ret = 'UNKNOWN (0x%x)' % value
58 def bitmap_string(module, bitmap_defs, value):
61 if value & getattr(module, b):
67 def boot_method_string(boot_method):
68 enum_defs = [ 'DNS_BOOT_METHOD_UNINITIALIZED', 'DNS_BOOT_METHOD_FILE',
69 'DNS_BOOT_METHOD_REGISTRY', 'DNS_BOOT_METHOD_DIRECTORY' ]
70 return enum_string(dnsserver, enum_defs, boot_method)
72 def name_check_flag_string(check_flag):
73 enum_defs = [ 'DNS_ALLOW_RFC_NAMES_ONLY', 'DNS_ALLOW_NONRFC_NAMES',
74 'DNS_ALLOW_MULTIBYTE_NAMES', 'DNS_ALLOW_ALL_NAMES' ]
75 return enum_string(dnsserver, enum_defs, check_flag)
77 def zone_type_string(zone_type):
78 enum_defs = [ 'DNS_ZONE_TYPE_CACHE', 'DNS_ZONE_TYPE_PRIMARY',
79 'DNS_ZONE_TYPE_SECONDARY', 'DNS_ZONE_TYPE_STUB',
80 'DNS_ZONE_TYPE_FORWARDER', 'DNS_ZONE_TYPE_SECONDARY_CACHE' ]
81 return enum_string(dnsp, enum_defs, zone_type)
83 def zone_update_string(zone_update):
84 enum_defs = [ 'DNS_ZONE_UPDATE_OFF', 'DNS_ZONE_UPDATE_SECURE',
85 'DNS_ZONE_UPDATE_SECURE' ]
86 return enum_string(dnsp, enum_defs, zone_update)
88 def zone_secondary_security_string(security):
89 enum_defs = [ 'DNS_ZONE_SECSECURE_NO_SECURITY', 'DNS_ZONE_SECSECURE_NS_ONLY',
90 'DNS_ZONE_SECSECURE_LIST_ONLY', 'DNS_ZONE_SECSECURE_NO_XFER' ]
91 return enum_string(dnsserver, enum_defs, security)
93 def zone_notify_level_string(notify_level):
94 enum_defs = [ 'DNS_ZONE_NOTIFY_OFF', 'DNS_ZONE_NOTIFY_ALL_SECONDARIES',
95 'DNS_ZONE_NOTIFY_LIST_ONLY' ]
96 return enum_string(dnsserver, enum_defs, notify_level)
98 def dp_flags_string(dp_flags):
99 bitmap_defs = [ 'DNS_DP_AUTOCREATED', 'DNS_DP_LEGACY', 'DNS_DP_DOMAIN_DEFAULT',
100 'DNS_DP_FOREST_DEFAULT', 'DNS_DP_ENLISTED', 'DNS_DP_DELETED' ]
101 return bitmap_string(dnsserver, bitmap_defs, dp_flags)
103 def zone_flags_string(flags):
104 bitmap_defs = [ 'DNS_RPC_ZONE_PAUSED', 'DNS_RPC_ZONE_SHUTDOWN',
105 'DNS_RPC_ZONE_REVERSE', 'DNS_RPC_ZONE_AUTOCREATED',
106 'DNS_RPC_ZONE_DSINTEGRATED', 'DNS_RPC_ZONE_AGING',
107 'DNS_RPC_ZONE_UPDATE_UNSECURE', 'DNS_RPC_ZONE_UPDATE_SECURE',
108 'DNS_RPC_ZONE_READONLY']
109 return bitmap_string(dnsserver, bitmap_defs, flags)
111 def ip4_array_string(array):
115 for i in xrange(array.AddrCount):
116 addr = '%s' % inet_ntoa(pack('i', array.AddrArray[i]))
120 def dns_addr_array_string(array):
124 for i in xrange(array.AddrCount):
125 if array.AddrArray[i].MaxSa[0] == 0x02:
126 addr = '%d.%d.%d.%d (%d)' % \
127 tuple(array.AddrArray[i].MaxSa[4:8] + [array.AddrArray[i].MaxSa[3]])
128 elif array.AddrArray[i].MaxSa[0] == 0x17:
129 addr = '%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x:%x%x (%d)' % \
130 tuple(array.AddrArray[i].MaxSa[4:20] + [array.AddrArray[i].MaxSa[3]])
136 def dns_type_flag(rec_type):
137 rtype = rec_type.upper()
139 record_type = dnsp.DNS_TYPE_A
140 elif rtype == 'AAAA':
141 record_type = dnsp.DNS_TYPE_AAAA
143 record_type = dnsp.DNS_TYPE_PTR
145 record_type = dnsp.DNS_TYPE_NS
146 elif rtype == 'CNAME':
147 record_type = dnsp.DNS_TYPE_CNAME
149 record_type = dnsp.DNS_TYPE_SOA
151 record_type = dnsp.DNS_TYPE_MX
153 record_type = dnsp.DNS_TYPE_SRV
155 record_type = dnsp.DNS_TYPE_ALL
157 raise CommandError('Unknown type of DNS record %s' % rec_type)
160 def dns_client_version(cli_version):
161 version = cli_version.upper()
163 client_version = dnsserver.DNS_CLIENT_VERSION_W2K
164 elif version == 'DOTNET':
165 client_version = dnsserver.DNS_CLIENT_VERSION_DOTNET
166 elif version == 'LONGHORN':
167 client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN
169 raise CommandError('Unknown client version %s' % cli_version)
170 return client_version
172 def print_serverinfo(outf, typeid, serverinfo):
173 outf.write(' dwVersion : 0x%x\n' % serverinfo.dwVersion)
174 outf.write(' fBootMethod : %s\n' % boot_method_string(serverinfo.fBootMethod))
175 outf.write(' fAdminConfigured : %s\n' % bool_string(serverinfo.fAdminConfigured))
176 outf.write(' fAllowUpdate : %s\n' % bool_string(serverinfo.fAllowUpdate))
177 outf.write(' fDsAvailable : %s\n' % bool_string(serverinfo.fDsAvailable))
178 outf.write(' pszServerName : %s\n' % serverinfo.pszServerName)
179 outf.write(' pszDsContainer : %s\n' % serverinfo.pszDsContainer)
181 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO:
182 outf.write(' aipServerAddrs : %s\n' %
183 ip4_array_string(serverinfo.aipServerAddrs))
184 outf.write(' aipListenAddrs : %s\n' %
185 ip4_array_string(serverinfo.aipListenAddrs))
186 outf.write(' aipForwarders : %s\n' %
187 ip4_array_string(serverinfo.aipForwarders))
189 outf.write(' aipServerAddrs : %s\n' %
190 dns_addr_array_string(serverinfo.aipServerAddrs))
191 outf.write(' aipListenAddrs : %s\n' %
192 dns_addr_array_string(serverinfo.aipListenAddrs))
193 outf.write(' aipForwarders : %s\n' %
194 dns_addr_array_string(serverinfo.aipForwarders))
196 outf.write(' dwLogLevel : %d\n' % serverinfo.dwLogLevel)
197 outf.write(' dwDebugLevel : %d\n' % serverinfo.dwDebugLevel)
198 outf.write(' dwForwardTimeout : %d\n' % serverinfo.dwForwardTimeout)
199 outf.write(' dwRpcPrototol : 0x%x\n' % serverinfo.dwRpcProtocol)
200 outf.write(' dwNameCheckFlag : %s\n' % name_check_flag_string(serverinfo.dwNameCheckFlag))
201 outf.write(' cAddressAnswerLimit : %d\n' % serverinfo.cAddressAnswerLimit)
202 outf.write(' dwRecursionRetry : %d\n' % serverinfo.dwRecursionRetry)
203 outf.write(' dwRecursionTimeout : %d\n' % serverinfo.dwRecursionTimeout)
204 outf.write(' dwMaxCacheTtl : %d\n' % serverinfo.dwMaxCacheTtl)
205 outf.write(' dwDsPollingInterval : %d\n' % serverinfo.dwDsPollingInterval)
206 outf.write(' dwScavengingInterval : %d\n' % serverinfo.dwScavengingInterval)
207 outf.write(' dwDefaultRefreshInterval : %d\n' % serverinfo.dwDefaultRefreshInterval)
208 outf.write(' dwDefaultNoRefreshInterval : %d\n' % serverinfo.dwDefaultNoRefreshInterval)
209 outf.write(' fAutoReverseZones : %s\n' % bool_string(serverinfo.fAutoReverseZones))
210 outf.write(' fAutoCacheUpdate : %s\n' % bool_string(serverinfo.fAutoCacheUpdate))
211 outf.write(' fRecurseAfterForwarding : %s\n' % bool_string(serverinfo.fRecurseAfterForwarding))
212 outf.write(' fForwardDelegations : %s\n' % bool_string(serverinfo.fForwardDelegations))
213 outf.write(' fNoRecursion : %s\n' % bool_string(serverinfo.fNoRecursion))
214 outf.write(' fSecureResponses : %s\n' % bool_string(serverinfo.fSecureResponses))
215 outf.write(' fRoundRobin : %s\n' % bool_string(serverinfo.fRoundRobin))
216 outf.write(' fLocalNetPriority : %s\n' % bool_string(serverinfo.fLocalNetPriority))
217 outf.write(' fBindSecondaries : %s\n' % bool_string(serverinfo.fBindSecondaries))
218 outf.write(' fWriteAuthorityNs : %s\n' % bool_string(serverinfo.fWriteAuthorityNs))
219 outf.write(' fStrictFileParsing : %s\n' % bool_string(serverinfo.fStrictFileParsing))
220 outf.write(' fLooseWildcarding : %s\n' % bool_string(serverinfo.fLooseWildcarding))
221 outf.write(' fDefaultAgingState : %s\n' % bool_string(serverinfo.fDefaultAgingState))
223 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO_W2K:
224 outf.write(' dwRpcStructureVersion : 0x%x\n' % serverinfo.dwRpcStructureVersion)
225 outf.write(' aipLogFilter : %s\n' % dns_addr_array_string(serverinfo.aipLogFilter))
226 outf.write(' pwszLogFilePath : %s\n' % serverinfo.pwszLogFilePath)
227 outf.write(' pszDomainName : %s\n' % serverinfo.pszDomainName)
228 outf.write(' pszForestName : %s\n' % serverinfo.pszForestName)
229 outf.write(' pszDomainDirectoryPartition : %s\n' % serverinfo.pszDomainDirectoryPartition)
230 outf.write(' pszForestDirectoryPartition : %s\n' % serverinfo.pszForestDirectoryPartition)
232 outf.write(' dwLocalNetPriorityNetMask : 0x%x\n' % serverinfo.dwLocalNetPriorityNetMask)
233 outf.write(' dwLastScavengeTime : %d\n' % serverinfo.dwLastScavengeTime)
234 outf.write(' dwEventLogLevel : %d\n' % serverinfo.dwEventLogLevel)
235 outf.write(' dwLogFileMaxSize : %d\n' % serverinfo.dwLogFileMaxSize)
236 outf.write(' dwDsForestVersion : %d\n' % serverinfo.dwDsForestVersion)
237 outf.write(' dwDsDomainVersion : %d\n' % serverinfo.dwDsDomainVersion)
238 outf.write(' dwDsDsaVersion : %d\n' % serverinfo.dwDsDsaVersion)
240 if typeid == dnsserver.DNSSRV_TYPEID_SERVER_INFO:
241 outf.write(' fReadOnlyDC : %s\n' % bool_string(serverinfo.fReadOnlyDC))
244 def print_zoneinfo(outf, typeid, zoneinfo):
245 outf.write(' pszZoneName : %s\n' % zoneinfo.pszZoneName)
246 outf.write(' dwZoneType : %s\n' % zone_type_string(zoneinfo.dwZoneType))
247 outf.write(' fReverse : %s\n' % bool_string(zoneinfo.fReverse))
248 outf.write(' fAllowUpdate : %s\n' % zone_update_string(zoneinfo.fAllowUpdate))
249 outf.write(' fPaused : %s\n' % bool_string(zoneinfo.fPaused))
250 outf.write(' fShutdown : %s\n' % bool_string(zoneinfo.fShutdown))
251 outf.write(' fAutoCreated : %s\n' % bool_string(zoneinfo.fAutoCreated))
252 outf.write(' fUseDatabase : %s\n' % bool_string(zoneinfo.fUseDatabase))
253 outf.write(' pszDataFile : %s\n' % zoneinfo.pszDataFile)
254 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
255 outf.write(' aipMasters : %s\n' %
256 ip4_array_string(zoneinfo.aipMasters))
258 outf.write(' aipMasters : %s\n' %
259 dns_addr_array_string(zoneinfo.aipMasters))
260 outf.write(' fSecureSecondaries : %s\n' % zone_secondary_security_string(zoneinfo.fSecureSecondaries))
261 outf.write(' fNotifyLevel : %s\n' % zone_notify_level_string(zoneinfo.fNotifyLevel))
262 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
263 outf.write(' aipSecondaries : %s\n' %
264 ip4_array_string(zoneinfo.aipSecondaries))
265 outf.write(' aipNotify : %s\n' %
266 ip4_array_string(zoneinfo.aipNotify))
268 outf.write(' aipSecondaries : %s\n' %
269 dns_addr_array_string(zoneinfo.aipSecondaries))
270 outf.write(' aipNotify : %s\n' %
271 dns_addr_array_string(zoneinfo.aipNotify))
272 outf.write(' fUseWins : %s\n' % bool_string(zoneinfo.fUseWins))
273 outf.write(' fUseNbstat : %s\n' % bool_string(zoneinfo.fUseNbstat))
274 outf.write(' fAging : %s\n' % bool_string(zoneinfo.fAging))
275 outf.write(' dwNoRefreshInterval : %d\n' % zoneinfo.dwNoRefreshInterval)
276 outf.write(' dwRefreshInterval : %d\n' % zoneinfo.dwRefreshInterval)
277 outf.write(' dwAvailForScavengeTime : %d\n' % zoneinfo.dwAvailForScavengeTime)
278 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
279 outf.write(' aipScavengeServers : %s\n' %
280 ip4_array_string(zoneinfo.aipScavengeServers))
282 outf.write(' aipScavengeServers : %s\n' %
283 dns_addr_array_string(zoneinfo.aipScavengeServers))
285 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO_W2K:
286 outf.write(' dwRpcStructureVersion : 0x%x\n' % zoneinfo.dwRpcStructureVersion)
287 outf.write(' dwForwarderTimeout : %d\n' % zoneinfo.dwForwarderTimeout)
288 outf.write(' fForwarderSlave : %d\n' % zoneinfo.fForwarderSlave)
289 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO:
290 outf.write(' aipLocalMasters : %s\n' %
291 ip4_array_string(zoneinfo.aipLocalMasters))
293 outf.write(' aipLocalMasters : %s\n' %
294 dns_addr_array_string(zoneinfo.aipLocalMasters))
295 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zoneinfo.dwDpFlags))
296 outf.write(' pszDpFqdn : %s\n' % zoneinfo.pszDpFqdn)
297 outf.write(' pwszZoneDn : %s\n' % zoneinfo.pwszZoneDn)
298 outf.write(' dwLastSuccessfulSoaCheck : %d\n' % zoneinfo.dwLastSuccessfulSoaCheck)
299 outf.write(' dwLastSuccessfulXfr : %d\n' % zoneinfo.dwLastSuccessfulXfr)
301 if typeid == dnsserver.DNSSRV_TYPEID_ZONE_INFO:
302 outf.write(' fQueuedForBackgroundLoad : %s\n' % bool_string(zoneinfo.fQueuedForBackgroundLoad))
303 outf.write(' fBackgroundLoadInProgress : %s\n' % bool_string(zoneinfo.fBackgroundLoadInProgress))
304 outf.write(' fReadOnlyZone : %s\n' % bool_string(zoneinfo.fReadOnlyZone))
305 outf.write(' dwLastXfrAttempt : %d\n' % zoneinfo.dwLastXfrAttempt)
306 outf.write(' dwLastXfrResult : %d\n' % zoneinfo.dwLastXfrResult)
309 def print_zone(outf, typeid, zone):
310 outf.write(' pszZoneName : %s\n' % zone.pszZoneName)
311 outf.write(' Flags : %s\n' % zone_flags_string(zone.Flags))
312 outf.write(' ZoneType : %s\n' % zone_type_string(zone.ZoneType))
313 outf.write(' Version : %s\n' % zone.Version)
315 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_W2K:
316 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zone.dwDpFlags))
317 outf.write(' pszDpFqdn : %s\n' % zone.pszDpFqdn)
320 def print_enumzones(outf, typeid, zones):
321 outf.write(' %d zone(s) found\n' % zones.dwZoneCount)
322 for zone in zones.ZoneArray:
324 print_zone(outf, typeid, zone)
327 def print_dns_record(outf, rec):
329 if rec.wType == dnsp.DNS_TYPE_A:
330 mesg = 'A: %s' % (rec.data)
331 elif rec.wType == dnsp.DNS_TYPE_AAAA:
332 mesg = 'AAAA: %s' % (rec.data)
333 elif rec.wType == dnsp.DNS_TYPE_PTR:
334 mesg = 'PTR: %s' % (rec.data.str)
335 elif rec.wType == dnsp.DNS_TYPE_NS:
336 mesg = 'NS: %s' % (rec.data.str)
337 elif rec.wType == dnsp.DNS_TYPE_CNAME:
338 mesg = 'CNAME: %s' % (rec.data.str)
339 elif rec.wType == dnsp.DNS_TYPE_SOA:
340 mesg = 'SOA: serial=%d, refresh=%d, retry=%d, expire=%d, ns=%s, email=%s' % (
345 rec.data.NamePrimaryServer.str,
346 rec.data.ZoneAdministratorEmail.str)
347 elif rec.wType == dnsp.DNS_TYPE_MX:
348 mesg = 'MX: %s' % (rec.data.str)
349 elif rec.wType == dnsp.DNS_TYPE_SRV:
350 mesg = 'SRV: %s (%d)' % (rec.data.nameTarget.str, rec.data.wPort)
351 outf.write(' %s (flags=%x, serial=%d, ttl=%d)\n' % (
352 mesg, rec.dwFlags, rec.dwSerial, rec.dwTtlSeconds))
355 def print_dnsrecords(outf, records):
356 for rec in records.rec:
357 outf.write(' Name=%s, Records=%d, Children=%d\n' % (
361 for dns_rec in rec.records:
362 print_dns_record(outf, dns_rec)
365 class ARecord(dnsserver.DNS_RPC_RECORD):
366 def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
368 super(ARecord, self).__init__()
369 self.wType = dnsp.DNS_TYPE_A
370 self.dwFlags = rank | node_flag
371 self.dwSerial = serial
372 self.dwTtlSeconds = ttl
375 class AAAARecord(dnsserver.DNS_RPC_RECORD):
376 def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
378 super(AAAARecord, self).__init__()
379 self.wType = dnsp.DNS_TYPE_AAAA
380 self.dwFlags = rank | node_flag
381 self.dwSerial = serial
382 self.dwTtlSeconds = ttl
385 class PTRRecord(dnsserver.DNS_RPC_RECORD):
386 def __init__(self, ptr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
388 super(PTRRecord, self).__init__()
389 self.wType = dnsp.DNS_TYPE_PTR
390 self.dwFlags = rank | node_flag
391 self.dwSerial = serial
392 self.dwTtleSeconds = ttl
393 ptr_name = dnsserver.DNS_RPC_NAME()
395 ptr_name.len = len(ptr)
398 class CNameRecord(dnsserver.DNS_RPC_RECORD):
399 def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
401 super(CNameRecord, self).__init__()
402 self.wType = dnsp.DNS_TYPE_CNAME
403 self.dwFlags = rank | node_flag
404 self.dwSerial = serial
405 self.dwTtlSeconds = ttl
406 cname_name = dnsserver.DNS_RPC_NAME()
407 cname_name.str = cname
408 cname_name.len = len(cname)
409 self.data = cname_name
411 class NSRecord(dnsserver.DNS_RPC_RECORD):
412 def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
414 super(NSRecord, self).__init__()
415 self.wType = dnsp.DNS_TYPE_NS
416 self.dwFlags = rank | node_flag
417 self.dwSerial = serial
418 self.dwTtlSeconds = ttl
419 ns = dnsserver.DNS_RPC_NAME()
421 ns.len = len(dns_server)
424 class SOARecord(dnsserver.DNS_RPC_RECORD):
425 def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
426 expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE,
427 node_flag=dnsp.DNS_RPC_FLAG_AUTH_ZONE_ROOT):
428 super(SOARecord, self).__init__()
429 self.wType = dnsp.DNS_TYPE_SOA
430 self.dwFlags = rank | node_flag
431 self.dwSerial = serial
432 self.dwTtlSeconds = ttl
433 soa = dnsserver.DNS_RPC_RECORD_SOA()
434 soa.dwSerialNo = serial
435 soa.dwRefresh = refresh
437 soa.dwExpire = expire
438 soa.NamePrimaryServer.str = mname
439 soa.NamePrimaryServer.len = len(mname)
440 soa.ZoneAdministratorEmail.str = rname
441 soa.ZoneAdministratorEmail.len = len(rname)
444 class SRVRecord(dnsserver.DNS_RPC_RECORD):
445 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
446 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
447 super(SRVRecord, self).__init__()
448 self.wType = dnsp.DNS_TYPE_SRV
449 self.dwFlags = rank | node_flag
450 self.dwSerial = serial
451 self.dwTtlSeconds = ttl
452 srv = dnsserver.DNS_RPC_RECORD_SRV()
453 srv.wPriority = priority
456 srv.nameTarget.str = target
457 srv.nameTarget.len = len(target)
460 # Match a dns record with specified data
461 def dns_record_match(dns_conn, server, zone, name, record_type, data):
462 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
465 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
475 except RuntimeError, e:
478 if not res or res.count == 0:
482 for rec in res.rec[0].records:
483 if rec.wType != record_type:
487 if record_type == dnsp.DNS_TYPE_A:
490 elif record_type == dnsp.DNS_TYPE_AAAA:
493 elif record_type == dnsp.DNS_TYPE_PTR:
494 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
496 elif record_type == dnsp.DNS_TYPE_CNAME:
497 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
499 elif record_type == dnsp.DNS_TYPE_NS:
500 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
509 class cmd_serverinfo(Command):
510 """Query for Server information"""
512 synopsis = '%prog <server> [options]'
514 takes_args = [ 'server' ]
516 takes_optiongroups = {
517 "sambaopts": options.SambaOptions,
518 "versionopts": options.VersionOptions,
519 "credopts": options.CredentialsOptions,
523 Option('--client-version', help='Client Version',
524 default='longhorn', metavar='w2k|dotnet|longhorn',
525 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
528 def run(self, server, cli_ver, sambaopts=None, credopts=None, versionopts=None):
529 self.lp = sambaopts.get_loadparm()
530 self.creds = credopts.get_credentials(self.lp)
531 dns_conn = dns_connect(server, self.lp, self.creds)
533 client_version = dns_client_version(cli_ver)
535 typeid, res = dns_conn.DnssrvQuery2(client_version,
540 print_serverinfo(self.outf, typeid, res)
543 class cmd_zoneinfo(Command):
544 """Query for zone information"""
546 synopsis = '%prog <server> <zone> [options]'
548 takes_args = [ 'server', 'zone' ]
550 takes_optiongroups = {
551 "sambaopts": options.SambaOptions,
552 "versionopts": options.VersionOptions,
553 "credopts": options.CredentialsOptions,
557 Option('--client-version', help='Client Version',
558 default='longhorn', metavar='w2k|dotnet|longhorn',
559 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
562 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, versionopts=None):
563 self.lp = sambaopts.get_loadparm()
564 self.creds = credopts.get_credentials(self.lp)
565 dns_conn = dns_connect(server, self.lp, self.creds)
567 client_version = dns_client_version(cli_ver)
569 typeid, res = dns_conn.DnssrvQuery2(client_version,
574 print_zoneinfo(self.outf, typeid, res)
577 class cmd_zonelist(Command):
578 """Query for zones"""
580 synopsis = '%prog <server> [options]'
582 takes_args = [ 'server' ]
584 takes_optiongroups = {
585 "sambaopts": options.SambaOptions,
586 "versionopts": options.VersionOptions,
587 "credopts": options.CredentialsOptions,
591 Option('--client-version', help='Client Version',
592 default='longhorn', metavar='w2k|dotnet|longhorn',
593 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
594 Option('--primary', help='List primary zones (default)',
595 action='store_true', dest='primary'),
596 Option('--secondary', help='List secondary zones',
597 action='store_true', dest='secondary'),
598 Option('--cache', help='List cached zones',
599 action='store_true', dest='cache'),
600 Option('--auto', help='List automatically created zones',
601 action='store_true', dest='auto'),
602 Option('--forward', help='List forward zones',
603 action='store_true', dest='forward'),
604 Option('--reverse', help='List reverse zones',
605 action='store_true', dest='reverse'),
606 Option('--ds', help='List directory integrated zones',
607 action='store_true', dest='ds'),
608 Option('--non-ds', help='List non-directory zones',
609 action='store_true', dest='nonds')
612 def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
613 auto=False, forward=False, reverse=False, ds=False, nonds=False,
614 sambaopts=None, credopts=None, versionopts=None):
618 request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
620 request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
622 request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
624 request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
626 request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
628 request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
630 request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
632 request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
634 if request_filter == 0:
635 request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
637 self.lp = sambaopts.get_loadparm()
638 self.creds = credopts.get_credentials(self.lp)
639 dns_conn = dns_connect(server, self.lp, self.creds)
641 client_version = dns_client_version(cli_ver)
643 typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
648 dnsserver.DNSSRV_TYPEID_DWORD,
651 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
652 typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
654 typeid = dnsserver.DNSSRV_TYPEID_ZONE
655 print_enumzones(self.outf, typeid, res)
658 class cmd_zonecreate(Command):
661 synopsis = '%prog <server> <zone> [options]'
663 takes_args = [ 'server', 'zone' ]
665 takes_optiongroups = {
666 "sambaopts": options.SambaOptions,
667 "versionopts": options.VersionOptions,
668 "credopts": options.CredentialsOptions,
672 Option('--client-version', help='Client Version',
673 default='longhorn', metavar='w2k|dotnet|longhorn',
674 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
677 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
680 self.lp = sambaopts.get_loadparm()
681 self.creds = credopts.get_credentials(self.lp)
682 dns_conn = dns_connect(server, self.lp, self.creds)
686 client_version = dns_client_version(cli_ver)
687 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
688 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
689 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
690 zone_create_info.pszZoneName = zone
691 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
692 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
693 zone_create_info.fAging = 0
694 elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
695 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
696 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
697 zone_create_info.pszZoneName = zone
698 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
699 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
700 zone_create_info.fAging = 0
701 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
703 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
704 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
705 zone_create_info.pszZoneName = zone
706 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
707 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
708 zone_create_info.fAging = 0
709 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
711 res = dns_conn.DnssrvOperation2(client_version,
719 self.outf.write('Zone %s created successfully\n' % zone)
722 class cmd_zonedelete(Command):
725 synopsis = '%prog <server> <zone> [options]'
727 takes_args = [ 'server', 'zone' ]
729 takes_optiongroups = {
730 "sambaopts": options.SambaOptions,
731 "versionopts": options.VersionOptions,
732 "credopts": options.CredentialsOptions,
735 def run(self, server, zone, sambaopts=None, credopts=None, versionopts=None):
737 self.lp = sambaopts.get_loadparm()
738 self.creds = credopts.get_credentials(self.lp)
739 dns_conn = dns_connect(server, self.lp, self.creds)
742 res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
748 dnsserver.DNSSRV_TYPEID_NULL,
750 self.outf.write('Zone %s delete successfully\n' % zone)
753 class cmd_query(Command):
756 synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|ALL> [options]'
758 takes_args = [ 'server', 'zone', 'name', 'rtype' ]
760 takes_optiongroups = {
761 "sambaopts": options.SambaOptions,
762 "versionopts": options.VersionOptions,
763 "credopts": options.CredentialsOptions,
767 Option('--authority', help='Search authoritative records (default)',
768 action='store_true', dest='authority'),
769 Option('--cache', help='Search cached records',
770 action='store_true', dest='cache'),
771 Option('--glue', help='Search glue records',
772 action='store_true', dest='glue'),
773 Option('--root', help='Search root hints',
774 action='store_true', dest='root'),
775 Option('--additional', help='List additional records',
776 action='store_true', dest='additional'),
777 Option('--no-children', help='Do not list children',
778 action='store_true', dest='no_children'),
779 Option('--only-children', help='List only children',
780 action='store_true', dest='only_children')
783 def run(self, server, zone, name, rtype, authority=False, cache=False, glue=False,
784 root=False, additional=False, no_children=False, only_children=False,
785 sambaopts=None, credopts=None, versionopts=None):
786 record_type = dns_type_flag(rtype)
790 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
792 select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
794 select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
796 select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
798 select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
800 select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
802 select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
804 if select_flags == 0:
805 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
807 if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
808 self.outf.write('Specify either --authority or --root along with --additional.\n')
809 self.outf.write('Assuming --authority.\n')
810 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
812 self.lp = sambaopts.get_loadparm()
813 self.creds = credopts.get_credentials(self.lp)
814 dns_conn = dns_connect(server, self.lp, self.creds)
816 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
826 print_dnsrecords(self.outf, res)
829 class cmd_roothints(Command):
830 """Query root hints"""
832 synopsis = '%prog <server> [<name>] [options]'
834 takes_args = [ 'server', 'name?' ]
836 takes_optiongroups = {
837 "sambaopts": options.SambaOptions,
838 "versionopts": options.VersionOptions,
839 "credopts": options.CredentialsOptions,
842 def run(self, server, name='.', sambaopts=None, credopts=None, versionopts=None):
843 record_type = dnsp.DNS_TYPE_NS
844 select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
845 dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
847 self.lp = sambaopts.get_loadparm()
848 self.creds = credopts.get_credentials(self.lp)
849 dns_conn = dns_connect(server, self.lp, self.creds)
851 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
861 print_dnsrecords(self.outf, res)
864 class cmd_add_record(Command):
865 """Add a DNS record"""
867 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
869 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
871 takes_optiongroups = {
872 "sambaopts": options.SambaOptions,
873 "versionopts": options.VersionOptions,
874 "credopts": options.CredentialsOptions,
877 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
879 record_type = dns_type_flag(rtype)
881 if record_type == dnsp.DNS_TYPE_A:
883 elif record_type == dnsp.DNS_TYPE_AAAA:
884 rec = AAAARecord(data)
885 elif record_type == dnsp.DNS_TYPE_PTR:
886 rec = PTRRecord(data)
887 elif record_type == dnsp.DNS_TYPE_CNAME:
888 rec = CNameRecord(data)
889 elif record_type == dnsp.DNS_TYPE_NS:
892 raise CommandError('Adding record of type %s is not supported' % rtype)
894 self.lp = sambaopts.get_loadparm()
895 self.creds = credopts.get_credentials(self.lp)
896 dns_conn = dns_connect(server, self.lp, self.creds)
898 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
899 if rec_match is not None:
900 raise CommandError('Record already exists')
902 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
903 add_rec_buf.rec = rec
905 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
912 self.outf.write('Record added successfully\n')
915 class cmd_update_record(Command):
916 """Update a DNS record"""
918 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <olddata> <newdata>'
920 takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
922 takes_optiongroups = {
923 "sambaopts": options.SambaOptions,
924 "versionopts": options.VersionOptions,
925 "credopts": options.CredentialsOptions,
928 def run(self, server, zone, name, rtype, olddata, newdata,
929 sambaopts=None, credopts=None, versionopts=None):
931 record_type = dns_type_flag(rtype)
932 if record_type == dnsp.DNS_TYPE_A:
933 rec = ARecord(newdata)
934 elif record_type == dnsp.DNS_TYPE_AAAA:
935 rec = AAAARecord(newdata)
936 elif record_type == dnsp.DNS_TYPE_PTR:
937 rec = PTRRecord(newdata)
938 elif record_type == dnsp.DNS_TYPE_CNAME:
939 rec = CNameRecord(newdata)
940 elif record_type == dnsp.DNS_TYPE_NS:
941 rec = NSRecord(newdata)
943 raise CommandError('Updating record of type %s is not supported' % rtype)
945 self.lp = sambaopts.get_loadparm()
946 self.creds = credopts.get_credentials(self.lp)
947 dns_conn = dns_connect(server, self.lp, self.creds)
949 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, olddata)
951 raise CommandError('Record does not exist')
953 # Copy properties from existing record to new record
954 rec.dwFlags = rec_match.dwFlags
955 rec.dwSerial = rec_match.dwSerial
956 rec.dwTtlSeconds = rec_match.dwTtlSeconds
957 rec.dwTimeStamp = rec_match.dwTimeStamp
959 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
960 add_rec_buf.rec = rec
962 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
963 del_rec_buf.rec = rec_match
965 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
972 self.outf.write('Record updated succefully\n')
975 class cmd_delete_record(Command):
976 """Delete a DNS record"""
978 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
980 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
982 takes_optiongroups = {
983 "sambaopts": options.SambaOptions,
984 "versionopts": options.VersionOptions,
985 "credopts": options.CredentialsOptions,
988 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
990 record_type = dns_type_flag(rtype)
992 if record_type == dnsp.DNS_TYPE_A:
994 elif record_type == dnsp.DNS_TYPE_AAAA:
995 rec = AAAARecord(data)
996 elif record_type == dnsp.DNS_TYPE_PTR:
997 rec = PTRRecord(data)
998 elif record_type == dnsp.DNS_TYPE_CNAME:
999 rec = CNameRecord(data)
1000 elif record_type == dnsp.DNS_TYPE_NS:
1001 rec = NSRecord(data)
1003 raise CommandError('Deleting record of type %s is not supported' % rtype)
1005 self.lp = sambaopts.get_loadparm()
1006 self.creds = credopts.get_credentials(self.lp)
1007 dns_conn = dns_connect(server, self.lp, self.creds)
1009 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
1011 raise CommandError('Record does not exist')
1013 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1014 del_rec_buf.rec = rec_match
1016 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1023 self.outf.write('Record deleted succefully\n')
1026 class cmd_dns(SuperCommand):
1027 """Domain Name Service (DNS) management"""
1030 subcommands['serverinfo'] = cmd_serverinfo()
1031 subcommands['zoneinfo'] = cmd_zoneinfo()
1032 subcommands['zonelist'] = cmd_zonelist()
1033 subcommands['zonecreate'] = cmd_zonecreate()
1034 subcommands['zonedelete'] = cmd_zonedelete()
1035 subcommands['query'] = cmd_query()
1036 subcommands['roothints'] = cmd_roothints()
1037 subcommands['add'] = cmd_add_record()
1038 subcommands['update'] = cmd_update_record()
1039 subcommands['delete'] = cmd_delete_record()