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 def dns_record_match(dns_conn, server, zone, name, record_type, data):
461 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
464 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
474 except RuntimeError, e:
478 if res and res.count > 0:
480 for rec in recs.records:
481 if rec.wType == record_type:
487 if record_type == dnsp.DNS_TYPE_A:
488 if rec_match.data == data:
490 elif record_type == dnsp.DNS_TYPE_AAAA:
491 if rec_match.data == data:
493 elif record_type == dnsp.DNS_TYPE_PTR:
494 if rec_match.data.str.rstrip('.') == data.rstrip('.'):
496 elif record_type == dnsp.DNS_TYPE_CNAME:
497 if rec_match.data.str.rstrip('.') == data.rstrip('.'):
499 elif record_type == dnsp.DNS_TYPE_NS:
500 if rec_match.data.str.rstrip('.') == data.rstrip('.'):
509 class cmd_serverinfo(Command):
510 """Query for Server information"""
512 synopsis = '%prog <server> [options]'
514 takes_args = [ 'server' ]
517 Option('--client-version', help='Client Version',
518 default='longhorn', metavar='w2k|dotnet|longhorn',
519 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
522 def run(self, server, cli_ver, sambaopts=None, credopts=None, versionopts=None):
523 self.lp = sambaopts.get_loadparm()
524 self.creds = credopts.get_credentials(self.lp)
525 dns_conn = dns_connect(server, self.lp, self.creds)
527 client_version = dns_client_version(cli_ver)
529 typeid, res = dns_conn.DnssrvQuery2(client_version,
534 print_serverinfo(self.outf, typeid, res)
537 class cmd_zoneinfo(Command):
538 """Query for zone information"""
540 synopsis = '%prog <server> <zone> [options]'
542 takes_args = [ 'server', 'zone' ]
545 Option('--client-version', help='Client Version',
546 default='longhorn', metavar='w2k|dotnet|longhorn',
547 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
550 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, versionopts=None):
551 self.lp = sambaopts.get_loadparm()
552 self.creds = credopts.get_credentials(self.lp)
553 dns_conn = dns_connect(server, self.lp, self.creds)
555 client_version = dns_client_version(cli_ver)
557 typeid, res = dns_conn.DnssrvQuery2(client_version,
562 print_zoneinfo(self.outf, typeid, res)
565 class cmd_zonelist(Command):
566 """Query for zones"""
568 synopsis = '%prog <server> [options]'
570 takes_args = [ 'server' ]
573 Option('--client-version', help='Client Version',
574 default='longhorn', metavar='w2k|dotnet|longhorn',
575 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
576 Option('--primary', help='List primary zones (default)',
577 action='store_true', dest='primary'),
578 Option('--secondary', help='List secondary zones',
579 action='store_true', dest='secondary'),
580 Option('--cache', help='List cached zones',
581 action='store_true', dest='cache'),
582 Option('--auto', help='List automatically created zones',
583 action='store_true', dest='auto'),
584 Option('--forward', help='List forward zones',
585 action='store_true', dest='forward'),
586 Option('--reverse', help='List reverse zones',
587 action='store_true', dest='reverse'),
588 Option('--ds', help='List directory integrated zones',
589 action='store_true', dest='ds'),
590 Option('--non-ds', help='List non-directory zones',
591 action='store_true', dest='nonds')
594 def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
595 auto=False, forward=False, reverse=False, ds=False, nonds=False,
596 sambaopts=None, credopts=None, versionopts=None):
600 request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
602 request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
604 request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
606 request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
608 request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
610 request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
612 request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
614 request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
616 if request_filter == 0:
617 request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
619 self.lp = sambaopts.get_loadparm()
620 self.creds = credopts.get_credentials(self.lp)
621 dns_conn = dns_connect(server, self.lp, self.creds)
623 client_version = dns_client_version(cli_ver)
625 typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
630 dnsserver.DNSSRV_TYPEID_DWORD,
633 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
634 typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
636 typeid = dnsserver.DNSSRV_TYPEID_ZONE
637 print_enumzones(self.outf, typeid, res)
640 class cmd_zonecreate(Command):
643 synopsis = '%prog <server> <zone> [options]'
645 takes_args = [ 'server', 'zone' ]
648 Option('--client-version', help='Client Version',
649 default='longhorn', metavar='w2k|dotnet|longhorn',
650 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
653 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
656 self.lp = sambaopts.get_loadparm()
657 self.creds = credopts.get_credentials(self.lp)
658 dns_conn = dns_connect(server, self.lp, self.creds)
662 client_version = dns_client_version(cli_ver)
663 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
664 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
665 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
666 zone_create_info.pszZoneName = zone
667 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
668 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
669 zone_create_info.fAging = 0
670 elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
671 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
672 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
673 zone_create_info.pszZoneName = zone
674 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
675 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
676 zone_create_info.fAging = 0
677 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
679 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
680 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
681 zone_create_info.pszZoneName = zone
682 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
683 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
684 zone_create_info.fAging = 0
685 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
687 res = dns_conn.DnssrvOperation2(client_version,
695 self.outf.write('Zone %s created successfully\n' % zone)
698 class cmd_zonedelete(Command):
701 synopsis = '%prog <server> <zone> [options]'
703 takes_args = [ 'server', 'zone' ]
705 def run(self, server, zone, sambaopts=None, credopts=None, versionopts=None):
707 self.lp = sambaopts.get_loadparm()
708 self.creds = credopts.get_credentials(self.lp)
709 dns_conn = dns_connect(server, self.lp, self.creds)
712 res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
718 dnsserver.DNSSRV_TYPEID_NULL,
720 self.outf.write('Zone %s delete successfully\n' % zone)
723 class cmd_query(Command):
726 synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|ALL> [options]'
728 takes_args = [ 'server', 'zone', 'name', 'rtype' ]
731 Option('--authority', help='Search authoritative records (default)',
732 action='store_true', dest='authority'),
733 Option('--cache', help='Search cached records',
734 action='store_true', dest='cache'),
735 Option('--glue', help='Search glue records',
736 action='store_true', dest='glue'),
737 Option('--root', help='Search root hints',
738 action='store_true', dest='root'),
739 Option('--additional', help='List additional records',
740 action='store_true', dest='additional'),
741 Option('--no-children', help='Do not list children',
742 action='store_true', dest='no_children'),
743 Option('--only-children', help='List only children',
744 action='store_true', dest='only_children')
747 def run(self, server, zone, name, rtype, authority=False, cache=False, glue=False,
748 root=False, additional=False, no_children=False, only_children=False,
749 sambaopts=None, credopts=None, versionopts=None):
750 record_type = dns_type_flag(rtype)
754 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
756 select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
758 select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
760 select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
762 select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
764 select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
766 select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
768 if select_flags == 0:
769 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
771 if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
772 self.outf.write('Specify either --authority or --root along with --additional.\n')
773 self.outf.write('Assuming --authority.\n')
774 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
776 self.lp = sambaopts.get_loadparm()
777 self.creds = credopts.get_credentials(self.lp)
778 dns_conn = dns_connect(server, self.lp, self.creds)
780 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
790 print_dnsrecords(self.outf, res)
793 class cmd_roothints(Command):
794 """Query root hints"""
796 synopsis = '%prog <server> [<name>] [options]'
798 takes_args = [ 'server', 'name?' ]
800 def run(self, server, name='.', sambaopts=None, credopts=None, versionopts=None):
801 record_type = dnsp.DNS_TYPE_NS
802 select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
803 dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
805 self.lp = sambaopts.get_loadparm()
806 self.creds = credopts.get_credentials(self.lp)
807 dns_conn = dns_connect(server, self.lp, self.creds)
809 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
819 print_dnsrecords(self.outf, res)
822 class cmd_add_record(Command):
823 """Add a DNS record"""
825 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
827 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
829 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
831 record_type = dns_type_flag(rtype)
833 if record_type == dnsp.DNS_TYPE_A:
835 elif record_type == dnsp.DNS_TYPE_AAAA:
836 rec = AAAARecord(data)
837 elif record_type == dnsp.DNS_TYPE_PTR:
838 rec = PTRRecord(data)
839 elif record_type == dnsp.DNS_TYPE_CNAME:
840 rec = CNameRecord(data)
841 elif record_type == dnsp.DNS_TYPE_NS:
844 raise CommandError('Adding record of type %s is not supported' % rtype)
846 self.lp = sambaopts.get_loadparm()
847 self.creds = credopts.get_credentials(self.lp)
848 dns_conn = dns_connect(server, self.lp, self.creds)
850 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
851 if rec_match is not None:
852 raise CommandError('Record already exists')
854 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
855 add_rec_buf.rec = rec
857 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
864 self.outf.write('Record added succefully\n')
867 class cmd_update_record(Command):
868 """Update a DNS record"""
870 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <olddata> <newdata>'
872 takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
874 def run(self, server, zone, name, rtype, olddata, newdata,
875 sambaopts=None, credopts=None, versionopts=None):
877 record_type = dns_type_flag(rtype)
878 if record_type == dnsp.DNS_TYPE_A:
879 rec = ARecord(newdata)
880 elif record_type == dnsp.DNS_TYPE_AAAA:
881 rec = AAAARecord(newdata)
882 elif record_type == dnsp.DNS_TYPE_PTR:
883 rec = PTRRecord(newdata)
884 elif record_type == dnsp.DNS_TYPE_CNAME:
885 rec = CNameRecord(newdata)
886 elif record_type == dnsp.DNS_TYPE_NS:
887 rec = NSRecord(newdata)
889 raise CommandError('Updating record of type %s is not supported' % rtype)
891 self.lp = sambaopts.get_loadparm()
892 self.creds = credopts.get_credentials(self.lp)
893 dns_conn = dns_connect(server, self.lp, self.creds)
895 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, olddata)
897 raise CommandError('Record does not exist')
899 # Copy properties from existing record to new record
900 rec.dwFlags = rec_match.dwFlags
901 rec.dwSerial = rec_match.dwSerial
902 rec.dwTtlSeconds = rec_match.dwTtlSeconds
903 rec.dwTimeStamp = rec_match.dwTimeStamp
905 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
906 add_rec_buf.rec = rec
908 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
909 del_rec_buf.rec = rec_match
911 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
918 self.outf.write('Record updated succefully\n')
921 class cmd_delete_record(Command):
922 """Delete a DNS record"""
924 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
926 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
928 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
930 record_type = dns_type_flag(rtype)
932 if record_type == dnsp.DNS_TYPE_A:
934 elif record_type == dnsp.DNS_TYPE_AAAA:
935 rec = AAAARecord(data)
936 elif record_type == dnsp.DNS_TYPE_PTR:
937 rec = PTRRecord(data)
938 elif record_type == dnsp.DNS_TYPE_CNAME:
939 rec = CNameRecord(data)
940 elif record_type == dnsp.DNS_TYPE_NS:
943 raise CommandError('Deleting 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, data)
951 raise CommandError('Record does not exist')
953 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
954 del_rec_buf.rec = rec_match
956 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
963 self.outf.write('Record deleted succefully\n')
966 class cmd_dns(SuperCommand):
967 """Domain Name Service (DNS) management"""
970 subcommands['serverinfo'] = cmd_serverinfo()
971 subcommands['zoneinfo'] = cmd_zoneinfo()
972 subcommands['zonelist'] = cmd_zonelist()
973 subcommands['zonecreate'] = cmd_zonecreate()
974 subcommands['zonedelete'] = cmd_zonedelete()
975 subcommands['query'] = cmd_query()
976 subcommands['roothints'] = cmd_roothints()
977 subcommands['add'] = cmd_add_record()
978 subcommands['update'] = cmd_update_record()
979 subcommands['delete'] = cmd_delete_record()