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 MXRecord(dnsserver.DNS_RPC_RECORD):
425 def __init__(self, mail_server, preference, serial=1, ttl=900,
426 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
427 super(MXRecord, self).__init__()
428 self.wType = dnsp.DNS_TYPE_MX
429 self.dwFlags = rank | node_flag
430 self.dwSerial = serial
431 self.dwTtlSeconds = ttl
432 mx = dnsserver.DNS_RPC_RECORD_NAME_PREFERENCE()
433 mx.wPreference = preference
434 mx.nameExchange.str = mail_server
435 mx.nameExchange.len = len(mail_server)
438 class SOARecord(dnsserver.DNS_RPC_RECORD):
439 def __init__(self, mname, rname, serial=1, refresh=900, retry=600,
440 expire=86400, minimum=3600, ttl=3600, rank=dnsp.DNS_RANK_ZONE,
441 node_flag=dnsp.DNS_RPC_FLAG_AUTH_ZONE_ROOT):
442 super(SOARecord, self).__init__()
443 self.wType = dnsp.DNS_TYPE_SOA
444 self.dwFlags = rank | node_flag
445 self.dwSerial = serial
446 self.dwTtlSeconds = ttl
447 soa = dnsserver.DNS_RPC_RECORD_SOA()
448 soa.dwSerialNo = serial
449 soa.dwRefresh = refresh
451 soa.dwExpire = expire
452 soa.NamePrimaryServer.str = mname
453 soa.NamePrimaryServer.len = len(mname)
454 soa.ZoneAdministratorEmail.str = rname
455 soa.ZoneAdministratorEmail.len = len(rname)
458 class SRVRecord(dnsserver.DNS_RPC_RECORD):
459 def __init__(self, target, port, priority=0, weight=100, serial=1, ttl=900,
460 rank=dnsp.DNS_RANK_ZONE, node_flag=0):
461 super(SRVRecord, self).__init__()
462 self.wType = dnsp.DNS_TYPE_SRV
463 self.dwFlags = rank | node_flag
464 self.dwSerial = serial
465 self.dwTtlSeconds = ttl
466 srv = dnsserver.DNS_RPC_RECORD_SRV()
467 srv.wPriority = priority
470 srv.nameTarget.str = target
471 srv.nameTarget.len = len(target)
474 # Match a dns record with specified data
475 def dns_record_match(dns_conn, server, zone, name, record_type, data):
476 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
479 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
489 except RuntimeError, e:
492 if not res or res.count == 0:
496 for rec in res.rec[0].records:
497 if rec.wType != record_type:
501 if record_type == dnsp.DNS_TYPE_A:
504 elif record_type == dnsp.DNS_TYPE_AAAA:
507 elif record_type == dnsp.DNS_TYPE_PTR:
508 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
510 elif record_type == dnsp.DNS_TYPE_CNAME:
511 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
513 elif record_type == dnsp.DNS_TYPE_NS:
514 if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
523 class cmd_serverinfo(Command):
524 """Query for Server information"""
526 synopsis = '%prog <server> [options]'
528 takes_args = [ 'server' ]
530 takes_optiongroups = {
531 "sambaopts": options.SambaOptions,
532 "versionopts": options.VersionOptions,
533 "credopts": options.CredentialsOptions,
537 Option('--client-version', help='Client Version',
538 default='longhorn', metavar='w2k|dotnet|longhorn',
539 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
542 def run(self, server, cli_ver, sambaopts=None, credopts=None, versionopts=None):
543 self.lp = sambaopts.get_loadparm()
544 self.creds = credopts.get_credentials(self.lp)
545 dns_conn = dns_connect(server, self.lp, self.creds)
547 client_version = dns_client_version(cli_ver)
549 typeid, res = dns_conn.DnssrvQuery2(client_version,
554 print_serverinfo(self.outf, typeid, res)
557 class cmd_zoneinfo(Command):
558 """Query for zone information"""
560 synopsis = '%prog <server> <zone> [options]'
562 takes_args = [ 'server', 'zone' ]
564 takes_optiongroups = {
565 "sambaopts": options.SambaOptions,
566 "versionopts": options.VersionOptions,
567 "credopts": options.CredentialsOptions,
571 Option('--client-version', help='Client Version',
572 default='longhorn', metavar='w2k|dotnet|longhorn',
573 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
576 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, versionopts=None):
577 self.lp = sambaopts.get_loadparm()
578 self.creds = credopts.get_credentials(self.lp)
579 dns_conn = dns_connect(server, self.lp, self.creds)
581 client_version = dns_client_version(cli_ver)
583 typeid, res = dns_conn.DnssrvQuery2(client_version,
588 print_zoneinfo(self.outf, typeid, res)
591 class cmd_zonelist(Command):
592 """Query for zones"""
594 synopsis = '%prog <server> [options]'
596 takes_args = [ 'server' ]
598 takes_optiongroups = {
599 "sambaopts": options.SambaOptions,
600 "versionopts": options.VersionOptions,
601 "credopts": options.CredentialsOptions,
605 Option('--client-version', help='Client Version',
606 default='longhorn', metavar='w2k|dotnet|longhorn',
607 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
608 Option('--primary', help='List primary zones (default)',
609 action='store_true', dest='primary'),
610 Option('--secondary', help='List secondary zones',
611 action='store_true', dest='secondary'),
612 Option('--cache', help='List cached zones',
613 action='store_true', dest='cache'),
614 Option('--auto', help='List automatically created zones',
615 action='store_true', dest='auto'),
616 Option('--forward', help='List forward zones',
617 action='store_true', dest='forward'),
618 Option('--reverse', help='List reverse zones',
619 action='store_true', dest='reverse'),
620 Option('--ds', help='List directory integrated zones',
621 action='store_true', dest='ds'),
622 Option('--non-ds', help='List non-directory zones',
623 action='store_true', dest='nonds')
626 def run(self, server, cli_ver, primary=False, secondary=False, cache=False,
627 auto=False, forward=False, reverse=False, ds=False, nonds=False,
628 sambaopts=None, credopts=None, versionopts=None):
632 request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
634 request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
636 request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
638 request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
640 request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
642 request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
644 request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
646 request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
648 if request_filter == 0:
649 request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
651 self.lp = sambaopts.get_loadparm()
652 self.creds = credopts.get_credentials(self.lp)
653 dns_conn = dns_connect(server, self.lp, self.creds)
655 client_version = dns_client_version(cli_ver)
657 typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
662 dnsserver.DNSSRV_TYPEID_DWORD,
665 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
666 typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
668 typeid = dnsserver.DNSSRV_TYPEID_ZONE
669 print_enumzones(self.outf, typeid, res)
672 class cmd_zonecreate(Command):
675 synopsis = '%prog <server> <zone> [options]'
677 takes_args = [ 'server', 'zone' ]
679 takes_optiongroups = {
680 "sambaopts": options.SambaOptions,
681 "versionopts": options.VersionOptions,
682 "credopts": options.CredentialsOptions,
686 Option('--client-version', help='Client Version',
687 default='longhorn', metavar='w2k|dotnet|longhorn',
688 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
691 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
694 self.lp = sambaopts.get_loadparm()
695 self.creds = credopts.get_credentials(self.lp)
696 dns_conn = dns_connect(server, self.lp, self.creds)
700 client_version = dns_client_version(cli_ver)
701 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
702 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K
703 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K()
704 zone_create_info.pszZoneName = zone
705 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
706 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
707 zone_create_info.fAging = 0
708 elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET:
709 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET
710 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET()
711 zone_create_info.pszZoneName = zone
712 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
713 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
714 zone_create_info.fAging = 0
715 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
717 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE
718 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN()
719 zone_create_info.pszZoneName = zone
720 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY
721 zone_create_info.fAllowUpdate = dnsp.DNS_ZONE_UPDATE_SECURE
722 zone_create_info.fAging = 0
723 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT
725 res = dns_conn.DnssrvOperation2(client_version,
733 self.outf.write('Zone %s created successfully\n' % zone)
736 class cmd_zonedelete(Command):
739 synopsis = '%prog <server> <zone> [options]'
741 takes_args = [ 'server', 'zone' ]
743 takes_optiongroups = {
744 "sambaopts": options.SambaOptions,
745 "versionopts": options.VersionOptions,
746 "credopts": options.CredentialsOptions,
749 def run(self, server, zone, sambaopts=None, credopts=None, versionopts=None):
751 self.lp = sambaopts.get_loadparm()
752 self.creds = credopts.get_credentials(self.lp)
753 dns_conn = dns_connect(server, self.lp, self.creds)
756 res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
762 dnsserver.DNSSRV_TYPEID_NULL,
764 self.outf.write('Zone %s delete successfully\n' % zone)
767 class cmd_query(Command):
770 synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|ALL> [options]'
772 takes_args = [ 'server', 'zone', 'name', 'rtype' ]
774 takes_optiongroups = {
775 "sambaopts": options.SambaOptions,
776 "versionopts": options.VersionOptions,
777 "credopts": options.CredentialsOptions,
781 Option('--authority', help='Search authoritative records (default)',
782 action='store_true', dest='authority'),
783 Option('--cache', help='Search cached records',
784 action='store_true', dest='cache'),
785 Option('--glue', help='Search glue records',
786 action='store_true', dest='glue'),
787 Option('--root', help='Search root hints',
788 action='store_true', dest='root'),
789 Option('--additional', help='List additional records',
790 action='store_true', dest='additional'),
791 Option('--no-children', help='Do not list children',
792 action='store_true', dest='no_children'),
793 Option('--only-children', help='List only children',
794 action='store_true', dest='only_children')
797 def run(self, server, zone, name, rtype, authority=False, cache=False, glue=False,
798 root=False, additional=False, no_children=False, only_children=False,
799 sambaopts=None, credopts=None, versionopts=None):
800 record_type = dns_type_flag(rtype)
804 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
806 select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
808 select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
810 select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
812 select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
814 select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
816 select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
818 if select_flags == 0:
819 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
821 if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA:
822 self.outf.write('Specify either --authority or --root along with --additional.\n')
823 self.outf.write('Assuming --authority.\n')
824 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
826 self.lp = sambaopts.get_loadparm()
827 self.creds = credopts.get_credentials(self.lp)
828 dns_conn = dns_connect(server, self.lp, self.creds)
830 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
840 print_dnsrecords(self.outf, res)
843 class cmd_roothints(Command):
844 """Query root hints"""
846 synopsis = '%prog <server> [<name>] [options]'
848 takes_args = [ 'server', 'name?' ]
850 takes_optiongroups = {
851 "sambaopts": options.SambaOptions,
852 "versionopts": options.VersionOptions,
853 "credopts": options.CredentialsOptions,
856 def run(self, server, name='.', sambaopts=None, credopts=None, versionopts=None):
857 record_type = dnsp.DNS_TYPE_NS
858 select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA |
859 dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA)
861 self.lp = sambaopts.get_loadparm()
862 self.creds = credopts.get_credentials(self.lp)
863 dns_conn = dns_connect(server, self.lp, self.creds)
865 buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
875 print_dnsrecords(self.outf, res)
878 class cmd_add_record(Command):
879 """Add a DNS record"""
881 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
883 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
885 takes_optiongroups = {
886 "sambaopts": options.SambaOptions,
887 "versionopts": options.VersionOptions,
888 "credopts": options.CredentialsOptions,
891 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
893 record_type = dns_type_flag(rtype)
895 if record_type == dnsp.DNS_TYPE_A:
897 elif record_type == dnsp.DNS_TYPE_AAAA:
898 rec = AAAARecord(data)
899 elif record_type == dnsp.DNS_TYPE_PTR:
900 rec = PTRRecord(data)
901 elif record_type == dnsp.DNS_TYPE_CNAME:
902 rec = CNameRecord(data)
903 elif record_type == dnsp.DNS_TYPE_NS:
906 raise CommandError('Adding record of type %s is not supported' % rtype)
908 self.lp = sambaopts.get_loadparm()
909 self.creds = credopts.get_credentials(self.lp)
910 dns_conn = dns_connect(server, self.lp, self.creds)
912 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
913 if rec_match is not None:
914 raise CommandError('Record already exists')
916 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
917 add_rec_buf.rec = rec
919 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
926 self.outf.write('Record added successfully\n')
929 class cmd_update_record(Command):
930 """Update a DNS record"""
932 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <olddata> <newdata>'
934 takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
936 takes_optiongroups = {
937 "sambaopts": options.SambaOptions,
938 "versionopts": options.VersionOptions,
939 "credopts": options.CredentialsOptions,
942 def run(self, server, zone, name, rtype, olddata, newdata,
943 sambaopts=None, credopts=None, versionopts=None):
945 record_type = dns_type_flag(rtype)
946 if record_type == dnsp.DNS_TYPE_A:
947 rec = ARecord(newdata)
948 elif record_type == dnsp.DNS_TYPE_AAAA:
949 rec = AAAARecord(newdata)
950 elif record_type == dnsp.DNS_TYPE_PTR:
951 rec = PTRRecord(newdata)
952 elif record_type == dnsp.DNS_TYPE_CNAME:
953 rec = CNameRecord(newdata)
954 elif record_type == dnsp.DNS_TYPE_NS:
955 rec = NSRecord(newdata)
957 raise CommandError('Updating record of type %s is not supported' % rtype)
959 self.lp = sambaopts.get_loadparm()
960 self.creds = credopts.get_credentials(self.lp)
961 dns_conn = dns_connect(server, self.lp, self.creds)
963 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, olddata)
965 raise CommandError('Record does not exist')
967 # Copy properties from existing record to new record
968 rec.dwFlags = rec_match.dwFlags
969 rec.dwSerial = rec_match.dwSerial
970 rec.dwTtlSeconds = rec_match.dwTtlSeconds
971 rec.dwTimeStamp = rec_match.dwTimeStamp
973 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
974 add_rec_buf.rec = rec
976 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
977 del_rec_buf.rec = rec_match
979 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
986 self.outf.write('Record updated succefully\n')
989 class cmd_delete_record(Command):
990 """Delete a DNS record"""
992 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
994 takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
996 takes_optiongroups = {
997 "sambaopts": options.SambaOptions,
998 "versionopts": options.VersionOptions,
999 "credopts": options.CredentialsOptions,
1002 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
1004 record_type = dns_type_flag(rtype)
1006 if record_type == dnsp.DNS_TYPE_A:
1008 elif record_type == dnsp.DNS_TYPE_AAAA:
1009 rec = AAAARecord(data)
1010 elif record_type == dnsp.DNS_TYPE_PTR:
1011 rec = PTRRecord(data)
1012 elif record_type == dnsp.DNS_TYPE_CNAME:
1013 rec = CNameRecord(data)
1014 elif record_type == dnsp.DNS_TYPE_NS:
1015 rec = NSRecord(data)
1017 raise CommandError('Deleting record of type %s is not supported' % rtype)
1019 self.lp = sambaopts.get_loadparm()
1020 self.creds = credopts.get_credentials(self.lp)
1021 dns_conn = dns_connect(server, self.lp, self.creds)
1023 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
1025 raise CommandError('Record does not exist')
1027 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1028 del_rec_buf.rec = rec_match
1030 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1037 self.outf.write('Record deleted succefully\n')
1040 class cmd_dns(SuperCommand):
1041 """Domain Name Service (DNS) management"""
1044 subcommands['serverinfo'] = cmd_serverinfo()
1045 subcommands['zoneinfo'] = cmd_zoneinfo()
1046 subcommands['zonelist'] = cmd_zonelist()
1047 subcommands['zonecreate'] = cmd_zonecreate()
1048 subcommands['zonedelete'] = cmd_zonedelete()
1049 subcommands['query'] = cmd_query()
1050 subcommands['roothints'] = cmd_roothints()
1051 subcommands['add'] = cmd_add_record()
1052 subcommands['update'] = cmd_update_record()
1053 subcommands['delete'] = cmd_delete_record()