samba-tool: dns: Add MXRecord type to add/update mx records
[ira/wip.git] / source4 / scripting / python / samba / netcmd / dns.py
1 #!/usr/bin/env python
2 #
3 # DNS management tool
4 #
5 # Copyright (C) Amitay Isaacs 2011
6 #
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.
11 #
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.
16 #
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/>.
19 #
20
21 import samba.getopt as options
22 from struct import pack
23 from socket import inet_ntoa
24
25 from samba.netcmd import (
26     Command,
27     CommandError,
28     Option,
29     SuperCommand,
30     )
31 from samba.dcerpc import dnsp, dnsserver
32
33
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)
37     return dns_conn
38
39 def bool_string(flag):
40     if flag == 0:
41         ret = 'FALSE'
42     elif flag == 1:
43         ret = 'TRUE'
44     else:
45         ret = 'UNKNOWN (0x%x)' % flag
46     return ret
47
48 def enum_string(module, enum_defs, value):
49     ret = None
50     for e in enum_defs:
51         if value == getattr(module, e):
52             ret = e
53             break
54     if not ret:
55         ret = 'UNKNOWN (0x%x)' % value
56     return ret
57
58 def bitmap_string(module, bitmap_defs, value):
59     ret = ''
60     for b in bitmap_defs:
61         if value & getattr(module, b):
62             ret += '%s ' % b
63     if not ret:
64         ret = 'NONE'
65     return ret
66
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)
71
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)
76
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)
82
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)
87
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)
92
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)
97
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)
102
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)
110
111 def ip4_array_string(array):
112     ret = []
113     if not array:
114         return ret
115     for i in xrange(array.AddrCount):
116         addr = '%s' % inet_ntoa(pack('i', array.AddrArray[i]))
117         ret.append(addr)
118     return ret
119
120 def dns_addr_array_string(array):
121     ret = []
122     if not array:
123         return ret
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]])
131         else:
132             addr = 'UNKNOWN'
133         ret.append(addr)
134     return ret
135
136 def dns_type_flag(rec_type):
137     rtype = rec_type.upper()
138     if rtype == 'A':
139         record_type = dnsp.DNS_TYPE_A
140     elif rtype == 'AAAA':
141         record_type = dnsp.DNS_TYPE_AAAA
142     elif rtype == 'PTR':
143         record_type = dnsp.DNS_TYPE_PTR
144     elif rtype == 'NS':
145         record_type = dnsp.DNS_TYPE_NS
146     elif rtype == 'CNAME':
147         record_type = dnsp.DNS_TYPE_CNAME
148     elif rtype == 'SOA':
149         record_type = dnsp.DNS_TYPE_SOA
150     elif rtype == 'MX':
151         record_type = dnsp.DNS_TYPE_MX
152     elif rtype == 'SRV':
153         record_type = dnsp.DNS_TYPE_SRV
154     elif rtype == 'ALL':
155         record_type = dnsp.DNS_TYPE_ALL
156     else:
157         raise CommandError('Unknown type of DNS record %s' % rec_type)
158     return record_type
159
160 def dns_client_version(cli_version):
161     version = cli_version.upper()
162     if version == 'W2K':
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
168     else:
169         raise CommandError('Unknown client version %s' % cli_version)
170     return client_version
171
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)
180
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))
188     else:
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))
195
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))
222
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)
231
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)
239
240     if typeid == dnsserver.DNSSRV_TYPEID_SERVER_INFO:
241         outf.write('  fReadOnlyDC                 : %s\n' % bool_string(serverinfo.fReadOnlyDC))
242
243
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))
257     else:
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))
267     else:
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))
281     else:
282         outf.write('  aipScavengeServers          : %s\n' %
283                     dns_addr_array_string(zoneinfo.aipScavengeServers))
284
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))
292         else:
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)
300
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)
307
308
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)
314
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)
318
319
320 def print_enumzones(outf, typeid, zones):
321     outf.write('  %d zone(s) found\n' % zones.dwZoneCount)
322     for zone in zones.ZoneArray:
323         outf.write('\n')
324         print_zone(outf, typeid, zone)
325
326
327 def print_dns_record(outf, rec):
328     mesg = 'Unknown: '
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' % (
341                     rec.data.dwSerialNo,
342                     rec.data.dwRefresh,
343                     rec.data.dwRetry,
344                     rec.data.dwExpire,
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))
353
354
355 def print_dnsrecords(outf, records):
356     for rec in records.rec:
357         outf.write('  Name=%s, Records=%d, Children=%d\n' % (
358                     rec.dnsNodeName.str,
359                     rec.wRecordCount,
360                     rec.dwChildCount))
361         for dns_rec in rec.records:
362                 print_dns_record(outf, dns_rec)
363
364
365 class ARecord(dnsserver.DNS_RPC_RECORD):
366     def __init__(self, ip_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
367                     node_flag=0):
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
373         self.data = ip_addr
374
375 class AAAARecord(dnsserver.DNS_RPC_RECORD):
376     def __init__(self, ip6_addr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
377                     node_flag=0):
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
383         self.data = ip6_addr
384
385 class PTRRecord(dnsserver.DNS_RPC_RECORD):
386     def __init__(self, ptr, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
387                  node_flag=0):
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()
394         ptr_name.str = ptr
395         ptr_name.len = len(ptr)
396         self.data = ptr_name
397
398 class CNameRecord(dnsserver.DNS_RPC_RECORD):
399     def __init__(self, cname, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
400                     node_flag=0):
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
410
411 class NSRecord(dnsserver.DNS_RPC_RECORD):
412     def __init__(self, dns_server, serial=1, ttl=900, rank=dnsp.DNS_RANK_ZONE,
413                     node_flag=0):
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()
420         ns.str = dns_server
421         ns.len = len(dns_server)
422         self.data = ns
423
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)
436         self.data = mx
437
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
450         soa.dwRetry = retry
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)
456         self.data = soa
457
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
468         srv.wWeight = weight
469         srv.wPort = port
470         srv.nameTarget.str = target
471         srv.nameTarget.len = len(target)
472         self.data = srv
473
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
477
478     try:
479         buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
480                                                     0,
481                                                     server,
482                                                     zone,
483                                                     name,
484                                                     None,
485                                                     record_type,
486                                                     select_flags,
487                                                     None,
488                                                     None)
489     except RuntimeError, e:
490         return None
491
492     if not res or res.count == 0:
493         return None
494
495     rec_match = None
496     for rec in res.rec[0].records:
497         if rec.wType != record_type:
498             continue
499
500         found = False
501         if record_type == dnsp.DNS_TYPE_A:
502             if rec.data == data:
503                 found = True
504         elif record_type == dnsp.DNS_TYPE_AAAA:
505             if rec.data == data:
506                 found = True
507         elif record_type == dnsp.DNS_TYPE_PTR:
508             if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
509                 found = True
510         elif record_type == dnsp.DNS_TYPE_CNAME:
511             if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
512                 found = True
513         elif record_type == dnsp.DNS_TYPE_NS:
514             if rec.data.str.rstrip('.').lower() == data.rstrip('.').lower():
515                 found = True
516         if found:
517             rec_match = rec
518             break
519
520     return rec_match
521
522
523 class cmd_serverinfo(Command):
524     """Query for Server information"""
525
526     synopsis = '%prog <server> [options]'
527
528     takes_args = [ 'server' ]
529
530     takes_optiongroups = {
531         "sambaopts": options.SambaOptions,
532         "versionopts": options.VersionOptions,
533         "credopts": options.CredentialsOptions,
534     }
535
536     takes_options = [
537         Option('--client-version', help='Client Version',
538                 default='longhorn', metavar='w2k|dotnet|longhorn',
539                 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
540     ]
541
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)
546
547         client_version = dns_client_version(cli_ver)
548
549         typeid, res = dns_conn.DnssrvQuery2(client_version,
550                                             0,
551                                             server,
552                                             None,
553                                             'ServerInfo')
554         print_serverinfo(self.outf, typeid, res)
555
556
557 class cmd_zoneinfo(Command):
558     """Query for zone information"""
559
560     synopsis = '%prog <server> <zone> [options]'
561
562     takes_args = [ 'server', 'zone' ]
563
564     takes_optiongroups = {
565         "sambaopts": options.SambaOptions,
566         "versionopts": options.VersionOptions,
567         "credopts": options.CredentialsOptions,
568     }
569
570     takes_options = [
571         Option('--client-version', help='Client Version',
572                 default='longhorn', metavar='w2k|dotnet|longhorn',
573                 choices=['w2k','dotnet','longhorn'], dest='cli_ver'),
574     ]
575
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)
580
581         client_version = dns_client_version(cli_ver)
582
583         typeid, res = dns_conn.DnssrvQuery2(client_version,
584                                             0,
585                                             server,
586                                             zone,
587                                             'ZoneInfo')
588         print_zoneinfo(self.outf, typeid, res)
589
590
591 class cmd_zonelist(Command):
592     """Query for zones"""
593
594     synopsis = '%prog <server> [options]'
595
596     takes_args = [ 'server' ]
597
598     takes_optiongroups = {
599         "sambaopts": options.SambaOptions,
600         "versionopts": options.VersionOptions,
601         "credopts": options.CredentialsOptions,
602     }
603
604     takes_options = [
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')
624     ]
625
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):
629         request_filter = 0
630
631         if primary:
632             request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY
633         if secondary:
634             request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY
635         if cache:
636             request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE
637         if auto:
638             request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO
639         if forward:
640             request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD
641         if reverse:
642             request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE
643         if ds:
644             request_filter |= dnsserver.DNS_ZONE_REQUEST_DS
645         if nonds:
646             request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS
647
648         if request_filter == 0:
649             request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY
650
651         self.lp = sambaopts.get_loadparm()
652         self.creds = credopts.get_credentials(self.lp)
653         dns_conn = dns_connect(server, self.lp, self.creds)
654
655         client_version = dns_client_version(cli_ver)
656
657         typeid, res = dns_conn.DnssrvComplexOperation2(client_version,
658                                                         0,
659                                                         server,
660                                                         None,
661                                                         'EnumZones',
662                                                         dnsserver.DNSSRV_TYPEID_DWORD,
663                                                         request_filter)
664
665         if client_version == dnsserver.DNS_CLIENT_VERSION_W2K:
666             typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K
667         else:
668             typeid = dnsserver.DNSSRV_TYPEID_ZONE
669         print_enumzones(self.outf, typeid, res)
670
671
672 class cmd_zonecreate(Command):
673     """Create a zone"""
674
675     synopsis = '%prog <server> <zone> [options]'
676
677     takes_args = [ 'server', 'zone' ]
678
679     takes_optiongroups = {
680         "sambaopts": options.SambaOptions,
681         "versionopts": options.VersionOptions,
682         "credopts": options.CredentialsOptions,
683     }
684
685     takes_options = [
686         Option('--client-version', help='Client Version',
687                 default='longhorn', metavar='w2k|dotnet|longhorn',
688                 choices=['w2k','dotnet','longhorn'], dest='cli_ver')
689     ]
690
691     def run(self, server, zone, cli_ver, sambaopts=None, credopts=None,
692             versionopts=None):
693
694         self.lp = sambaopts.get_loadparm()
695         self.creds = credopts.get_credentials(self.lp)
696         dns_conn = dns_connect(server, self.lp, self.creds)
697
698         zone = zone.lower()
699
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
716         else:
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
724
725         res = dns_conn.DnssrvOperation2(client_version,
726                                         0,
727                                         server,
728                                         None,
729                                         0,
730                                         'ZoneCreate',
731                                         typeid,
732                                         zone_create_info)
733         self.outf.write('Zone %s created successfully\n' % zone)
734
735
736 class cmd_zonedelete(Command):
737     """Delete a zone"""
738
739     synopsis = '%prog <server> <zone> [options]'
740
741     takes_args = [ 'server', 'zone' ]
742
743     takes_optiongroups = {
744         "sambaopts": options.SambaOptions,
745         "versionopts": options.VersionOptions,
746         "credopts": options.CredentialsOptions,
747     }
748
749     def run(self, server, zone, sambaopts=None, credopts=None, versionopts=None):
750
751         self.lp = sambaopts.get_loadparm()
752         self.creds = credopts.get_credentials(self.lp)
753         dns_conn = dns_connect(server, self.lp, self.creds)
754
755         zone = zone.lower()
756         res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
757                                         0,
758                                         server,
759                                         zone,
760                                         0,
761                                         'DeleteZoneFromDs',
762                                         dnsserver.DNSSRV_TYPEID_NULL,
763                                         None)
764         self.outf.write('Zone %s delete successfully\n' % zone)
765
766
767 class cmd_query(Command):
768     """Query a name."""
769
770     synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|ALL> [options]'
771
772     takes_args = [ 'server', 'zone', 'name', 'rtype' ]
773
774     takes_optiongroups = {
775         "sambaopts": options.SambaOptions,
776         "versionopts": options.VersionOptions,
777         "credopts": options.CredentialsOptions,
778     }
779
780     takes_options = [
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')
795     ]
796
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)
801
802         select_flags = 0
803         if authority:
804             select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
805         if cache:
806             select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA
807         if glue:
808             select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA
809         if root:
810             select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA
811         if additional:
812             select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA
813         if no_children:
814             select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN
815         if only_children:
816             select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN
817
818         if select_flags == 0:
819             select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA
820
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
825
826         self.lp = sambaopts.get_loadparm()
827         self.creds = credopts.get_credentials(self.lp)
828         dns_conn = dns_connect(server, self.lp, self.creds)
829
830         buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
831                                                     0,
832                                                     server,
833                                                     zone,
834                                                     name,
835                                                     None,
836                                                     record_type,
837                                                     select_flags,
838                                                     None,
839                                                     None)
840         print_dnsrecords(self.outf, res)
841
842
843 class cmd_roothints(Command):
844     """Query root hints"""
845
846     synopsis = '%prog <server> [<name>] [options]'
847
848     takes_args = [ 'server', 'name?' ]
849
850     takes_optiongroups = {
851         "sambaopts": options.SambaOptions,
852         "versionopts": options.VersionOptions,
853         "credopts": options.CredentialsOptions,
854     }
855
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)
860
861         self.lp = sambaopts.get_loadparm()
862         self.creds = credopts.get_credentials(self.lp)
863         dns_conn = dns_connect(server, self.lp, self.creds)
864
865         buflen, res = dns_conn.DnssrvEnumRecords2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
866                                                     0,
867                                                     server,
868                                                     '..RootHints',
869                                                     name,
870                                                     None,
871                                                     record_type,
872                                                     select_flags,
873                                                     None,
874                                                     None)
875         print_dnsrecords(self.outf, res)
876
877
878 class cmd_add_record(Command):
879     """Add a DNS record"""
880
881     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
882
883     takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
884
885     takes_optiongroups = {
886         "sambaopts": options.SambaOptions,
887         "versionopts": options.VersionOptions,
888         "credopts": options.CredentialsOptions,
889     }
890
891     def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
892
893         record_type = dns_type_flag(rtype)
894
895         if record_type == dnsp.DNS_TYPE_A:
896             rec = ARecord(data)
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:
904             rec = NSRecord(data)
905         else:
906             raise CommandError('Adding record of type %s is not supported' % rtype)
907
908         self.lp = sambaopts.get_loadparm()
909         self.creds = credopts.get_credentials(self.lp)
910         dns_conn = dns_connect(server, self.lp, self.creds)
911
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')
915
916         add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
917         add_rec_buf.rec = rec
918
919         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
920                                         0,
921                                         server,
922                                         zone,
923                                         name,
924                                         add_rec_buf,
925                                         None)
926         self.outf.write('Record added successfully\n')
927
928
929 class cmd_update_record(Command):
930     """Update a DNS record"""
931
932     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <olddata> <newdata>'
933
934     takes_args = [ 'server', 'zone', 'name', 'rtype', 'olddata', 'newdata' ]
935
936     takes_optiongroups = {
937         "sambaopts": options.SambaOptions,
938         "versionopts": options.VersionOptions,
939         "credopts": options.CredentialsOptions,
940     }
941
942     def run(self, server, zone, name, rtype, olddata, newdata,
943                 sambaopts=None, credopts=None, versionopts=None):
944
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)
956         else:
957             raise CommandError('Updating record of type %s is not supported' % rtype)
958
959         self.lp = sambaopts.get_loadparm()
960         self.creds = credopts.get_credentials(self.lp)
961         dns_conn = dns_connect(server, self.lp, self.creds)
962
963         rec_match = dns_record_match(dns_conn, server, zone, name, record_type, olddata)
964         if not rec_match:
965             raise CommandError('Record does not exist')
966
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
972
973         add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
974         add_rec_buf.rec = rec
975
976         del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
977         del_rec_buf.rec = rec_match
978
979         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
980                                         0,
981                                         server,
982                                         zone,
983                                         name,
984                                         add_rec_buf,
985                                         del_rec_buf)
986         self.outf.write('Record updated succefully\n')
987
988
989 class cmd_delete_record(Command):
990     """Delete a DNS record"""
991
992     synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS> <data>'
993
994     takes_args = [ 'server', 'zone', 'name', 'rtype', 'data' ]
995
996     takes_optiongroups = {
997         "sambaopts": options.SambaOptions,
998         "versionopts": options.VersionOptions,
999         "credopts": options.CredentialsOptions,
1000     }
1001
1002     def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None):
1003
1004         record_type = dns_type_flag(rtype)
1005
1006         if record_type == dnsp.DNS_TYPE_A:
1007             rec = ARecord(data)
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)
1016         else:
1017             raise CommandError('Deleting record of type %s is not supported' % rtype)
1018
1019         self.lp = sambaopts.get_loadparm()
1020         self.creds = credopts.get_credentials(self.lp)
1021         dns_conn = dns_connect(server, self.lp, self.creds)
1022
1023         rec_match = dns_record_match(dns_conn, server, zone, name, record_type, data)
1024         if not rec_match:
1025             raise CommandError('Record does not exist')
1026
1027         del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF()
1028         del_rec_buf.rec = rec_match
1029
1030         dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN,
1031                                         0,
1032                                         server,
1033                                         zone,
1034                                         name,
1035                                         None,
1036                                         del_rec_buf)
1037         self.outf.write('Record deleted succefully\n')
1038
1039
1040 class cmd_dns(SuperCommand):
1041     """Domain Name Service (DNS) management"""
1042
1043     subcommands = {}
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()