config['debug']) { $this->log->debug(message: "__construct()"); } $this->localZoneFile = '/etc/bind/local.zones'; $this->localZonesDir = '/etc/bind/zones/'; $this->namedConfLocalFile = '/etc/bind/named.conf.local'; $this->zoneCachePath = '/var/cache/bind/'; } function createIncludeFile() { if ($this->config['debug']) { $this->log->debug(message: "createIncludeFile()"); } $domains = $this->domainRepository->findAll(); $oFile = fopen(filename: $this->localZoneFile, mode: 'w'); foreach ($domains as $domain) { if (!$this->isMasterZone(domain: $domain)) { fputs(stream: $oFile, data: 'include "' . $this->localZonesDir . $domain->getName() . '";' . PHP_EOL); } } fclose(stream: $oFile); exec(command: '/usr/sbin/named-checkconf', output: $output, result_code: $resultCode); if ($resultCode != 0) { echo 'There was an error:' . PHP_EOL; foreach ($output as $line) { echo $line . PHP_EOL; } echo 'You need to fix the error before the configuration can be activated.' . PHP_EOL; exit(1); } exec(command: '/usr/sbin/rndc reload'); } function updateSlaveZones() { if ($this->config['verbose']) { echo 'Delete all slave zones'; } $zones = glob(pattern: $this->localZonesDir . '*'); foreach ($zones as $zone) { unlink(filename: $zone); } $domains = $this->domainRepository->findAll(); foreach ($domains as $domain) { if ($this->config['verbose']) { echo 'Create zone: ' . $domain->getName() . PHP_EOL; } $this->createSlaveZoneFile(domain: $domain); } $this->createIncludeFile(); } function deleteOnNameservers(Domain $domain) { if ($this->config['debug']) { $this->log->debug(message: "deleteOnNameserver()"); } $nameservers = $this->nameserverRepository->findAll(); foreach ($nameservers as $nameserver) { $body = [ 'name' => $domain->getName() ]; if (!empty($nameserver->getAaaa())) { $this->checkController->sendCommand(requestType: 'DELETE', serverName: $nameserver->getName(), versionIP: 6, apiKey: $nameserver->getApikey(), command: 'delete', serverType: 'nameserver', body: $body); } else { $this->checkController->sendCommand(requestType: 'DELETE', serverName: $nameserver->getName(), versionIP: 4, apiKey: $nameserver->getApikey(), command: 'delete', serverType: 'nameserver', body: $body); } } } /** * @param \App\Entity\Domain $domain * * @return void */ function deleteZone(Domain $domain) { if ($this->config['debug']) { $this->log->debug(message: "deleteZone()"); } $zoneFile = $this->localZonesDir . $domain->getName(); if (file_exists(filename: "$zoneFile")) { unlink(filename: $zoneFile); } $this->createIncludeFile(); $this->deleteOnNameservers(domain: $domain); } /** * @return void */ function checkPermissions(): void { if ($this->config['debug']) { $this->log->debug(message: "checkPermissions()"); } echo 'Checking permission:' . PHP_EOL . PHP_EOL; $uid = posix_geteuid(); echo "UID:\t" . COLOR_YELLOW . $uid . PHP_EOL; $pwuid = posix_getpwuid(user_id: $uid); $name = $pwuid['name']; echo COLOR_DEFAULT . "Name:\t" . COLOR_YELLOW . $name . PHP_EOL; $bindGroup = posix_getgrnam(name: 'bind'); $members = $bindGroup['members']; if (in_array(needle: $name, haystack: $members)) { echo "\t✅ $name" . COLOR_DEFAULT . ' is in group ' . COLOR_YELLOW . 'bind' . PHP_EOL; } else { echo "\t❌$name needs to be in group " . COLOR_YELLOW . 'bind' . COLOR_DEFAULT . '!' . PHP_EOL; } echo COLOR_DEFAULT . 'Checking ' . COLOR_YELLOW . $this->localZoneFile . PHP_EOL; $localZoneFilePermissions = @fileperms(filename: $this->localZoneFile); if ($localZoneFilePermissions & 0x0010) { echo COLOR_DEFAULT . "\t✅ Group has write access." . PHP_EOL; } else { echo COLOR_RED . "\t❌Group needs write permission!" . PHP_EOL; } echo 'Checking ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL; if ($namedConfLocal = file_get_contents(filename: $this->namedConfLocalFile)) { if (!str_contains(haystack: $namedConfLocal, needle: $this->localZoneFile)) { echo "\t❌ $this->localZoneFile" . COLOR_RED . ' needs to be included in ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL; } else { echo "\t✅ $this->localZoneFile" . COLOR_DEFAULT . ' is included in ' . COLOR_YELLOW . $this->namedConfLocalFile . PHP_EOL; } } else { echo "\t❌ No access to '$this->namedConfLocalFile' . Please check permissions" . PHP_EOL; } echo COLOR_DEFAULT . 'Checking directory: ' . COLOR_YELLOW . $this->localZonesDir . PHP_EOL; $localZoneDirPermissions = @fileperms(filename: $this->localZonesDir); if ($localZoneDirPermissions & 0x0010) { echo "\t✅ Group has write access." . PHP_EOL; } else { echo "\t❌Group needs write permission!" . PHP_EOL; } } /** * @return void */ function checkDomains(): void { $localZones = file_get_contents(filename: $this->localZoneFile); $maxNameLength = $this->domainRepository->getLongestEntry(field: 'name'); $domains = $this->domainRepository->findAll(); foreach ($domains as $domain) { echo COLOR_YELLOW . str_pad(string: $domain->getName(), length: $maxNameLength + 1) . COLOR_DEFAULT; if ($this->isMasterZone(domain: $domain)) { echo 'Master Zone lies on this panel.'; } else { if (!str_contains(haystack: $localZones, needle: $domain->getName())) { echo COLOR_RED . ' is missing in ' . COLOR_YELLOW . $this->localZoneFile . COLOR_DEFAULT; } else { echo $domain->getName() . ' exists in ' . COLOR_YELLOW . $this->localZoneFile; } $zoneFile = $this->localZonesDir . $domain->getName(); if (!file_exists(filename: $zoneFile)) { echo "Missing zone file for $zoneFile . Update zone to create it"; } } echo COLOR_DEFAULT . PHP_EOL; } } /** * @param \App\Entity\Domain $domain * * @return void */ public function createSlaveZoneFile(Domain $domain): void { $domainName = $domain->getName(); if ($this->config['debug']) { $this->log->debug(message: "createZoneFile($domainName)"); } // check if we're a master zone if ($this->isMasterZone(domain: $domain)) { echo 'We are zone master for ' . $domainName . PHP_EOL; exit(1); } if ($zonefile = fopen(filename: $this->localZonesDir . $domainName, mode: 'w')) { $panelName = $domain->getPanel(); if (!$panel = $this->panelRepository->findByName(name: $panelName)) { echo "Error: Panel $panelName doesn't exist." . PHP_EOL; die(); } $a = $panel->getA(); $aaaa = $panel->getAaaa(); fputs(stream: $zonefile, data: 'zone "' . $domainName . '"' . ' IN {' . PHP_EOL); fputs(stream: $zonefile, data: "\ttype slave;" . PHP_EOL); fputs(stream: $zonefile, data: "\tfile \"" . $this->zoneCachePath . $domainName . '.db";' . PHP_EOL); fputs(stream: $zonefile, data: "\tmasters {" . PHP_EOL); if (!empty($a)) { fputs(stream: $zonefile, data: "\t\t" . $a . ';' . PHP_EOL); } if (!empty($aaaa)) { fputs(stream: $zonefile, data: "\t\t" . $aaaa . ';' . PHP_EOL); } fputs(stream: $zonefile, data: "\t};" . PHP_EOL); fputs(stream: $zonefile, data: "};" . PHP_EOL); } } public function isMasterZone(Domain $domain): bool { if (file_exists(filename: '/etc/bind/keyhelp_domains/' . $domain->getName())) { return true; } else { return false; } } }