def connectAndCollectConfig(self,deviceName,deviceIP,sshUser,sshPwd,privilegedPwd): self.incrThreadNb() try: sshPwdClear = base64.b64decode(sshPwd) privilegedPwdClear = base64.b64decode(privilegedPwd) ssh = ZEyeSSHBroker(deviceIP,sshUser,sshPwdClear) if ssh.connect() == False: self.decrThreadNb() return if ssh.setupPrivileges(privilegedPwdClear) == False: self.decrThreadNb() return startupCfg = "" runningCfg = "" #startupCfg = ssh.sendPrivilegedCmd("show startup-config") #runningCfg = ssh.sendPrivilegedCmd("show running-config") pgsqlCon = PgSQL.connect(host=zConfig.pgHost,user=zConfig.pgUser,password=zConfig.pgPwd,database=zConfig.pgDB) pgcursor = pgsqlCon.cursor() pgcursor.execute("DELETE FROM z_eye_switch_configs WHERE device = '%s'" % deviceName) if len(startupCfg) > 0: pgcursor.execute("INSERT INTO z_eye_switch_configs (device,cfgtype,cfgoutput) VALUES ('%s','1','%s')" % (deviceName,startupCfg)) if len(runningCfg) > 0: pgcursor.execute("INSERT INTO z_eye_switch_configs (device,cfgtype,cfgoutput) VALUES ('%s','2','%s')" % (deviceName,runningCfg)) pgsqlCon.commit() pgcursor.close() pgsqlCon.close() ssh.disablePrivileges() except Exception, e: self.logCritical("connectAndCollectConfig: FATAL %s" % e)
def doConfigDHCP(self,addr,user,pwd,reservpath,subnetpath): self.incrThreadNb() subnetBuf = "" reservBuf = "" try: # One pgsql connection per thread pgsqlCon = PgSQL.connect(host=zConfig.pgHost,user=zConfig.pgUser,password=zConfig.pgPwd,database=zConfig.pgDB) pgcursor = pgsqlCon.cursor() pgcursor.execute("SELECT clustername FROM z_eye_dhcp_cluster WHERE dhcpaddr = '%s'" % addr) pgres = pgcursor.fetchall() # No cluster, then no action to do if pgcursor.rowcount == 0: self.decrThreadNb() return ssh = ZEyeSSHBroker(addr,user,pwd) if ssh.connect() == False: self.decrThreadNb() return # We get the remote OS for some commands remoteOs = ssh.getRemoteOS() if remoteOs != "Linux" and remoteOs != "FreeBSD" and remoteOs != "OpenBSD": self.logError("%s OS (on %s) is not supported" % (remoteOs,addr)) self.decrThreadNb() return hashCmd = "" if remoteOs == "Linux": hashCmd = "md5sum" elif remoteOs == "FreeBSD" or remoteOs == "OpenBSD": hashCmd = "md5 -q" # We test file existence. If they doesn't exist, we create it. If creation failed, the DHCP manager cannot use this server if ssh.isRemoteExists(reservpath) == False: ssh.sendCmd("touch %s" % reservpath) if ssh.isRemoteWritable(reservpath) == False: self.logError("%s (on %s) is not writable" % (reservpath,addr)) self.decrThreadNb() return if ssh.isRemoteExists(subnetpath) == False: ssh.sendCmd("touch %s" % subnetpath) if ssh.isRemoteWritable(subnetpath) == False: self.logError("%s (on %s) is not writable" % (subnetpath,addr)) self.decrThreadNb() return if ssh.isRemoteExists("/tmp/dhcprestart") == False: ssh.sendCmd("touch %s" % "/tmp/dhcprestart") if ssh.isRemoteWritable("/tmp/dhcprestart") == False: self.logError("%s (on %s) is not writable" % ("/tmp/dhcprestart",addr)) self.decrThreadNb() return """ This variable enable failover part With ISC DHCP failover can be declared only if used """ showFailover = False for idx in pgres: if idx[0] in self.clusterList: # custom options for cOpt in self.customOptsList: # Only real custom options are declared if self.customOptsList[cOpt][2] == False: codeType = "" if self.customOptsList[cOpt][1] == "uint8": codeType = "unsigned integer 8" elif self.customOptsList[cOpt][1] == "uint16": codeType = "unsigned integer 16" elif self.customOptsList[cOpt][1] == "uint32": codeType = "unsigned integer 32" elif self.customOptsList[cOpt][1] == "int8": codeType = "integer 8" elif self.customOptsList[cOpt][1] == "int16": codeType = "integer 16" elif self.customOptsList[cOpt][1] == "uint32": codeType = "integer 32" elif self.customOptsList[cOpt][1] == "ip": codeType = "ip-address" else: codeType = self.customOptsList[cOpt][1] subnetBuf += "option %s code %s = %s;\n" % (cOpt,self.customOptsList[cOpt][0],codeType) if len(subnetBuf) > 0: subnetBuf += "\n" # Cluster options failoverPeerBuf = "" failoverPeerName = "" if idx[0] in self.clusterOptions: # ISC dhcp clusters if self.clusterOptions[idx[0]][0] == 1 or self.clusterOptions[idx[0]][0] == 2: peerAddr = "" """ cluster members has always 2 members on this configuration then, peer is the other record """ for peer in self.clusterMembers[idx[0]]: if peer != addr: if self.clusterMembers[idx[0]][peer]["clusteraddr"] != None: peerAddr = self.clusterMembers[idx[0]][peer]["clusteraddr"] localAddr = addr # If there is a valid clusterAddr, replace localAddr if addr in self.clusterMembers[idx[0]] and self.clusterMembers[idx[0]][addr]["clusteraddr"] != None: localAddr = self.clusterMembers[idx[0]][addr]["clusteraddr"] failoverPeerBuf += "failover peer \"cluster-%s\" {" % idx[0].replace(' ','-') failoverPeerName = "cluster-%s" % idx[0].replace(' ','-') # This is for cluster master if addr == self.clusterOptions[idx[0]][1]: failoverPeerBuf += "\n\tprimary;" # This is for cluster slave else: failoverPeerBuf += "\n\tsecondary;" failoverPeerBuf += "\n\taddress %s;\n\tport 647;\n\tpeer address %s;\n\tpeer port 647;" % (localAddr,peerAddr) failoverPeerBuf += "\n\tmax-response-delay 3;\n\tmax-unacked-updates 2;\n\tload balance max seconds 10;" # This is for cluster master if (self.clusterOptions[idx[0]][0] == 1 or self.clusterOptions[idx[0]][0] == 2) and self.clusterOptions[idx[0]][1] == addr: if self.clusterOptions[idx[0]][0] == 2: failoverPeerBuf += "\n\tmclt 1800;\n\tsplit 127;" else: failoverPeerBuf += "\n\tmclt 1800;\n\tsplit 255;" failoverPeerBuf += "\n}\n\n" for subnet in self.clusterList[idx[0]]: netmask = self.subnetList[subnet][0] subnetIpList = self.subnetList[subnet][1] # Special case for DNS2 dns2 = "" if len(self.subnetList[subnet][4]) > 0 and self.subnetList[subnet][4] != self.subnetList[subnet][3]: dns2 = ",%s" % self.subnetList[subnet][4] subnetBuf += "subnet %s netmask %s {\n\toption routers %s;\n\toption domain-name \"%s\";\n" % (subnet,netmask,self.subnetList[subnet][2],self.subnetList[subnet][5]) # Set options values if subnet in self.subnetOptgroupsList: for options in self.subnetOptgroupsList[subnet]: # Text values must have braces and strip ' " ' char if self.customOptsList[options[0]][1] == "text": subnetBuf += "\toption %s \"%s\";\n" % (options[0],ZEyeUtil.addslashes(options[1])) else: if options[0] == "next-server": subnetBuf += "\t%s %s;\n" % (options[0],options[1]) else: subnetBuf += "\toption %s %s;\n" % (options[0],options[1]) if self.subnetList[subnet][6] != "" and self.subnetList[subnet][6] != 0: subnetBuf += "\tdefault-lease-time %s;\n" % self.subnetList[subnet][6] if self.subnetList[subnet][7] != "" and self.subnetList[subnet][7] != 0: subnetBuf += "\tmax-lease-time %s;\n" % self.subnetList[subnet][7] subnetBuf += "\toption domain-name-servers %s%s;\n\n" % (self.subnetList[subnet][3],dns2) # Now create pool with failover peer and ranges if subnet in self.rangeList: # Show this part only if we have rangelist if len(self.rangeList[subnet]) > 0: # Start pool brace subnetBuf += "\tpool {\n" # Show failover part and enable showFailover variable showFailover = True if len(failoverPeerName) > 0: subnetBuf += "\t\tfailover peer \"%s\";\n\n" % failoverPeerName for range in self.rangeList[subnet]: subnetBuf += "\t\trange %s %s;\n" % (range[0],range[1]) subnetBuf += "\t}\n" subnetBuf += "}\n\n" for ip in subnetIpList: reservBuf += "host %s {\n\thardware ethernet %s;\n\tfixed-address %s;\n" % (self.ipList[ip][1],self.ipList[ip][0],ip) if ip in self.IPv4OptgroupsList: for options in self.IPv4OptgroupsList[ip]: # Text values must have braces and strip ' " ' char if self.customOptsList[options[0]][1] == "text": reservBuf += "\toption %s \"%s\";\n" % (options[0],ZEyeUtil.addslashes(options[1])) else: if options[0] == "next-server": reservBuf += "\t%s %s;\n" % (options[0],options[1]) else: reservBuf += "\toption %s %s;\n" % (options[0],options[1]) reservBuf += "}\n" if showFailover == True: subnetBuf = "%s%s" % (failoverPeerBuf,subnetBuf) # check md5 trace to see if subnet file is different tmpmd5 = ssh.sendCmd("cat %s|%s" % (subnetpath,hashCmd)) tmpmd5 = re.sub("\n", "", tmpmd5) tmpmd52 = hashlib.md5("%s\n" % subnetBuf).hexdigest() if tmpmd5 != tmpmd52: ssh.sendCmd("echo '%s' > %s" % (subnetBuf,subnetpath)) ssh.sendCmd("echo 1 > /tmp/dhcprestart") self.logInfo("subnets modified on %s, asking dhcpd restart" % addr) # check md5 trace to see if reserv file is different tmpmd5 = ssh.sendCmd("cat %s|%s" % (reservpath,hashCmd)) tmpmd5 = re.sub("\n", "", tmpmd5) tmpmd52 = hashlib.md5("%s\n" % reservBuf).hexdigest() if tmpmd5 != tmpmd52: ssh.sendCmd("echo '%s' > %s" % (reservBuf,reservpath)) ssh.sendCmd("echo 1 > /tmp/dhcprestart") self.logInfo("reservations modified on %s, asking dhcpd restart" % addr) ssh.close() except Exception, e: self.logCritical(e)
def doConfigDNS(self,addr,user,pwd,namedpath,chrootpath,mzonepath,szonepath,zeyenamedpath,nsfqdn,tsigtransfer,tsigupdate): self.incrThreadNb() cfgbuffer = "" try: # No zone or cluster, stop it if len(self.zoneList) == 0 or len(self.clusterList) == 0: self.decrThreadNb() return ssh = ZEyeSSHBroker(addr,user,pwd) if ssh.connect() == False: self.decrThreadNb() return # We get the remote OS for some commands remoteOs = ssh.getRemoteOS() if remoteOs != "Linux" and remoteOs != "FreeBSD" and remoteOs != "OpenBSD": self.logError("%s OS (on %s) is not supported" % (remoteOs,addr)) self.decrThreadNb() return hashCmd = "" if remoteOs == "Linux": hashCmd = "md5sum" elif remoteOs == "FreeBSD" or remoteOs == "OpenBSD": hashCmd = "md5 -q" # We test file existence. If they doesn't exist, we create it. If creation failed, the DNS manager cannot use this server if ssh.isRemoteExists(zeyenamedpath) == False: ssh.sendCmd("touch %s" % zeyenamedpath) if ssh.isRemoteWritable(zeyenamedpath) == False: self.logError("%s (on %s) is not writable, no DNS configuration will be done on this server" % (zeyenamedpath,addr)) self.decrThreadNb() return if ssh.isRemoteExists("/tmp/dnsrestart") == False: ssh.sendCmd("touch /tmp/dnsrestart") if ssh.isRemoteWritable("/tmp/dnsrestart") == False: self.logError("/tmp/dnsrestart (on %s) is not writable, no DNS configuration will be done on this server" % addr) self.decrThreadNb() return # Write options for cluster in self.clusterList: if addr in self.clusterList[cluster][0] or addr in self.clusterList[cluster][1] or addr in self.clusterList[cluster][2]: tmpcfgbuffer = "" if len(self.clusterList[cluster][3]) > 0: tmpcfgbuffer += "\tallow-recursion {\n" for acl in self.clusterList[cluster][3]: if acl == "none" or acl == "any": tmpcfgbuffer += "\t\t%s;\n" % acl else: tmpcfgbuffer += "\t\t\"%s\";\n" % acl tmpcfgbuffer += "\t};\n" if len(self.clusterList[cluster][4]) > 0: tmpcfgbuffer += "\tallow-transfer {\n" for acl in self.clusterList[cluster][4]: # Only write non if no tsig transfer key if acl == "none": if tsigtransfer == "": tmpcfgbuffer += "\t\t%s;\n" % acl elif acl == "any": tmpcfgbuffer += "\t\t%s;\n" % acl else: tmpcfgbuffer += "\t\t\"%s\";\n" % acl if tsigtransfer != "": tmpcfgbuffer += "\t\tkey \"%s\";\n" % self.tsigList[tsigtransfer][0] tmpcfgbuffer += "\t};\n" if len(self.clusterList[cluster][5]) > 0: tmpcfgbuffer += "\tallow-update {\n" for acl in self.clusterList[cluster][5]: # Only write non if no tsig update key if acl == "none": if tsigupdate == "": tmpcfgbuffer += "\t\t%s;\n" % acl elif acl == "any": tmpcfgbuffer += "\t\t%s;\n" % acl else: tmpcfgbuffer += "\t\t\"%s\";\n" % acl if tsigupdate != "": tmpcfgbuffer += "\t\tkey \"%s\";\n" % self.tsigList[tsigupdate][0] tmpcfgbuffer += "\t};\n" if len(self.clusterList[cluster][6]) > 0: tmpcfgbuffer += "\tallow-notify {\n" for acl in self.clusterList[cluster][6]: if acl == "none" or acl == "any": tmpcfgbuffer += "\t\t%s;\n" % acl else: tmpcfgbuffer += "\t\t\"%s\";\n" % acl tmpcfgbuffer += "\t};\n" if len(self.clusterList[cluster][7]) > 0: tmpcfgbuffer += "\tallow-query {\n\t\t127.0.0.1;\n\t\t::1;\n" for acl in self.clusterList[cluster][7]: # If none ACL is found, don't write it because we must allow localhost if acl == "any": tmpcfgbuffer += "\t\t%s;\n" % acl elif acl != "none": tmpcfgbuffer += "\t\t\"%s\";\n" % acl tmpcfgbuffer += "\t};\n" if self.clusterList[cluster][8] == True: tmpcfgbuffer += "\tdnssec-enable yes;\n" else: tmpcfgbuffer += "\tdnssec-enable no;\n" if self.clusterList[cluster][9] == True: tmpcfgbuffer += "\tdnssec-validation yes;\n" else: tmpcfgbuffer += "\tdnssec-validation no;\n" if len(tmpcfgbuffer) > 0: cfgbuffer += "options {\n\tversion\"\";\n\tlisten-on { any; };\n\tlisten-on-v6 { any; };\n%s};\n" % tmpcfgbuffer # Write TSIG keys for tsig in self.tsigList: algo = "" if self.tsigList[tsig][1] == 1: algo = "hmac-md5" elif self.tsigList[tsig][1] == 2: algo = "hmac-sha1" elif self.tsigList[tsig][2] == 3: algo = "hmac-sha256" if algo != "": cfgbuffer += "key \"%s\" {\n\talgorithm %s;\n\tsecret \"%s\";\n};\n" % (self.tsigList[tsig][0],algo,self.tsigList[tsig][2]) # Write ACLS for acl in self.aclList: tmpcfgbuffer = "" for ip in self.aclList[acl][0]: tmpcfgbuffer += "\t%s;\n" % ip for network in self.aclList[acl][1]: tmpcfgbuffer += "\t%s;\n" % network for childacl in self.aclList[acl][2]: tmpcfgbuffer += "\t\"%s\";\n" % childacl for tsig in self.aclList[acl][3]: tmpcfgbuffer += "\tkey \"%s\";\n" % tsig for dnsname in self.aclList[acl][4]: # We need to catch exception. If exception, name not resolvable try: dnsanswer = dns.resolver.query(dnsname,'A') for rdata in dnsanswer: tmpcfgbuffer += "\t%s;\n" % rdata.address except DNSException, e: self.logError("unable to resolve name %s" % dnsname) if len(tmpcfgbuffer) > 0: cfgbuffer += "acl \"%s\" {\n%s};\n" % (acl,tmpcfgbuffer) for zone in self.zoneList: srvType = 0 clusterCaches = False for cluster in self.zoneList[zone][1]: # This server must be in the zone clusters if addr in self.clusterList[cluster][0]: srvType = 1 elif addr in self.clusterList[cluster][1]: srvType = 2 elif addr in self.clusterList[cluster][2]: srvType = 3 if len(self.clusterList[cluster][2]) > 0: clusterCaches = True if srvType > 0: validZone = False masterList = None slaveList = None cacheList = None tmpcfgbuffer = "zone \"%s.\" {\n" % zone # Zone in classic mode if self.zoneList[zone][0] == 1: # Configuration for caches if clusterCaches: if srvType == 3: tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n" # Forwarders are master and then slaves for cluster in self.zoneList[zone][1]: for master in self.clusterList[cluster][0]: tmpcfgbuffer += "\t\t%s;\n" % master for slave in self.clusterList[cluster][1]: tmpcfgbuffer += "\t\t%s;\n" % slave validZone = True else: # Configuration for masters if srvType == 1: tmpcfgbuffer += "\ttype master;\n" if len(chrootpath) > 0: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",mzonepath),zone) else: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (mzonepath,zone) transferBuf = "" updateBuf = "" queryBuf = "" """ If there is slaves, we must allow transfer and queries If there is caches, we must allow queries We also load herited rules if herited is selected """ for cluster in self.zoneList[zone][1]: if len(self.clusterList[cluster][1]) > 0: slaveList = self.clusterList[cluster][1] if len(self.clusterList[cluster][2]) > 0: cacheList = self.clusterList[cluster][2] if "herited" in self.zoneList[zone][4]: for acl in self.clusterList[cluster][4]: if acl != "none": transferBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][6]: for acl in self.clusterList[cluster][5]: if acl != "none": updateBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][7]: for acl in self.clusterList[cluster][7]: if acl != "none": queryBuf += "\t\t\"%s\";\n" % acl if slaveList != None: for slave in slaveList: transferBuf += "\t\t%s;\n" % slave queryBuf += "\t\t%s;\n" % slave if cacheList != None: for cache in cacheList: queryBuf += "\t\t%s;\n" % cache """ We add Z-Eye TSIG key, if present """ if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList: transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0] queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0] updateBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0] """ Now we load real ACLs If any, allow all and simplify output. If none or herited, only allow cluster members (needed to have a working cluster) Else, allow cluster members + ACLS """ if "any" in self.zoneList[zone][4]: transferBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]: for acl in self.zoneList[zone][4]: transferBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][6]: updateBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][6] and "herited" not in self.zoneList[zone][6]: for acl in self.zoneList[zone][6]: updateBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][7]: queryBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]: for acl in self.zoneList[zone][7]: queryBuf += "\t\t\"%s\";\n" % acl # And we write ACLs if len(transferBuf) > 0: tmpcfgbuffer += "\tallow-transfer {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % transferBuf if len(updateBuf) > 0: tmpcfgbuffer += "\tallow-update {\n%s\t};\n" % updateBuf if len(queryBuf) > 0: tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf tmpcfgbuffer += "\tnotify yes;\n" validZone = True # Configuration for slaves elif srvType == 2: tmpcfgbuffer += "\ttype slave;\n\tmasters {\n" # Now we configure masters for cluster in self.zoneList[zone][1]: for master in self.clusterList[cluster][0]: tmpcfgbuffer += "\t\t%s;\n" % master tmpcfgbuffer += "\t};\n" if len(chrootpath) > 0: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",szonepath),zone) else: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (szonepath,zone) transferBuf = "" notifyBuf = "" queryBuf = "" """ If there is masters, we must allow transfer, queries and notify If there is caches, we must allow queries We also load herited rules if herited is selected """ for cluster in self.zoneList[zone][1]: if len(self.clusterList[cluster][0]) > 0: masterList = self.clusterList[cluster][0] if len(self.clusterList[cluster][2]) > 0: cacheList = self.clusterList[cluster][2] if "herited" in self.zoneList[zone][4]: for acl in self.clusterList[cluster][4]: if acl != "none": transferBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][5]: for acl in self.clusterList[cluster][6]: if acl != "none": notifyBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][7]: for acl in self.clusterList[cluster][7]: if acl != "none": queryBuf += "\t\t\"%s\";\n" % acl if masterList != None: for master in masterList: transferBuf += "\t\t%s;\n" % master notifyBuf += "\t\t%s;\n" % master queryBuf += "\t\t%s;\n" % master if cacheList != None: for cache in cacheList: queryBuf += "\t\t%s;\n" % cache """ We add Z-Eye TSIG key, if present """ if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList: transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]; queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]; """ Now we load real ACLs If any, allow all and simplify output. If none, only allow cluster members Else, allow cluster members + ACLS """ if "any" in self.zoneList[zone][4]: transferBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]: for acl in self.zoneList[zone][4]: transferBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][5]: notifyBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][5] and "herited" not in self.zoneList[zone][5]: for acl in self.zoneList[zone][5]: notifyBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][7]: queryBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]: for acl in self.zoneList[zone][7]: queryBuf += "\t\t\"%s\";\n" % acl # And we write ACLs if len(transferBuf) > 0: tmpcfgbuffer += "\tallow-transfer {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % transferBuf if len(notifyBuf) > 0: tmpcfgbuffer += "\tallow-notify {\n%s\t};\n" % notifyBuf if len(queryBuf) > 0: tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf validZone = True # Zone in slave mode elif self.zoneList[zone][0] == 2: # Only if there is masters if len(self.zoneList[zone][2]) > 0: # If there is caches, slave is on cache if clusterCaches: if srvType == 3: tmpcfgbuffer += "\ttype slave;\n\tmasters {\n" for fwd in self.zoneList[zone][2]: tmpcfgbuffer += "\t\t%s;\n" % fwd tmpcfgbuffer += "\t};\n" validZone = True else: tmpcfgbuffer += "\ttype slave;\n\tmasters {\n" for master in self.zoneList[zone][2]: tmpcfgbuffer += "\t\t%s;\n" % master tmpcfgbuffer += "\t};\n" if len(chrootpath) > 0: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (re.sub(ZEyeUtil.addslashes(chrootpath),"",szonepath),zone) else: tmpcfgbuffer += "\tfile \"%s/%s\";\n" % (szonepath,zone) transferBuf = "" notifyBuf = "" queryBuf = "" """ If there is masters, we must allow transfer and notify If there is caches, we must allow queries We also load herited rules if herited is selected """ for cluster in self.zoneList[zone][1]: if len(self.clusterList[cluster][2]) > 0: cacheList = self.clusterList[cluster][2] if "herited" in self.zoneList[zone][4]: for acl in self.clusterList[cluster][4]: transferBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][5]: for acl in self.clusterList[cluster][6]: notifyBuf += "\t\t\"%s\";\n" % acl if "herited" in self.zoneList[zone][7]: for acl in self.clusterList[cluster][7]: queryBuf += "\t\t\"%s\";\n" % acl for master in self.zoneList[zone][2]: notifyBuf += "\t\t%s;\n" % master transferBuf += "\t\t%s;\n" % master # If this is a cluster master of slave, we must allow cache to query if cacheList != None and srvType != 3: for cache in cacheList: queryBuf += "\t\t%s;\n" % cache """ We add Z-Eye TSIG key, if present """ if tsigtransfer != None and tsigtransfer != "" and tsigtransfer in self.tsigList: transferBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]; queryBuf += "\t\tkey %s;\n" % self.tsigList[tsigtransfer][0]; """ Now we load real ACLs If any, allow all and simplify output. If none or herited, only allow cluster members Else, allow cluster members + ACLS """ if "any" in self.zoneList[zone][4]: transferBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][4] and "herited" not in self.zoneList[zone][4]: for acl in self.zoneList[zone][4]: transferBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][5]: notifyBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][5] and "herited" not in self.zoneList[zone][5]: for acl in self.zoneList[zone][5]: notifyBuf += "\t\t\"%s\";\n" % acl if "any" in self.zoneList[zone][7]: queryBuf = "\t\tany;\n" elif "none" not in self.zoneList[zone][7] and "herited" not in self.zoneList[zone][7]: for acl in self.zoneList[zone][7]: queryBuf += "\t\t\"%s\";\n" % acl # And we write ACLs if len(transferBuf) > 0: tmpcfgbuffer += "\tallow-transfer {\n%s\t};\n" % transferBuf if len(notifyBuf) > 0: tmpcfgbuffer += "\tallow-notify {\n%s\t};\n" % notifyBuf if len(queryBuf) > 0: tmpcfgbuffer += "\tallow-query {\n%s\t\t127.0.0.1;\n\t\t::1;\n\t};\n" % queryBuf validZone = True # Zone in forward mode elif self.zoneList[zone][0] == 3: # Only if there is forwarders if len(self.zoneList[zone][3]) > 0: # If there is caches, forward is on cache if clusterCaches: if srvType == 3: tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n" for fwd in self.zoneList[zone][3]: tmpcfgbuffer += "\t\t%s;\n" % fwd tmpcfgbuffer += "\t};\n" # No ACL in a forward zone validZone = True else: tmpcfgbuffer += "\ttype forward;\n\tforwarders {\n" for fwd in self.zoneList[zone][3]: tmpcfgbuffer += "\t\t%s;\n" % fwd tmpcfgbuffer += "\t};\n" # No ACL in a forward zone validZone = True if validZone == True: cfgbuffer += "%s};\n" % tmpcfgbuffer # Classic zone if self.zoneList[zone][0] == 1 and srvType == 1: """ Verify if zone file exists on master servers. If not exists create a basic file Not needed for slaves. Zonefile is created when transfer if not exists on slave servers. """ if ssh.isRemoteExists("%s/%s/%s" % (chrootpath,mzonepath,zone)) == False: # SOA record ttlRefresh = self.zoneList[zone][8] if ttlRefresh == 0: ttlRefresh = 3600 ttlRetry = self.zoneList[zone][9] if ttlRetry == 0: ttlRetry = 180 ttlExpire = self.zoneList[zone][10] if ttlExpire == 0: ttlExpire = 864000 ttlMinimum = self.zoneList[zone][11] if ttlMinimum == 0: ttlMinimum = 3600 zonefile = "$ORIGIN .\n$TTL 86400\n%s IN SOA %s. hostmaster.%s. (\n\t\t\t1\n\t\t\t%d\n\t\t\t%d\n\t\t\t%d\n\t\t\t%d )\n" % (zone,nsfqdn,zone,ttlRefresh,ttlRetry,ttlExpire,ttlMinimum) # If caches, NS are on caches if cacheList != None: for cache in cacheList: zonefile += "\t\t\tNS\t%s.\n" % self.serverList[cache][7] else: zonefile += "\t\t\tNS\t%s.\n" % nsfqdn if slaveList != None: for slave in slaveList: zonefile += "\t\t\tNS\t%s.\n" % self.serverList[slave][7] zonefile += "\n$ORIGIN %s.\n" % zone if ssh.isRemoteWritable("%s/%s/%s" % (chrootpath,mzonepath,zone)) == False: self.logError("Unable to write zonefile on server %s. Please ensure %s/%s/%s is writable !" % (addr,chrootpath,mzonepath,zone)) else: ssh.sendCmd("echo '%s' > %s/%s/%s" % (zonefile,chrootpath,mzonepath,zone)) ssh.sendCmd("echo 1 > /tmp/dnsrestart") self.logInfo("file for zone %s created on %s" % (zone,addr)) elif self.zoneList[zone][0] == 1 and srvType == 2: """ Verify if zone file exists on slave servers. If not exists ask a service restart to load zone """ if ssh.isRemoteExists("%s/%s/%s" % (chrootpath,szonepath,zone)) == False: ssh.sendCmd("echo 1 > /tmp/dnsrestart") self.logInfo("file for zone %s inexistant on %s (slave), asking named restart" % (zone,addr)) # check md5 trace to see if subnet file is different tmpmd5 = ssh.sendCmd("cat %s|%s" % (zeyenamedpath,hashCmd)) tmpmd5 = re.sub("\n", "", tmpmd5) tmpmd52 = hashlib.md5("%s\n" % cfgbuffer).hexdigest() if tmpmd5 != tmpmd52: ssh.sendCmd("echo '%s' > %s" % (cfgbuffer,zeyenamedpath)) ssh.sendCmd("echo 1 > /tmp/dnsrestart") self.logInfo("configuration modified on %s" % addr) ssh.close()