1# DNS management tool 2# 3# Copyright (C) Amitay Isaacs 2011-2012 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 3 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program. If not, see <http://www.gnu.org/licenses/>. 17# 18import logging 19 20import samba.getopt as options 21from samba import WERRORError 22from samba import werror 23from struct import pack 24from socket import inet_ntoa 25from socket import inet_ntop 26from socket import AF_INET 27from socket import AF_INET6 28import shlex 29import struct 30 31from samba import remove_dc 32from samba.samdb import SamDB 33from samba.auth import system_session 34 35from samba.netcmd import ( 36 Command, 37 CommandError, 38 Option, 39 SuperCommand, 40) 41from samba.dcerpc import dnsp, dnsserver 42 43from samba.dnsserver import ARecord, AAAARecord, PTRRecord, CNameRecord, NSRecord, MXRecord, SOARecord, SRVRecord, TXTRecord 44 45 46def dns_connect(server, lp, creds): 47 if server.lower() == 'localhost': 48 server = '127.0.0.1' 49 binding_str = "ncacn_ip_tcp:%s[sign]" % server 50 try: 51 dns_conn = dnsserver.dnsserver(binding_str, lp, creds) 52 except RuntimeError as e: 53 raise CommandError('Connecting to DNS RPC server %s failed with %s' % (server, e)) 54 55 return dns_conn 56 57 58def bool_string(flag): 59 if flag == 0: 60 ret = 'FALSE' 61 elif flag == 1: 62 ret = 'TRUE' 63 else: 64 ret = 'UNKNOWN (0x%x)' % flag 65 return ret 66 67 68def enum_string(module, enum_defs, value): 69 ret = None 70 for e in enum_defs: 71 if value == getattr(module, e): 72 ret = e 73 break 74 if not ret: 75 ret = 'UNKNOWN (0x%x)' % value 76 return ret 77 78 79def bitmap_string(module, bitmap_defs, value): 80 ret = '' 81 for b in bitmap_defs: 82 if value & getattr(module, b): 83 ret += '%s ' % b 84 if not ret: 85 ret = 'NONE' 86 return ret 87 88 89def boot_method_string(boot_method): 90 enum_defs = ['DNS_BOOT_METHOD_UNINITIALIZED', 'DNS_BOOT_METHOD_FILE', 91 'DNS_BOOT_METHOD_REGISTRY', 'DNS_BOOT_METHOD_DIRECTORY'] 92 return enum_string(dnsserver, enum_defs, boot_method) 93 94 95def name_check_flag_string(check_flag): 96 enum_defs = ['DNS_ALLOW_RFC_NAMES_ONLY', 'DNS_ALLOW_NONRFC_NAMES', 97 'DNS_ALLOW_MULTIBYTE_NAMES', 'DNS_ALLOW_ALL_NAMES'] 98 return enum_string(dnsserver, enum_defs, check_flag) 99 100 101def zone_type_string(zone_type): 102 enum_defs = ['DNS_ZONE_TYPE_CACHE', 'DNS_ZONE_TYPE_PRIMARY', 103 'DNS_ZONE_TYPE_SECONDARY', 'DNS_ZONE_TYPE_STUB', 104 'DNS_ZONE_TYPE_FORWARDER', 'DNS_ZONE_TYPE_SECONDARY_CACHE'] 105 return enum_string(dnsp, enum_defs, zone_type) 106 107 108def zone_update_string(zone_update): 109 enum_defs = ['DNS_ZONE_UPDATE_OFF', 'DNS_ZONE_UPDATE_UNSECURE', 110 'DNS_ZONE_UPDATE_SECURE'] 111 return enum_string(dnsp, enum_defs, zone_update) 112 113 114def zone_secondary_security_string(security): 115 enum_defs = ['DNS_ZONE_SECSECURE_NO_SECURITY', 'DNS_ZONE_SECSECURE_NS_ONLY', 116 'DNS_ZONE_SECSECURE_LIST_ONLY', 'DNS_ZONE_SECSECURE_NO_XFER'] 117 return enum_string(dnsserver, enum_defs, security) 118 119 120def zone_notify_level_string(notify_level): 121 enum_defs = ['DNS_ZONE_NOTIFY_OFF', 'DNS_ZONE_NOTIFY_ALL_SECONDARIES', 122 'DNS_ZONE_NOTIFY_LIST_ONLY'] 123 return enum_string(dnsserver, enum_defs, notify_level) 124 125 126def dp_flags_string(dp_flags): 127 bitmap_defs = ['DNS_DP_AUTOCREATED', 'DNS_DP_LEGACY', 'DNS_DP_DOMAIN_DEFAULT', 128 'DNS_DP_FOREST_DEFAULT', 'DNS_DP_ENLISTED', 'DNS_DP_DELETED'] 129 return bitmap_string(dnsserver, bitmap_defs, dp_flags) 130 131 132def zone_flags_string(flags): 133 bitmap_defs = ['DNS_RPC_ZONE_PAUSED', 'DNS_RPC_ZONE_SHUTDOWN', 134 'DNS_RPC_ZONE_REVERSE', 'DNS_RPC_ZONE_AUTOCREATED', 135 'DNS_RPC_ZONE_DSINTEGRATED', 'DNS_RPC_ZONE_AGING', 136 'DNS_RPC_ZONE_UPDATE_UNSECURE', 'DNS_RPC_ZONE_UPDATE_SECURE', 137 'DNS_RPC_ZONE_READONLY'] 138 return bitmap_string(dnsserver, bitmap_defs, flags) 139 140 141def ip4_array_string(array): 142 ret = [] 143 if not array: 144 return ret 145 for i in range(array.AddrCount): 146 addr = inet_ntop(AF_INET, pack('I', array.AddrArray[i])) 147 ret.append(addr) 148 return ret 149 150 151def dns_addr_array_string(array): 152 ret = [] 153 if not array: 154 return ret 155 for i in range(array.AddrCount): 156 if array.AddrArray[i].MaxSa[0] == 0x02: 157 x = struct.pack('4B', *array.AddrArray[i].MaxSa[4:8]) 158 addr = inet_ntop(AF_INET, x) 159 elif array.AddrArray[i].MaxSa[0] == 0x17: 160 x = struct.pack('16B', *array.AddrArray[i].MaxSa[8:24]) 161 addr = inet_ntop(AF_INET6, x) 162 else: 163 addr = 'UNKNOWN' 164 ret.append(addr) 165 return ret 166 167 168def dns_type_flag(rec_type): 169 rtype = rec_type.upper() 170 if rtype == 'A': 171 record_type = dnsp.DNS_TYPE_A 172 elif rtype == 'AAAA': 173 record_type = dnsp.DNS_TYPE_AAAA 174 elif rtype == 'PTR': 175 record_type = dnsp.DNS_TYPE_PTR 176 elif rtype == 'NS': 177 record_type = dnsp.DNS_TYPE_NS 178 elif rtype == 'CNAME': 179 record_type = dnsp.DNS_TYPE_CNAME 180 elif rtype == 'SOA': 181 record_type = dnsp.DNS_TYPE_SOA 182 elif rtype == 'MX': 183 record_type = dnsp.DNS_TYPE_MX 184 elif rtype == 'SRV': 185 record_type = dnsp.DNS_TYPE_SRV 186 elif rtype == 'TXT': 187 record_type = dnsp.DNS_TYPE_TXT 188 elif rtype == 'ALL': 189 record_type = dnsp.DNS_TYPE_ALL 190 else: 191 raise CommandError('Unknown type of DNS record %s' % rec_type) 192 return record_type 193 194 195def dns_client_version(cli_version): 196 version = cli_version.upper() 197 if version == 'W2K': 198 client_version = dnsserver.DNS_CLIENT_VERSION_W2K 199 elif version == 'DOTNET': 200 client_version = dnsserver.DNS_CLIENT_VERSION_DOTNET 201 elif version == 'LONGHORN': 202 client_version = dnsserver.DNS_CLIENT_VERSION_LONGHORN 203 else: 204 raise CommandError('Unknown client version %s' % cli_version) 205 return client_version 206 207 208def print_serverinfo(outf, typeid, serverinfo): 209 outf.write(' dwVersion : 0x%x\n' % serverinfo.dwVersion) 210 outf.write(' fBootMethod : %s\n' % boot_method_string(serverinfo.fBootMethod)) 211 outf.write(' fAdminConfigured : %s\n' % bool_string(serverinfo.fAdminConfigured)) 212 outf.write(' fAllowUpdate : %s\n' % bool_string(serverinfo.fAllowUpdate)) 213 outf.write(' fDsAvailable : %s\n' % bool_string(serverinfo.fDsAvailable)) 214 outf.write(' pszServerName : %s\n' % serverinfo.pszServerName) 215 outf.write(' pszDsContainer : %s\n' % serverinfo.pszDsContainer) 216 217 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO: 218 outf.write(' aipServerAddrs : %s\n' % 219 ip4_array_string(serverinfo.aipServerAddrs)) 220 outf.write(' aipListenAddrs : %s\n' % 221 ip4_array_string(serverinfo.aipListenAddrs)) 222 outf.write(' aipForwarders : %s\n' % 223 ip4_array_string(serverinfo.aipForwarders)) 224 else: 225 outf.write(' aipServerAddrs : %s\n' % 226 dns_addr_array_string(serverinfo.aipServerAddrs)) 227 outf.write(' aipListenAddrs : %s\n' % 228 dns_addr_array_string(serverinfo.aipListenAddrs)) 229 outf.write(' aipForwarders : %s\n' % 230 dns_addr_array_string(serverinfo.aipForwarders)) 231 232 outf.write(' dwLogLevel : %d\n' % serverinfo.dwLogLevel) 233 outf.write(' dwDebugLevel : %d\n' % serverinfo.dwDebugLevel) 234 outf.write(' dwForwardTimeout : %d\n' % serverinfo.dwForwardTimeout) 235 outf.write(' dwRpcPrototol : 0x%x\n' % serverinfo.dwRpcProtocol) 236 outf.write(' dwNameCheckFlag : %s\n' % name_check_flag_string(serverinfo.dwNameCheckFlag)) 237 outf.write(' cAddressAnswerLimit : %d\n' % serverinfo.cAddressAnswerLimit) 238 outf.write(' dwRecursionRetry : %d\n' % serverinfo.dwRecursionRetry) 239 outf.write(' dwRecursionTimeout : %d\n' % serverinfo.dwRecursionTimeout) 240 outf.write(' dwMaxCacheTtl : %d\n' % serverinfo.dwMaxCacheTtl) 241 outf.write(' dwDsPollingInterval : %d\n' % serverinfo.dwDsPollingInterval) 242 outf.write(' dwScavengingInterval : %d\n' % serverinfo.dwScavengingInterval) 243 outf.write(' dwDefaultRefreshInterval : %d\n' % serverinfo.dwDefaultRefreshInterval) 244 outf.write(' dwDefaultNoRefreshInterval : %d\n' % serverinfo.dwDefaultNoRefreshInterval) 245 outf.write(' fAutoReverseZones : %s\n' % bool_string(serverinfo.fAutoReverseZones)) 246 outf.write(' fAutoCacheUpdate : %s\n' % bool_string(serverinfo.fAutoCacheUpdate)) 247 outf.write(' fRecurseAfterForwarding : %s\n' % bool_string(serverinfo.fRecurseAfterForwarding)) 248 outf.write(' fForwardDelegations : %s\n' % bool_string(serverinfo.fForwardDelegations)) 249 outf.write(' fNoRecursion : %s\n' % bool_string(serverinfo.fNoRecursion)) 250 outf.write(' fSecureResponses : %s\n' % bool_string(serverinfo.fSecureResponses)) 251 outf.write(' fRoundRobin : %s\n' % bool_string(serverinfo.fRoundRobin)) 252 outf.write(' fLocalNetPriority : %s\n' % bool_string(serverinfo.fLocalNetPriority)) 253 outf.write(' fBindSecondaries : %s\n' % bool_string(serverinfo.fBindSecondaries)) 254 outf.write(' fWriteAuthorityNs : %s\n' % bool_string(serverinfo.fWriteAuthorityNs)) 255 outf.write(' fStrictFileParsing : %s\n' % bool_string(serverinfo.fStrictFileParsing)) 256 outf.write(' fLooseWildcarding : %s\n' % bool_string(serverinfo.fLooseWildcarding)) 257 outf.write(' fDefaultAgingState : %s\n' % bool_string(serverinfo.fDefaultAgingState)) 258 259 if typeid != dnsserver.DNSSRV_TYPEID_SERVER_INFO_W2K: 260 outf.write(' dwRpcStructureVersion : 0x%x\n' % serverinfo.dwRpcStructureVersion) 261 outf.write(' aipLogFilter : %s\n' % dns_addr_array_string(serverinfo.aipLogFilter)) 262 outf.write(' pwszLogFilePath : %s\n' % serverinfo.pwszLogFilePath) 263 outf.write(' pszDomainName : %s\n' % serverinfo.pszDomainName) 264 outf.write(' pszForestName : %s\n' % serverinfo.pszForestName) 265 outf.write(' pszDomainDirectoryPartition : %s\n' % serverinfo.pszDomainDirectoryPartition) 266 outf.write(' pszForestDirectoryPartition : %s\n' % serverinfo.pszForestDirectoryPartition) 267 268 outf.write(' dwLocalNetPriorityNetMask : 0x%x\n' % serverinfo.dwLocalNetPriorityNetMask) 269 outf.write(' dwLastScavengeTime : %d\n' % serverinfo.dwLastScavengeTime) 270 outf.write(' dwEventLogLevel : %d\n' % serverinfo.dwEventLogLevel) 271 outf.write(' dwLogFileMaxSize : %d\n' % serverinfo.dwLogFileMaxSize) 272 outf.write(' dwDsForestVersion : %d\n' % serverinfo.dwDsForestVersion) 273 outf.write(' dwDsDomainVersion : %d\n' % serverinfo.dwDsDomainVersion) 274 outf.write(' dwDsDsaVersion : %d\n' % serverinfo.dwDsDsaVersion) 275 276 if typeid == dnsserver.DNSSRV_TYPEID_SERVER_INFO: 277 outf.write(' fReadOnlyDC : %s\n' % bool_string(serverinfo.fReadOnlyDC)) 278 279 280def print_zoneinfo(outf, typeid, zoneinfo): 281 outf.write(' pszZoneName : %s\n' % zoneinfo.pszZoneName) 282 outf.write(' dwZoneType : %s\n' % zone_type_string(zoneinfo.dwZoneType)) 283 outf.write(' fReverse : %s\n' % bool_string(zoneinfo.fReverse)) 284 outf.write(' fAllowUpdate : %s\n' % zone_update_string(zoneinfo.fAllowUpdate)) 285 outf.write(' fPaused : %s\n' % bool_string(zoneinfo.fPaused)) 286 outf.write(' fShutdown : %s\n' % bool_string(zoneinfo.fShutdown)) 287 outf.write(' fAutoCreated : %s\n' % bool_string(zoneinfo.fAutoCreated)) 288 outf.write(' fUseDatabase : %s\n' % bool_string(zoneinfo.fUseDatabase)) 289 outf.write(' pszDataFile : %s\n' % zoneinfo.pszDataFile) 290 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO: 291 outf.write(' aipMasters : %s\n' % 292 ip4_array_string(zoneinfo.aipMasters)) 293 else: 294 outf.write(' aipMasters : %s\n' % 295 dns_addr_array_string(zoneinfo.aipMasters)) 296 outf.write(' fSecureSecondaries : %s\n' % zone_secondary_security_string(zoneinfo.fSecureSecondaries)) 297 outf.write(' fNotifyLevel : %s\n' % zone_notify_level_string(zoneinfo.fNotifyLevel)) 298 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO: 299 outf.write(' aipSecondaries : %s\n' % 300 ip4_array_string(zoneinfo.aipSecondaries)) 301 outf.write(' aipNotify : %s\n' % 302 ip4_array_string(zoneinfo.aipNotify)) 303 else: 304 outf.write(' aipSecondaries : %s\n' % 305 dns_addr_array_string(zoneinfo.aipSecondaries)) 306 outf.write(' aipNotify : %s\n' % 307 dns_addr_array_string(zoneinfo.aipNotify)) 308 outf.write(' fUseWins : %s\n' % bool_string(zoneinfo.fUseWins)) 309 outf.write(' fUseNbstat : %s\n' % bool_string(zoneinfo.fUseNbstat)) 310 outf.write(' fAging : %s\n' % bool_string(zoneinfo.fAging)) 311 outf.write(' dwNoRefreshInterval : %d\n' % zoneinfo.dwNoRefreshInterval) 312 outf.write(' dwRefreshInterval : %d\n' % zoneinfo.dwRefreshInterval) 313 outf.write(' dwAvailForScavengeTime : %d\n' % zoneinfo.dwAvailForScavengeTime) 314 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO: 315 outf.write(' aipScavengeServers : %s\n' % 316 ip4_array_string(zoneinfo.aipScavengeServers)) 317 else: 318 outf.write(' aipScavengeServers : %s\n' % 319 dns_addr_array_string(zoneinfo.aipScavengeServers)) 320 321 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO_W2K: 322 outf.write(' dwRpcStructureVersion : 0x%x\n' % zoneinfo.dwRpcStructureVersion) 323 outf.write(' dwForwarderTimeout : %d\n' % zoneinfo.dwForwarderTimeout) 324 outf.write(' fForwarderSlave : %d\n' % zoneinfo.fForwarderSlave) 325 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_INFO: 326 outf.write(' aipLocalMasters : %s\n' % 327 ip4_array_string(zoneinfo.aipLocalMasters)) 328 else: 329 outf.write(' aipLocalMasters : %s\n' % 330 dns_addr_array_string(zoneinfo.aipLocalMasters)) 331 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zoneinfo.dwDpFlags)) 332 outf.write(' pszDpFqdn : %s\n' % zoneinfo.pszDpFqdn) 333 outf.write(' pwszZoneDn : %s\n' % zoneinfo.pwszZoneDn) 334 outf.write(' dwLastSuccessfulSoaCheck : %d\n' % zoneinfo.dwLastSuccessfulSoaCheck) 335 outf.write(' dwLastSuccessfulXfr : %d\n' % zoneinfo.dwLastSuccessfulXfr) 336 337 if typeid == dnsserver.DNSSRV_TYPEID_ZONE_INFO: 338 outf.write(' fQueuedForBackgroundLoad : %s\n' % bool_string(zoneinfo.fQueuedForBackgroundLoad)) 339 outf.write(' fBackgroundLoadInProgress : %s\n' % bool_string(zoneinfo.fBackgroundLoadInProgress)) 340 outf.write(' fReadOnlyZone : %s\n' % bool_string(zoneinfo.fReadOnlyZone)) 341 outf.write(' dwLastXfrAttempt : %d\n' % zoneinfo.dwLastXfrAttempt) 342 outf.write(' dwLastXfrResult : %d\n' % zoneinfo.dwLastXfrResult) 343 344 345def print_zone(outf, typeid, zone): 346 outf.write(' pszZoneName : %s\n' % zone.pszZoneName) 347 outf.write(' Flags : %s\n' % zone_flags_string(zone.Flags)) 348 outf.write(' ZoneType : %s\n' % zone_type_string(zone.ZoneType)) 349 outf.write(' Version : %s\n' % zone.Version) 350 351 if typeid != dnsserver.DNSSRV_TYPEID_ZONE_W2K: 352 outf.write(' dwDpFlags : %s\n' % dp_flags_string(zone.dwDpFlags)) 353 outf.write(' pszDpFqdn : %s\n' % zone.pszDpFqdn) 354 355 356def print_enumzones(outf, typeid, zones): 357 outf.write(' %d zone(s) found\n' % zones.dwZoneCount) 358 for zone in zones.ZoneArray: 359 outf.write('\n') 360 print_zone(outf, typeid, zone) 361 362 363def print_dns_record(outf, rec): 364 if rec.wType == dnsp.DNS_TYPE_A: 365 mesg = 'A: %s' % (rec.data) 366 elif rec.wType == dnsp.DNS_TYPE_AAAA: 367 mesg = 'AAAA: %s' % (rec.data) 368 elif rec.wType == dnsp.DNS_TYPE_PTR: 369 mesg = 'PTR: %s' % (rec.data.str) 370 elif rec.wType == dnsp.DNS_TYPE_NS: 371 mesg = 'NS: %s' % (rec.data.str) 372 elif rec.wType == dnsp.DNS_TYPE_CNAME: 373 mesg = 'CNAME: %s' % (rec.data.str) 374 elif rec.wType == dnsp.DNS_TYPE_SOA: 375 mesg = 'SOA: serial=%d, refresh=%d, retry=%d, expire=%d, minttl=%d, ns=%s, email=%s' % ( 376 rec.data.dwSerialNo, 377 rec.data.dwRefresh, 378 rec.data.dwRetry, 379 rec.data.dwExpire, 380 rec.data.dwMinimumTtl, 381 rec.data.NamePrimaryServer.str, 382 rec.data.ZoneAdministratorEmail.str) 383 elif rec.wType == dnsp.DNS_TYPE_MX: 384 mesg = 'MX: %s (%d)' % (rec.data.nameExchange.str, rec.data.wPreference) 385 elif rec.wType == dnsp.DNS_TYPE_SRV: 386 mesg = 'SRV: %s (%d, %d, %d)' % (rec.data.nameTarget.str, rec.data.wPort, 387 rec.data.wPriority, rec.data.wWeight) 388 elif rec.wType == dnsp.DNS_TYPE_TXT: 389 slist = ['"%s"' % name.str for name in rec.data.str] 390 mesg = 'TXT: %s' % ','.join(slist) 391 else: 392 mesg = 'Unknown: ' 393 outf.write(' %s (flags=%x, serial=%d, ttl=%d)\n' % ( 394 mesg, rec.dwFlags, rec.dwSerial, rec.dwTtlSeconds)) 395 396 397def print_dnsrecords(outf, records): 398 for rec in records.rec: 399 outf.write(' Name=%s, Records=%d, Children=%d\n' % ( 400 rec.dnsNodeName.str, 401 rec.wRecordCount, 402 rec.dwChildCount)) 403 for dns_rec in rec.records: 404 print_dns_record(outf, dns_rec) 405 406 407# Convert data into a dns record 408def data_to_dns_record(record_type, data): 409 if record_type == dnsp.DNS_TYPE_A: 410 rec = ARecord(data) 411 elif record_type == dnsp.DNS_TYPE_AAAA: 412 rec = AAAARecord(data) 413 elif record_type == dnsp.DNS_TYPE_PTR: 414 rec = PTRRecord(data) 415 elif record_type == dnsp.DNS_TYPE_CNAME: 416 rec = CNameRecord(data) 417 elif record_type == dnsp.DNS_TYPE_NS: 418 rec = NSRecord(data) 419 elif record_type == dnsp.DNS_TYPE_MX: 420 tmp = data.split() 421 if len(tmp) != 2: 422 raise CommandError('Data requires 2 elements - mail_server, preference') 423 mail_server = tmp[0] 424 preference = int(tmp[1]) 425 rec = MXRecord(mail_server, preference) 426 elif record_type == dnsp.DNS_TYPE_SRV: 427 tmp = data.split() 428 if len(tmp) != 4: 429 raise CommandError('Data requires 4 elements - server, port, priority, weight') 430 server = tmp[0] 431 port = int(tmp[1]) 432 priority = int(tmp[2]) 433 weight = int(tmp[3]) 434 rec = SRVRecord(server, port, priority=priority, weight=weight) 435 elif record_type == dnsp.DNS_TYPE_SOA: 436 tmp = data.split() 437 if len(tmp) != 7: 438 raise CommandError('Data requires 7 elements - nameserver, email, serial, ' 439 'refresh, retry, expire, minimumttl') 440 nameserver = tmp[0] 441 email = tmp[1] 442 serial = int(tmp[2]) 443 refresh = int(tmp[3]) 444 retry = int(tmp[4]) 445 expire = int(tmp[5]) 446 minimum = int(tmp[6]) 447 rec = SOARecord(nameserver, email, serial=serial, refresh=refresh, 448 retry=retry, expire=expire, minimum=minimum) 449 elif record_type == dnsp.DNS_TYPE_TXT: 450 slist = shlex.split(data) 451 rec = TXTRecord(slist) 452 else: 453 raise CommandError('Unsupported record type') 454 return rec 455 456 457# Match dns name (of type DNS_RPC_NAME) 458def dns_name_equal(n1, n2): 459 return n1.str.rstrip('.').lower() == n2.str.rstrip('.').lower() 460 461 462# Match a dns record with specified data 463def dns_record_match(dns_conn, server, zone, name, record_type, data): 464 urec = data_to_dns_record(record_type, data) 465 466 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA 467 468 try: 469 buflen, res = dns_conn.DnssrvEnumRecords2( 470 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name, None, 471 record_type, select_flags, None, None) 472 except WERRORError as e: 473 if e.args[0] == werror.WERR_DNS_ERROR_NAME_DOES_NOT_EXIST: 474 # Either the zone doesn't exist, or there were no records. 475 # We can't differentiate the two. 476 return None 477 raise e 478 479 if not res or res.count == 0: 480 return None 481 482 for rec in res.rec[0].records: 483 if rec.wType != record_type: 484 continue 485 486 found = False 487 if record_type == dnsp.DNS_TYPE_A: 488 if rec.data == urec.data: 489 found = True 490 elif record_type == dnsp.DNS_TYPE_AAAA: 491 if rec.data == urec.data: 492 found = True 493 elif record_type == dnsp.DNS_TYPE_PTR: 494 if dns_name_equal(rec.data, urec.data): 495 found = True 496 elif record_type == dnsp.DNS_TYPE_CNAME: 497 if dns_name_equal(rec.data, urec.data): 498 found = True 499 elif record_type == dnsp.DNS_TYPE_NS: 500 if dns_name_equal(rec.data, urec.data): 501 found = True 502 elif record_type == dnsp.DNS_TYPE_MX: 503 if dns_name_equal(rec.data.nameExchange, urec.data.nameExchange) and \ 504 rec.data.wPreference == urec.data.wPreference: 505 found = True 506 elif record_type == dnsp.DNS_TYPE_SRV: 507 if rec.data.wPriority == urec.data.wPriority and \ 508 rec.data.wWeight == urec.data.wWeight and \ 509 rec.data.wPort == urec.data.wPort and \ 510 dns_name_equal(rec.data.nameTarget, urec.data.nameTarget): 511 found = True 512 elif record_type == dnsp.DNS_TYPE_SOA: 513 if rec.data.dwSerialNo == urec.data.dwSerialNo and \ 514 rec.data.dwRefresh == urec.data.dwRefresh and \ 515 rec.data.dwRetry == urec.data.dwRetry and \ 516 rec.data.dwExpire == urec.data.dwExpire and \ 517 rec.data.dwMinimumTtl == urec.data.dwMinimumTtl and \ 518 dns_name_equal(rec.data.NamePrimaryServer, 519 urec.data.NamePrimaryServer) and \ 520 dns_name_equal(rec.data.ZoneAdministratorEmail, 521 urec.data.ZoneAdministratorEmail): 522 found = True 523 elif record_type == dnsp.DNS_TYPE_TXT: 524 if rec.data.count == urec.data.count: 525 found = True 526 for i in range(rec.data.count): 527 found = found and \ 528 (rec.data.str[i].str == urec.data.str[i].str) 529 530 if found: 531 return rec 532 533 return None 534 535 536class cmd_serverinfo(Command): 537 """Query for Server information.""" 538 539 synopsis = '%prog <server> [options]' 540 541 takes_args = ['server'] 542 543 takes_optiongroups = { 544 "sambaopts": options.SambaOptions, 545 "versionopts": options.VersionOptions, 546 "credopts": options.CredentialsOptions, 547 } 548 549 takes_options = [ 550 Option('--client-version', help='Client Version', 551 default='longhorn', metavar='w2k|dotnet|longhorn', 552 choices=['w2k', 'dotnet', 'longhorn'], dest='cli_ver'), 553 ] 554 555 def run(self, server, cli_ver, sambaopts=None, credopts=None, 556 versionopts=None): 557 self.lp = sambaopts.get_loadparm() 558 self.creds = credopts.get_credentials(self.lp) 559 dns_conn = dns_connect(server, self.lp, self.creds) 560 561 client_version = dns_client_version(cli_ver) 562 563 typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server, 564 None, 'ServerInfo') 565 print_serverinfo(self.outf, typeid, res) 566 567 568class cmd_zoneinfo(Command): 569 """Query for zone information.""" 570 571 synopsis = '%prog <server> <zone> [options]' 572 573 takes_args = ['server', 'zone'] 574 575 takes_optiongroups = { 576 "sambaopts": options.SambaOptions, 577 "versionopts": options.VersionOptions, 578 "credopts": options.CredentialsOptions, 579 } 580 581 takes_options = [ 582 Option('--client-version', help='Client Version', 583 default='longhorn', metavar='w2k|dotnet|longhorn', 584 choices=['w2k', 'dotnet', 'longhorn'], dest='cli_ver'), 585 ] 586 587 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, 588 versionopts=None): 589 self.lp = sambaopts.get_loadparm() 590 self.creds = credopts.get_credentials(self.lp) 591 dns_conn = dns_connect(server, self.lp, self.creds) 592 593 client_version = dns_client_version(cli_ver) 594 595 typeid, res = dns_conn.DnssrvQuery2(client_version, 0, server, zone, 596 'ZoneInfo') 597 print_zoneinfo(self.outf, typeid, res) 598 599 600class cmd_zonelist(Command): 601 """Query for zones.""" 602 603 synopsis = '%prog <server> [options]' 604 605 takes_args = ['server'] 606 607 takes_optiongroups = { 608 "sambaopts": options.SambaOptions, 609 "versionopts": options.VersionOptions, 610 "credopts": options.CredentialsOptions, 611 } 612 613 takes_options = [ 614 Option('--client-version', help='Client Version', 615 default='longhorn', metavar='w2k|dotnet|longhorn', 616 choices=['w2k', 'dotnet', 'longhorn'], dest='cli_ver'), 617 Option('--primary', help='List primary zones (default)', 618 action='store_true', dest='primary'), 619 Option('--secondary', help='List secondary zones', 620 action='store_true', dest='secondary'), 621 Option('--cache', help='List cached zones', 622 action='store_true', dest='cache'), 623 Option('--auto', help='List automatically created zones', 624 action='store_true', dest='auto'), 625 Option('--forward', help='List forward zones', 626 action='store_true', dest='forward'), 627 Option('--reverse', help='List reverse zones', 628 action='store_true', dest='reverse'), 629 Option('--ds', help='List directory integrated zones', 630 action='store_true', dest='ds'), 631 Option('--non-ds', help='List non-directory zones', 632 action='store_true', dest='nonds') 633 ] 634 635 def run(self, server, cli_ver, primary=False, secondary=False, cache=False, 636 auto=False, forward=False, reverse=False, ds=False, nonds=False, 637 sambaopts=None, credopts=None, versionopts=None): 638 request_filter = 0 639 640 if primary: 641 request_filter |= dnsserver.DNS_ZONE_REQUEST_PRIMARY 642 if secondary: 643 request_filter |= dnsserver.DNS_ZONE_REQUEST_SECONDARY 644 if cache: 645 request_filter |= dnsserver.DNS_ZONE_REQUEST_CACHE 646 if auto: 647 request_filter |= dnsserver.DNS_ZONE_REQUEST_AUTO 648 if forward: 649 request_filter |= dnsserver.DNS_ZONE_REQUEST_FORWARD 650 if reverse: 651 request_filter |= dnsserver.DNS_ZONE_REQUEST_REVERSE 652 if ds: 653 request_filter |= dnsserver.DNS_ZONE_REQUEST_DS 654 if nonds: 655 request_filter |= dnsserver.DNS_ZONE_REQUEST_NON_DS 656 657 if request_filter == 0: 658 request_filter = dnsserver.DNS_ZONE_REQUEST_PRIMARY 659 660 self.lp = sambaopts.get_loadparm() 661 self.creds = credopts.get_credentials(self.lp) 662 dns_conn = dns_connect(server, self.lp, self.creds) 663 664 client_version = dns_client_version(cli_ver) 665 666 typeid, res = dns_conn.DnssrvComplexOperation2(client_version, 667 0, server, None, 668 'EnumZones', 669 dnsserver.DNSSRV_TYPEID_DWORD, 670 request_filter) 671 672 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K: 673 typeid = dnsserver.DNSSRV_TYPEID_ZONE_W2K 674 else: 675 typeid = dnsserver.DNSSRV_TYPEID_ZONE 676 print_enumzones(self.outf, typeid, res) 677 678 679class cmd_zonecreate(Command): 680 """Create a zone.""" 681 682 synopsis = '%prog <server> <zone> [options]' 683 684 takes_args = ['server', 'zone'] 685 686 takes_optiongroups = { 687 "sambaopts": options.SambaOptions, 688 "versionopts": options.VersionOptions, 689 "credopts": options.CredentialsOptions, 690 } 691 692 takes_options = [ 693 Option('--client-version', help='Client Version', 694 default='longhorn', metavar='w2k|dotnet|longhorn', 695 choices=['w2k', 'dotnet', 'longhorn'], dest='cli_ver') 696 ] 697 698 def run(self, server, zone, cli_ver, sambaopts=None, credopts=None, 699 versionopts=None): 700 701 self.lp = sambaopts.get_loadparm() 702 self.creds = credopts.get_credentials(self.lp) 703 dns_conn = dns_connect(server, self.lp, self.creds) 704 705 zone = zone.lower() 706 707 client_version = dns_client_version(cli_ver) 708 if client_version == dnsserver.DNS_CLIENT_VERSION_W2K: 709 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_W2K 710 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_W2K() 711 zone_create_info.pszZoneName = zone 712 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY 713 zone_create_info.fAging = 0 714 zone_create_info.fDsIntegrated = 1 715 zone_create_info.fLoadExisting = 1 716 elif client_version == dnsserver.DNS_CLIENT_VERSION_DOTNET: 717 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE_DOTNET 718 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_DOTNET() 719 zone_create_info.pszZoneName = zone 720 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY 721 zone_create_info.fAging = 0 722 zone_create_info.fDsIntegrated = 1 723 zone_create_info.fLoadExisting = 1 724 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT 725 else: 726 typeid = dnsserver.DNSSRV_TYPEID_ZONE_CREATE 727 zone_create_info = dnsserver.DNS_RPC_ZONE_CREATE_INFO_LONGHORN() 728 zone_create_info.pszZoneName = zone 729 zone_create_info.dwZoneType = dnsp.DNS_ZONE_TYPE_PRIMARY 730 zone_create_info.fAging = 0 731 zone_create_info.fDsIntegrated = 1 732 zone_create_info.fLoadExisting = 1 733 zone_create_info.dwDpFlags = dnsserver.DNS_DP_DOMAIN_DEFAULT 734 735 res = dns_conn.DnssrvOperation2(client_version, 0, server, None, 736 0, 'ZoneCreate', typeid, 737 zone_create_info) 738 739 typeid = dnsserver.DNSSRV_TYPEID_NAME_AND_PARAM 740 name_and_param = dnsserver.DNS_RPC_NAME_AND_PARAM() 741 name_and_param.pszNodeName = 'AllowUpdate' 742 name_and_param.dwParam = dnsp.DNS_ZONE_UPDATE_SECURE 743 744 try: 745 res = dns_conn.DnssrvOperation2(client_version, 0, server, zone, 746 0, 'ResetDwordProperty', typeid, 747 name_and_param) 748 except WERRORError as e: 749 if e.args[0] == werror.WERR_DNS_ERROR_ZONE_ALREADY_EXISTS: 750 self.outf.write('Zone already exists.') 751 raise e 752 753 self.outf.write('Zone %s created successfully\n' % zone) 754 755 756class cmd_zonedelete(Command): 757 """Delete a zone.""" 758 759 synopsis = '%prog <server> <zone> [options]' 760 761 takes_args = ['server', 'zone'] 762 763 takes_optiongroups = { 764 "sambaopts": options.SambaOptions, 765 "versionopts": options.VersionOptions, 766 "credopts": options.CredentialsOptions, 767 } 768 769 def run(self, server, zone, sambaopts=None, credopts=None, 770 versionopts=None): 771 772 self.lp = sambaopts.get_loadparm() 773 self.creds = credopts.get_credentials(self.lp) 774 dns_conn = dns_connect(server, self.lp, self.creds) 775 776 zone = zone.lower() 777 try: 778 res = dns_conn.DnssrvOperation2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, 779 0, server, zone, 0, 'DeleteZoneFromDs', 780 dnsserver.DNSSRV_TYPEID_NULL, 781 None) 782 except WERRORError as e: 783 if e.args[0] == werror.WERR_DNS_ERROR_ZONE_DOES_NOT_EXIST: 784 raise CommandError('Zone does not exist and so could not be deleted.') 785 raise e 786 787 self.outf.write('Zone %s deleted successfully\n' % zone) 788 789 790class cmd_query(Command): 791 """Query a name.""" 792 793 synopsis = '%prog <server> <zone> <name> <A|AAAA|CNAME|MX|NS|SOA|SRV|TXT|ALL> [options]' 794 795 takes_args = ['server', 'zone', 'name', 'rtype'] 796 797 takes_optiongroups = { 798 "sambaopts": options.SambaOptions, 799 "versionopts": options.VersionOptions, 800 "credopts": options.CredentialsOptions, 801 } 802 803 takes_options = [ 804 Option('--authority', help='Search authoritative records (default)', 805 action='store_true', dest='authority'), 806 Option('--cache', help='Search cached records', 807 action='store_true', dest='cache'), 808 Option('--glue', help='Search glue records', 809 action='store_true', dest='glue'), 810 Option('--root', help='Search root hints', 811 action='store_true', dest='root'), 812 Option('--additional', help='List additional records', 813 action='store_true', dest='additional'), 814 Option('--no-children', help='Do not list children', 815 action='store_true', dest='no_children'), 816 Option('--only-children', help='List only children', 817 action='store_true', dest='only_children') 818 ] 819 820 def run(self, server, zone, name, rtype, authority=False, cache=False, 821 glue=False, root=False, additional=False, no_children=False, 822 only_children=False, sambaopts=None, credopts=None, 823 versionopts=None): 824 record_type = dns_type_flag(rtype) 825 826 if name.find('*') != -1: 827 self.outf.write('use "@" to dump entire domain, looking up %s\n' % 828 name) 829 830 select_flags = 0 831 if authority: 832 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA 833 if cache: 834 select_flags |= dnsserver.DNS_RPC_VIEW_CACHE_DATA 835 if glue: 836 select_flags |= dnsserver.DNS_RPC_VIEW_GLUE_DATA 837 if root: 838 select_flags |= dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA 839 if additional: 840 select_flags |= dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA 841 if no_children: 842 select_flags |= dnsserver.DNS_RPC_VIEW_NO_CHILDREN 843 if only_children: 844 select_flags |= dnsserver.DNS_RPC_VIEW_ONLY_CHILDREN 845 846 if select_flags == 0: 847 select_flags = dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA 848 849 if select_flags == dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA: 850 self.outf.write('Specify either --authority or --root along with --additional.\n') 851 self.outf.write('Assuming --authority.\n') 852 select_flags |= dnsserver.DNS_RPC_VIEW_AUTHORITY_DATA 853 854 self.lp = sambaopts.get_loadparm() 855 self.creds = credopts.get_credentials(self.lp) 856 dns_conn = dns_connect(server, self.lp, self.creds) 857 858 try: 859 buflen, res = dns_conn.DnssrvEnumRecords2( 860 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, zone, name, 861 None, record_type, select_flags, None, None) 862 except WERRORError as e: 863 if e.args[0] == werror.WERR_DNS_ERROR_NAME_DOES_NOT_EXIST: 864 raise CommandError('Record or zone does not exist.') 865 raise e 866 867 print_dnsrecords(self.outf, res) 868 869 870class cmd_roothints(Command): 871 """Query root hints.""" 872 873 synopsis = '%prog <server> [<name>] [options]' 874 875 takes_args = ['server', 'name?'] 876 877 takes_optiongroups = { 878 "sambaopts": options.SambaOptions, 879 "versionopts": options.VersionOptions, 880 "credopts": options.CredentialsOptions, 881 } 882 883 def run(self, server, name='.', sambaopts=None, credopts=None, 884 versionopts=None): 885 record_type = dnsp.DNS_TYPE_NS 886 select_flags = (dnsserver.DNS_RPC_VIEW_ROOT_HINT_DATA | 887 dnsserver.DNS_RPC_VIEW_ADDITIONAL_DATA) 888 889 self.lp = sambaopts.get_loadparm() 890 self.creds = credopts.get_credentials(self.lp) 891 dns_conn = dns_connect(server, self.lp, self.creds) 892 893 buflen, res = dns_conn.DnssrvEnumRecords2( 894 dnsserver.DNS_CLIENT_VERSION_LONGHORN, 0, server, '..RootHints', 895 name, None, record_type, select_flags, None, None) 896 print_dnsrecords(self.outf, res) 897 898 899class cmd_add_record(Command): 900 """Add a DNS record 901 902 For each type data contents are as follows: 903 A ipv4_address_string 904 AAAA ipv6_address_string 905 PTR fqdn_string 906 CNAME fqdn_string 907 NS fqdn_string 908 MX "fqdn_string preference" 909 SRV "fqdn_string port priority weight" 910 TXT "'string1' 'string2' ..." 911 """ 912 913 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>' 914 915 takes_args = ['server', 'zone', 'name', 'rtype', 'data'] 916 917 takes_optiongroups = { 918 "sambaopts": options.SambaOptions, 919 "versionopts": options.VersionOptions, 920 "credopts": options.CredentialsOptions, 921 } 922 923 def run(self, server, zone, name, rtype, data, sambaopts=None, 924 credopts=None, versionopts=None): 925 926 if rtype.upper() not in ('A', 'AAAA', 'PTR', 'CNAME', 'NS', 'MX', 'SRV', 'TXT'): 927 raise CommandError('Adding record of type %s is not supported' % rtype) 928 929 record_type = dns_type_flag(rtype) 930 rec = data_to_dns_record(record_type, data) 931 932 self.lp = sambaopts.get_loadparm() 933 self.creds = credopts.get_credentials(self.lp) 934 dns_conn = dns_connect(server, self.lp, self.creds) 935 936 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF() 937 add_rec_buf.rec = rec 938 939 try: 940 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, 941 0, server, zone, name, add_rec_buf, None) 942 except WERRORError as e: 943 if e.args[0] == werror.WERR_DNS_ERROR_NAME_DOES_NOT_EXIST: 944 raise CommandError('Zone does not exist; record could not be added.') 945 raise e 946 947 self.outf.write('Record added successfully\n') 948 949 950class cmd_update_record(Command): 951 """Update a DNS record 952 953 For each type data contents are as follows: 954 A ipv4_address_string 955 AAAA ipv6_address_string 956 PTR fqdn_string 957 CNAME fqdn_string 958 NS fqdn_string 959 MX "fqdn_string preference" 960 SOA "fqdn_dns fqdn_email serial refresh retry expire minimumttl" 961 SRV "fqdn_string port priority weight" 962 TXT "'string1' 'string2' ..." 963 """ 964 965 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SOA|SRV|TXT> <olddata> <newdata>' 966 967 takes_args = ['server', 'zone', 'name', 'rtype', 'olddata', 'newdata'] 968 969 takes_optiongroups = { 970 "sambaopts": options.SambaOptions, 971 "versionopts": options.VersionOptions, 972 "credopts": options.CredentialsOptions, 973 } 974 975 def run(self, server, zone, name, rtype, olddata, newdata, 976 sambaopts=None, credopts=None, versionopts=None): 977 978 if rtype.upper() not in ('A', 'AAAA', 'PTR', 'CNAME', 'NS', 'MX', 'SOA', 'SRV', 'TXT'): 979 raise CommandError('Updating record of type %s is not supported' % rtype) 980 981 record_type = dns_type_flag(rtype) 982 rec = data_to_dns_record(record_type, newdata) 983 984 self.lp = sambaopts.get_loadparm() 985 self.creds = credopts.get_credentials(self.lp) 986 dns_conn = dns_connect(server, self.lp, self.creds) 987 988 rec_match = dns_record_match(dns_conn, server, zone, name, record_type, 989 olddata) 990 if not rec_match: 991 raise CommandError('Record or zone does not exist.') 992 993 # Copy properties from existing record to new record 994 rec.dwFlags = rec_match.dwFlags 995 rec.dwSerial = rec_match.dwSerial 996 rec.dwTtlSeconds = rec_match.dwTtlSeconds 997 rec.dwTimeStamp = rec_match.dwTimeStamp 998 999 add_rec_buf = dnsserver.DNS_RPC_RECORD_BUF() 1000 add_rec_buf.rec = rec 1001 1002 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF() 1003 del_rec_buf.rec = rec_match 1004 1005 try: 1006 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, 1007 0, 1008 server, 1009 zone, 1010 name, 1011 add_rec_buf, 1012 del_rec_buf) 1013 except WERRORError as e: 1014 if e.args[0] == werror.WERR_DNS_ERROR_NAME_DOES_NOT_EXIST: 1015 raise CommandError('Zone does not exist; record could not be updated.') 1016 raise e 1017 1018 self.outf.write('Record updated successfully\n') 1019 1020 1021class cmd_delete_record(Command): 1022 """Delete a DNS record 1023 1024 For each type data contents are as follows: 1025 A ipv4_address_string 1026 AAAA ipv6_address_string 1027 PTR fqdn_string 1028 CNAME fqdn_string 1029 NS fqdn_string 1030 MX "fqdn_string preference" 1031 SRV "fqdn_string port priority weight" 1032 TXT "'string1' 'string2' ..." 1033 """ 1034 1035 synopsis = '%prog <server> <zone> <name> <A|AAAA|PTR|CNAME|NS|MX|SRV|TXT> <data>' 1036 1037 takes_args = ['server', 'zone', 'name', 'rtype', 'data'] 1038 1039 takes_optiongroups = { 1040 "sambaopts": options.SambaOptions, 1041 "versionopts": options.VersionOptions, 1042 "credopts": options.CredentialsOptions, 1043 } 1044 1045 def run(self, server, zone, name, rtype, data, sambaopts=None, credopts=None, versionopts=None): 1046 1047 if rtype.upper() not in ('A', 'AAAA', 'PTR', 'CNAME', 'NS', 'MX', 'SRV', 'TXT'): 1048 raise CommandError('Deleting record of type %s is not supported' % rtype) 1049 1050 record_type = dns_type_flag(rtype) 1051 rec = data_to_dns_record(record_type, data) 1052 1053 self.lp = sambaopts.get_loadparm() 1054 self.creds = credopts.get_credentials(self.lp) 1055 dns_conn = dns_connect(server, self.lp, self.creds) 1056 1057 del_rec_buf = dnsserver.DNS_RPC_RECORD_BUF() 1058 del_rec_buf.rec = rec 1059 1060 try: 1061 dns_conn.DnssrvUpdateRecord2(dnsserver.DNS_CLIENT_VERSION_LONGHORN, 1062 0, 1063 server, 1064 zone, 1065 name, 1066 None, 1067 del_rec_buf) 1068 except WERRORError as e: 1069 if e.args[0] == werror.WERR_DNS_ERROR_NAME_DOES_NOT_EXIST: 1070 raise CommandError('Zone does not exist; record could not be deleted.') 1071 raise e 1072 1073 self.outf.write('Record deleted successfully\n') 1074 1075 1076class cmd_cleanup_record(Command): 1077 """Cleanup DNS records for a DNS host. 1078 1079 example: 1080 1081 samba-tool dns cleanup dc1 dc1.samdom.test.site -U USER%PASSWORD 1082 1083 NOTE: This command in many cases will only mark the `dNSTombstoned` attr 1084 as `TRUE` on the DNS records. Querying will no longer return results but 1085 there may still be some placeholder entries in the database. 1086 """ 1087 1088 synopsis = '%prog <server> <dnshostname>' 1089 1090 takes_args = ['server', 'dnshostname'] 1091 1092 takes_optiongroups = { 1093 "sambaopts": options.SambaOptions, 1094 "versionopts": options.VersionOptions, 1095 "credopts": options.CredentialsOptions, 1096 } 1097 1098 takes_options = [ 1099 Option("-v", "--verbose", help="Be verbose", action="store_true"), 1100 Option("-q", "--quiet", help="Be quiet", action="store_true"), 1101 ] 1102 1103 def run(self, server, dnshostname, sambaopts=None, credopts=None, 1104 versionopts=None, verbose=False, quiet=False): 1105 lp = sambaopts.get_loadparm() 1106 creds = credopts.get_credentials(lp) 1107 1108 logger = self.get_logger(verbose=verbose, quiet=quiet) 1109 1110 samdb = SamDB(url="ldap://%s" % server, 1111 session_info=system_session(), 1112 credentials=creds, lp=lp) 1113 1114 remove_dc.remove_dns_references(samdb, logger, dnshostname, 1115 ignore_no_name=True) 1116 1117 1118class cmd_dns(SuperCommand): 1119 """Domain Name Service (DNS) management.""" 1120 1121 subcommands = {} 1122 subcommands['serverinfo'] = cmd_serverinfo() 1123 subcommands['zoneinfo'] = cmd_zoneinfo() 1124 subcommands['zonelist'] = cmd_zonelist() 1125 subcommands['zonecreate'] = cmd_zonecreate() 1126 subcommands['zonedelete'] = cmd_zonedelete() 1127 subcommands['query'] = cmd_query() 1128 subcommands['roothints'] = cmd_roothints() 1129 subcommands['add'] = cmd_add_record() 1130 subcommands['update'] = cmd_update_record() 1131 subcommands['delete'] = cmd_delete_record() 1132 subcommands['cleanup'] = cmd_cleanup_record() 1133