DNS-Module erstellen: Unterschied zwischen den Versionen
Aus sourceDESK Wiki
(Die Seite wurde neu angelegt: „== Grundaufbau == ... == Methoden == ...“) |
|||
Zeile 1: | Zeile 1: | ||
+ | Entwickler können ein neues [[DNS-System]] an sourceDESK relativ leicht anbinden. Dazu muss ein DNS-Modul erstellt werden. | ||
+ | |||
== Grundaufbau == | == Grundaufbau == | ||
− | ... | + | Ein DNS-Modul bekommt ein eigenes Verzeichnis unter ''modules/dns''. In diesem Verzeichnis muss sich eine PHP-Datei mit dem gleichen Namen wie das Verzeichnis und der Endung ''.php'' befinden. In dieser PHP-Datei wird eine Klasse definiert, die von der Klasse ''DNSProvider'' erbt. |
+ | |||
+ | == Attribute == | ||
+ | Es werden mehrere Attribute innerhalb der erstellten Klasse benötigt, die höchstens ''protected'' sein dürfen: | ||
+ | |||
+ | * ''$short'' gibt den Kurznamen des Moduls an, das entspricht dem Verzeichnis- bzw. Dateinamen | ||
+ | * ''$name'' gibt einen Anzeigenamen für das Modul an | ||
+ | * ''$version'' definiert die Version des Moduls | ||
== Methoden == | == Methoden == | ||
− | ... | + | Folgende Methoden können definiert werden: |
+ | |||
+ | * ''getSettings()'' gibt die verfügbaren Modul-Einstellungen als Array zurück - auf sie kann nachher über das Objekt (stdClass) ''$this->options'' zugegriffen werden | ||
+ | * ''addZone($domain, Array $ns, $defaultIp, $defaultIp6 = null)'' soll eine neue Zone anlegen | ||
+ | * ''getZones()'' soll eine Liste der vorhandenen Zonennamen zurückliefern | ||
+ | * ''getZone($domain, $force = false)'' soll die Records einer Zone abrufen | ||
+ | * ''recordTypes($admin = false)'' soll die verfügbaren RR-Typen zurückgeben | ||
+ | * ''addRecord($domain, $record, $hidden, $admin)'' soll einen RR anlegen | ||
+ | * ''refreshZone($domain)'' soll die Zone auf allen Servern neu laden | ||
+ | * ''editRecord($domain, $record, $new, $force)'' soll einen Record ändern | ||
+ | * ''editHidden($domain, $record, $hidden)'' soll die Hidden-Eigenschaft für einen Record setzen | ||
+ | * ''removeRecord($domain, $record, $force)'' soll einen Record löschen | ||
+ | * ''removeZone($domain)'' soll eine Zone löschen | ||
+ | * ''addDynDNS($domain, $sub, $password)'' soll einen DynDNS-Record erstellen | ||
+ | * ''getDynDNS($domain)'' soll die DynDNS-Records einer Zone auflisten | ||
+ | * ''delDynDNS($domain, $sub)'' soll einen DynDNS-Record löschen | ||
+ | * ''updateDynDNS($domain, $password, $ip, $ip6)'' soll einen DynDNS-Record aktualisieren | ||
+ | * ''pushToSlave($domain)'' soll eine Zone an die Slave-Server pushen | ||
+ | |||
+ | == Beispiel-Code == | ||
+ | <source lang="php"> | ||
+ | <?php | ||
+ | |||
+ | class PowerDNS extends DNSProvider { | ||
+ | protected $short = "powerdns"; | ||
+ | protected $name = "PowerDNS (MySQL/MariaDB)"; | ||
+ | protected $version = "1.0"; | ||
+ | |||
+ | public function getSettings() { | ||
+ | return Array( | ||
+ | "db_host" => Array("type" => "text", "name" => "Datenbank-Host"), | ||
+ | "db_user" => Array("type" => "text", "name" => "Datenbank-Benutzer"), | ||
+ | "db_password" => Array("type" => "password", "name" => "Datenbank-Passwort"), | ||
+ | "db_name" => Array("type" => "text", "name" => "Datenbank"), | ||
+ | "hint" => Array("name" => "Hinweis", "help" => "Es muss die PowerDNS-Datenbankstruktur vorhanden sein. In der Tabelle records muss noch eine Spalte 'hidden' vorhanden sein (Integer, Länge: 1, Standard: 0). Außerdem noch eine weitere Spalte 'dyndns' vom Typ Varchar (Länge: 255, Standard: leer).", "type" => "hint"), | ||
+ | "ws_ipv4" => Array("type" => "text", "name" => "IPv4-Adresse des Webservers", "placeholder" => "Nur wenn URL-Weiterleitungen konfiguriert sind (siehe Wiki)"), | ||
+ | "ws_ipv6" => Array("type" => "text", "name" => "IPv6-Adresse des Webservers", "placeholder" => "Optional"), | ||
+ | ); | ||
+ | } | ||
+ | |||
+ | public function addZone($domain, Array $ns, $ip, $ip6 = null) { | ||
+ | global $CFG; | ||
+ | |||
+ | $domain = $this->idn($domain); | ||
+ | |||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if ($ip == "8.8.8.8") { | ||
+ | $ip = "5.189.157.67"; | ||
+ | } | ||
+ | |||
+ | if (!$db->query("INSERT INTO domains (`name`, `type`) VALUES ('" . $db->real_escape_string($domain) . "', 'MASTER')")) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $zoneId = $db->insert_id; | ||
+ | |||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'SOA', '" . $ns[0] . " " . str_replace("@", ".", $CFG['PAGEMAIL']) . ". " . date("Ymd") . "01 3600 900 604800 3600', 3600, 0)"); | ||
+ | |||
+ | foreach ($ns as $n) { | ||
+ | if (!empty($n)) { | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'NS', '$n', 3600, 0)"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, 'www." . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '*." . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); | ||
+ | |||
+ | if (filter_var($ip6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, 'www." . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '*." . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); | ||
+ | } | ||
+ | |||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'MX', '" . $db->real_escape_string($domain) . "', 3600, 0)"); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | public function idn($domain) { | ||
+ | $idn = new IdnaConvert; | ||
+ | return $idn->encode($domain); | ||
+ | } | ||
+ | |||
+ | private function getConnection() { | ||
+ | @$db = new MySQLi($this->options->db_host, $this->options->db_user, $this->options->db_password, $this->options->db_name); | ||
+ | return $db->connect_errno ? false : $db; | ||
+ | } | ||
+ | |||
+ | public function getZones() { | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT name, id FROM domains ORDER BY name ASC"); | ||
+ | $arr = Array(); | ||
+ | |||
+ | while ($row = $sql->fetch_object()) { | ||
+ | $arr[$this->idd($row->name)] = $db->query("SELECT COUNT(*) AS c FROM records WHERE domain_id = {$row->id}")->fetch_object()->c; | ||
+ | } | ||
+ | |||
+ | return $arr; | ||
+ | } | ||
+ | |||
+ | public function idd($domain) { | ||
+ | $idn = new IdnaConvert; | ||
+ | return $idn->decode($domain); | ||
+ | } | ||
+ | |||
+ | public function getZone($domain, $force = 0) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $typeOrder = $force ? "`type` = 'SOA' DESC, `type` = 'NS' DESC, " : ""; | ||
+ | foreach ($this->recordTypes() as $t) { | ||
+ | $typeOrder .= "`type` = '" . $t . "' DESC, "; | ||
+ | } | ||
+ | |||
+ | $typeOrder = rtrim($typeOrder, ", "); | ||
+ | $hidden = $force ? " AND hidden < 2" : " AND hidden = 0 AND dyndns = ''"; | ||
+ | |||
+ | $sql = $db->query("SELECT * FROM records WHERE domain_id = " . intval($id) . "$hidden ORDER BY $typeOrder, name ASC"); | ||
+ | $records = Array(); | ||
+ | while ($row = $sql->fetch_object()) { | ||
+ | if (in_array($row->type, $this->recordTypes()) || $force) { | ||
+ | $records[$row->id] = Array($this->trimDomain($row->name, $domain), $row->type, $this->idd($row->content), $row->ttl, $row->prio, $row->hidden, $row->dyndns); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT * FROM redirects WHERE hostname LIKE '%" . $db->real_escape_string($domain) . "' ORDER BY hostname ASC"); | ||
+ | while ($row = $sql->fetch_object()) { | ||
+ | $sql2 = $db->query("SELECT * FROM records WHERE domain_id = " . intval($id) . " AND hidden = 2 AND name LIKE '" . $db->real_escape_string($row->hostname) . "' LIMIT 1"); | ||
+ | if ($sql2->num_rows != 1) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | $i = $sql2->fetch_object(); | ||
+ | |||
+ | $records[$i->id] = Array($this->trimDomain($row->hostname, $domain), $row->type == "REDIRECT" ? "URL" : "IFRAME", $row->target, $i->ttl, $i->prio, 0, 0); | ||
+ | } | ||
+ | |||
+ | return $records; | ||
+ | } | ||
+ | |||
+ | public function recordTypes($admin = false) { | ||
+ | if (!$admin) { | ||
+ | $a = Array("MX", "A", "AAAA", "CNAME", "URL", "IFRAME", "SPF", "SRV", "TXT", "AFSDB", "CERT", "DHCID", "DLV", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "IPSECKEY", "KEY", "KX", "LOC", "MINFO", "MR", "NAPTR", "NSEC", "NSEC3", "NSEC3PARAM", "OPT", "PTR", "RKEY", "RP", "RRSIG", "SSHFP", "TLSA", "TSIG", "WKS"); | ||
+ | } | ||
+ | |||
+ | $a = Array("SOA", "NS", "MX", "A", "AAAA", "CNAME", "URL", "IFRAME", "SPF", "SRV", "TXT", "AFSDB", "CERT", "DHCID", "DLV", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "IPSECKEY", "KEY", "KX", "LOC", "MINFO", "MR", "NAPTR", "NSEC", "NSEC3", "NSEC3PARAM", "OPT", "PTR", "RKEY", "RP", "RRSIG", "SSHFP", "TLSA", "TSIG", "WKS"); | ||
+ | |||
+ | if (empty($this->options->ws_ipv4) || !filter_var($this->options->ws_ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { | ||
+ | unset($a[array_search("URL", $a)]); | ||
+ | unset($a[array_search("IFRAME", $a)]); | ||
+ | } | ||
+ | |||
+ | return $a; | ||
+ | } | ||
+ | |||
+ | private function trimDomain($text, $domain, $r = true) { | ||
+ | if (substr($text, strlen("." . $domain) / -1) == "." . $domain) { | ||
+ | return substr($text, 0, strlen("." . $domain) / -1); | ||
+ | } | ||
+ | |||
+ | if (substr($text, strlen($domain) / -1) == $domain) { | ||
+ | return substr($text, 0, strlen($domain) / -1); | ||
+ | } | ||
+ | |||
+ | if (!$r) { | ||
+ | return $text; | ||
+ | } | ||
+ | |||
+ | return $this->trimDomain($text, $this->idn($domain), false); | ||
+ | } | ||
+ | |||
+ | public function addRecord($domain, $record, $hidden = 0, $admin = true) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $record = $this->sanitizeRecord($domain, $record, $admin); | ||
+ | if (!$record) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $name = $db->real_escape_string($record[0]); | ||
+ | $type = $db->real_escape_string($record[1]); | ||
+ | $content = $db->real_escape_string($this->idn($record[2])); | ||
+ | $ttl = $db->real_escape_string($record[3]); | ||
+ | $prio = $db->real_escape_string($record[4]); | ||
+ | |||
+ | if ($type == "URL" || $type == "IFRAME") { | ||
+ | $type = "A"; | ||
+ | $hidden = 2; | ||
+ | $content = $this->options->ws_ipv4; | ||
+ | |||
+ | if (!empty($this->options->ws_ipv6) && filter_var($this->options->ws_ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | ||
+ | $this->addRecord($domain, Array($record[0], "AAAA", $this->options->ws_ipv6, $record[3], $record[4]), 2); | ||
+ | } | ||
+ | |||
+ | $db->query("INSERT INTO redirects (hostname, type, target) VALUES ('" . $db->real_escape_string($record[0]) . "', '" . ($record[1] == "URL" ? "REDIRECT" : "FRAME") . "', '" . $db->real_escape_string($record[2]) . "')"); | ||
+ | } | ||
+ | |||
+ | if ($db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `hidden`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", $hidden)")) { | ||
+ | $record[0] = $this->trimDomain($record[0], $domain); | ||
+ | $this->refreshZone($domain); | ||
+ | return $record; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | private function sanitizeRecord($domain, $record, $admin = false) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $record[0] = $this->trimDomain($record[0], $domain); | ||
+ | |||
+ | if (!ctype_alnum(str_replace(Array(".", "-", "_", '@', '*'), "", $record[0]) . "a")) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if ($record[0] == "@") { | ||
+ | $record[0] = ""; | ||
+ | } | ||
+ | |||
+ | if (!empty($record[0])) { | ||
+ | $record[0] .= "."; | ||
+ | } | ||
+ | |||
+ | $record[0] .= $domain; | ||
+ | |||
+ | if (!in_array($record[1], $this->recordTypes(), $admin)) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if ($record[1] == "A" && !filter_var($record[2], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if ($record[1] == "AAAA" && !filter_var($record[2], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if (!is_numeric($record[3]) || $record[3] < 180) { | ||
+ | $record[3] = 3600; | ||
+ | } | ||
+ | |||
+ | if (!is_numeric($record[4]) || $record[4] < 0) { | ||
+ | $record[4] = 0; | ||
+ | } | ||
+ | |||
+ | return $record; | ||
+ | } | ||
+ | |||
+ | private function refreshZone($domain) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT * FROM records WHERE name = '" . $db->real_escape_string($domain) . "' AND type = 'SOA'"); | ||
+ | while ($row = $sql->fetch_object()) { | ||
+ | $ex = explode(" ", $row->content); | ||
+ | $old = $ex[2]; | ||
+ | $soa = date("Ymd") . "01"; | ||
+ | while ($old >= $soa) { | ||
+ | $soa++; | ||
+ | } | ||
+ | |||
+ | $ex[2] = $soa; | ||
+ | $db->query("UPDATE records SET content = '" . $db->real_escape_string(implode(" ", $ex)) . "' WHERE id = {$row->id}"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public function editRecord($domain, $record, $new, $force = 0) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $new = $this->sanitizeRecord($domain, $new); | ||
+ | if (!$new) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $name = $db->real_escape_string($new[0]); | ||
+ | $type = $db->real_escape_string($new[1]); | ||
+ | $content = $db->real_escape_string($this->idn($new[2])); | ||
+ | $ttl = $db->real_escape_string($new[3]); | ||
+ | $prio = $db->real_escape_string($new[4]); | ||
+ | $hidden = $force ? "" : " AND hidden != -1 AND dyndns = ''"; | ||
+ | |||
+ | $sql = $db->query("SELECT * FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id)); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $info = $sql->fetch_object(); | ||
+ | |||
+ | if ($type == "URL" || $type == "IFRAME") { | ||
+ | if ($info->hidden == 2) { | ||
+ | $db->query("UPDATE redirects SET type = '" . ($type == "URL" ? "REDIRECT" : "FRAME") . "', target = '" . $db->real_escape_string($content) . "' WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); | ||
+ | } else { | ||
+ | $content = $db->real_escape_string($this->options->ws_ipv4); | ||
+ | $db->query("UPDATE records SET `name` = '$name', `type` = 'A', `content` = '$content', `ttl` = $ttl, `prio` = $prio, `hidden` = 2 WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1"); | ||
+ | |||
+ | if (!empty($this->options->ws_ipv6) && filter_var($this->options->ws_ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | ||
+ | $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`, `hidden`) VALUES (" . intval($id) . ", '$name', 'AAAA', '" . $db->real_escape_string($this->options->ws_ipv6) . "', $ttl, $prio, 2)"); | ||
+ | } | ||
+ | |||
+ | $db->query("INSERT INTO redirects (hostname, type, target) VALUES ('" . $db->real_escape_string($name) . "', '" . ($type == "URL" ? "REDIRECT" : "FRAME") . "', '" . $db->real_escape_string($new[2]) . "')"); | ||
+ | } | ||
+ | |||
+ | return true; | ||
+ | } else if ($info->hidden == 2) { | ||
+ | $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); | ||
+ | |||
+ | $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'AAAA' AND content = '" . $db->real_escape_string($this->options->ws_ipv6) . "' AND id != " . intval($record)); | ||
+ | $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'A' AND content = '" . $db->real_escape_string($this->options->ws_ipv4) . "' AND id != " . intval($record)); | ||
+ | |||
+ | $db->query("UPDATE records SET `hidden` = 0 WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1"); | ||
+ | } | ||
+ | |||
+ | $this->refreshZone($domain); | ||
+ | if ($db->query("UPDATE records SET `name` = '$name', `type` = '$type', `content` = '$content', `ttl` = $ttl, `prio` = $prio WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1")) { | ||
+ | return $new; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public function editHidden($domain, $record, $hidden = 0) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | if ($db->query("UPDATE records SET `hidden` = " . ($hidden ? "1" : "0") . " WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . " LIMIT 1")) { | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public function removeRecord($domain, $record, $force = 0) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | $hidden = $force ? "" : " AND hidden != -1 AND dyndns = ''"; | ||
+ | |||
+ | $sql = $db->query("SELECT * FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id)); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $info = $sql->fetch_object(); | ||
+ | |||
+ | if ($info->type == "A" && $info->content == $this->options->ws_ipv4) { | ||
+ | $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'AAAA' AND content = '" . $db->real_escape_string($this->options->ws_ipv6) . "'"); | ||
+ | $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); | ||
+ | } else if ($info->type == "AAAA" && $info->content == $this->options->ws_ipv6) { | ||
+ | $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'A' AND content = '" . $db->real_escape_string($this->options->ws_ipv4) . "'"); | ||
+ | $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); | ||
+ | } | ||
+ | |||
+ | $this->refreshZone($domain); | ||
+ | if ($db->query("DELETE FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1")) { | ||
+ | return true; | ||
+ | } | ||
+ | |||
+ | return false; | ||
+ | } | ||
+ | |||
+ | public function removeZone($domain) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | return $db->query("DELETE FROM records WHERE domain_id = " . intval($id)) && $db->query("DELETE FROM domains WHERE id = " . intval($id)); | ||
+ | } | ||
+ | |||
+ | public function addDynDNS($domain, $sub, $password) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $name = $db->real_escape_string($sub) . "." . $db->real_escape_string($domain); | ||
+ | $type = "A"; | ||
+ | $content = "127.0.0.1"; | ||
+ | $ttl = "180"; | ||
+ | $prio = "0"; | ||
+ | $password = $db->real_escape_string($password); | ||
+ | |||
+ | if ($db->query("SELECT 1 FROM `records` WHERE `name` = '$name' AND `dyndns` != ''")->num_rows > 0) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `dyndns`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", '$password')"); | ||
+ | |||
+ | $type = "AAAA"; | ||
+ | $content = "::1"; | ||
+ | |||
+ | $db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `dyndns`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", '$password')"); | ||
+ | |||
+ | return true; | ||
+ | } | ||
+ | |||
+ | public function getDynDNS($domain) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $a = Array(); | ||
+ | $sql = $db->query("SELECT * FROM `records` WHERE `type` = 'A' AND `domain_id` = $id AND `dyndns` != ''"); | ||
+ | while ($row = $sql->fetch_object()) { | ||
+ | array_push($a, Array($this->trimDomain($row->name, $domain), $row->content, $db->query("SELECT * FROM `records` WHERE `type` = 'AAAA' AND `domain_id` = $id AND `dyndns` != ''")->fetch_object()->content, $row->dyndns)); | ||
+ | } | ||
+ | |||
+ | return $a; | ||
+ | } | ||
+ | |||
+ | public function delDynDNS($domain, $sub) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); | ||
+ | if ($sql->num_rows != 1) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $id = $sql->fetch_object()->id; | ||
+ | |||
+ | $name = $db->real_escape_string($sub) . "." . $db->real_escape_string($domain); | ||
+ | $db->query("DELETE FROM `records` WHERE `domain_id` = $id AND (`type` = 'A' OR `type` = 'AAAA') AND `dyndns` != '' AND `name` = '$name'"); | ||
+ | } | ||
+ | |||
+ | public function updateDynDNS($domain, $password, $ip, $ip6) { | ||
+ | $domain = $this->idn($domain); | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { | ||
+ | $db->query("UPDATE `records` SET `content` = '" . $db->real_escape_string($ip) . "' WHERE `dyndns` = '" . $db->real_escape_string($password) . "' AND name = '" . $db->real_escape_string($domain) . "' AND `type` = 'A'"); | ||
+ | } | ||
+ | |||
+ | if (!empty($ip6) && filter_var($ip6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { | ||
+ | $db->query("UPDATE `records` SET `content` = '" . $db->real_escape_string($ip6) . "' WHERE `dyndns` = '" . $db->real_escape_string($password) . "' AND name = '" . $db->real_escape_string($domain) . "' AND `type` = 'AAAA'"); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | public function pushToSlave($domain) { | ||
+ | $db = $this->getConnection(); | ||
+ | if (!$db) { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | $db->query("UPDATE domains SET notified_serial = 0 WHERE name = '" . $db->real_escape_string($domain) . "' LIMIT 1"); | ||
+ | return (bool) $db->affected_rows; | ||
+ | } | ||
+ | } | ||
+ | </source> |
Aktuelle Version vom 10. Oktober 2018, 08:48 Uhr
Entwickler können ein neues DNS-System an sourceDESK relativ leicht anbinden. Dazu muss ein DNS-Modul erstellt werden.
Inhaltsverzeichnis
Grundaufbau
Ein DNS-Modul bekommt ein eigenes Verzeichnis unter modules/dns. In diesem Verzeichnis muss sich eine PHP-Datei mit dem gleichen Namen wie das Verzeichnis und der Endung .php befinden. In dieser PHP-Datei wird eine Klasse definiert, die von der Klasse DNSProvider erbt.
Attribute
Es werden mehrere Attribute innerhalb der erstellten Klasse benötigt, die höchstens protected sein dürfen:
- $short gibt den Kurznamen des Moduls an, das entspricht dem Verzeichnis- bzw. Dateinamen
- $name gibt einen Anzeigenamen für das Modul an
- $version definiert die Version des Moduls
Methoden
Folgende Methoden können definiert werden:
- getSettings() gibt die verfügbaren Modul-Einstellungen als Array zurück - auf sie kann nachher über das Objekt (stdClass) $this->options zugegriffen werden
- addZone($domain, Array $ns, $defaultIp, $defaultIp6 = null) soll eine neue Zone anlegen
- getZones() soll eine Liste der vorhandenen Zonennamen zurückliefern
- getZone($domain, $force = false) soll die Records einer Zone abrufen
- recordTypes($admin = false) soll die verfügbaren RR-Typen zurückgeben
- addRecord($domain, $record, $hidden, $admin) soll einen RR anlegen
- refreshZone($domain) soll die Zone auf allen Servern neu laden
- editRecord($domain, $record, $new, $force) soll einen Record ändern
- editHidden($domain, $record, $hidden) soll die Hidden-Eigenschaft für einen Record setzen
- removeRecord($domain, $record, $force) soll einen Record löschen
- removeZone($domain) soll eine Zone löschen
- addDynDNS($domain, $sub, $password) soll einen DynDNS-Record erstellen
- getDynDNS($domain) soll die DynDNS-Records einer Zone auflisten
- delDynDNS($domain, $sub) soll einen DynDNS-Record löschen
- updateDynDNS($domain, $password, $ip, $ip6) soll einen DynDNS-Record aktualisieren
- pushToSlave($domain) soll eine Zone an die Slave-Server pushen
Beispiel-Code
<?php class PowerDNS extends DNSProvider { protected $short = "powerdns"; protected $name = "PowerDNS (MySQL/MariaDB)"; protected $version = "1.0"; public function getSettings() { return Array( "db_host" => Array("type" => "text", "name" => "Datenbank-Host"), "db_user" => Array("type" => "text", "name" => "Datenbank-Benutzer"), "db_password" => Array("type" => "password", "name" => "Datenbank-Passwort"), "db_name" => Array("type" => "text", "name" => "Datenbank"), "hint" => Array("name" => "Hinweis", "help" => "Es muss die PowerDNS-Datenbankstruktur vorhanden sein. In der Tabelle records muss noch eine Spalte 'hidden' vorhanden sein (Integer, Länge: 1, Standard: 0). Außerdem noch eine weitere Spalte 'dyndns' vom Typ Varchar (Länge: 255, Standard: leer).", "type" => "hint"), "ws_ipv4" => Array("type" => "text", "name" => "IPv4-Adresse des Webservers", "placeholder" => "Nur wenn URL-Weiterleitungen konfiguriert sind (siehe Wiki)"), "ws_ipv6" => Array("type" => "text", "name" => "IPv6-Adresse des Webservers", "placeholder" => "Optional"), ); } public function addZone($domain, Array $ns, $ip, $ip6 = null) { global $CFG; $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } if ($ip == "8.8.8.8") { $ip = "5.189.157.67"; } if (!$db->query("INSERT INTO domains (`name`, `type`) VALUES ('" . $db->real_escape_string($domain) . "', 'MASTER')")) { return false; } $zoneId = $db->insert_id; $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'SOA', '" . $ns[0] . " " . str_replace("@", ".", $CFG['PAGEMAIL']) . ". " . date("Ymd") . "01 3600 900 604800 3600', 3600, 0)"); foreach ($ns as $n) { if (!empty($n)) { $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'NS', '$n', 3600, 0)"); } } $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, 'www." . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '*." . $db->real_escape_string($domain) . "', 'A', '" . $db->real_escape_string($ip) . "', 3600, 0)"); if (filter_var($ip6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, 'www." . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '*." . $db->real_escape_string($domain) . "', 'AAAA', '" . $db->real_escape_string($ip6) . "', 3600, 0)"); } $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`) VALUES ($zoneId, '" . $db->real_escape_string($domain) . "', 'MX', '" . $db->real_escape_string($domain) . "', 3600, 0)"); return true; } public function idn($domain) { $idn = new IdnaConvert; return $idn->encode($domain); } private function getConnection() { @$db = new MySQLi($this->options->db_host, $this->options->db_user, $this->options->db_password, $this->options->db_name); return $db->connect_errno ? false : $db; } public function getZones() { $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT name, id FROM domains ORDER BY name ASC"); $arr = Array(); while ($row = $sql->fetch_object()) { $arr[$this->idd($row->name)] = $db->query("SELECT COUNT(*) AS c FROM records WHERE domain_id = {$row->id}")->fetch_object()->c; } return $arr; } public function idd($domain) { $idn = new IdnaConvert; return $idn->decode($domain); } public function getZone($domain, $force = 0) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $typeOrder = $force ? "`type` = 'SOA' DESC, `type` = 'NS' DESC, " : ""; foreach ($this->recordTypes() as $t) { $typeOrder .= "`type` = '" . $t . "' DESC, "; } $typeOrder = rtrim($typeOrder, ", "); $hidden = $force ? " AND hidden < 2" : " AND hidden = 0 AND dyndns = ''"; $sql = $db->query("SELECT * FROM records WHERE domain_id = " . intval($id) . "$hidden ORDER BY $typeOrder, name ASC"); $records = Array(); while ($row = $sql->fetch_object()) { if (in_array($row->type, $this->recordTypes()) || $force) { $records[$row->id] = Array($this->trimDomain($row->name, $domain), $row->type, $this->idd($row->content), $row->ttl, $row->prio, $row->hidden, $row->dyndns); } } $sql = $db->query("SELECT * FROM redirects WHERE hostname LIKE '%" . $db->real_escape_string($domain) . "' ORDER BY hostname ASC"); while ($row = $sql->fetch_object()) { $sql2 = $db->query("SELECT * FROM records WHERE domain_id = " . intval($id) . " AND hidden = 2 AND name LIKE '" . $db->real_escape_string($row->hostname) . "' LIMIT 1"); if ($sql2->num_rows != 1) { continue; } $i = $sql2->fetch_object(); $records[$i->id] = Array($this->trimDomain($row->hostname, $domain), $row->type == "REDIRECT" ? "URL" : "IFRAME", $row->target, $i->ttl, $i->prio, 0, 0); } return $records; } public function recordTypes($admin = false) { if (!$admin) { $a = Array("MX", "A", "AAAA", "CNAME", "URL", "IFRAME", "SPF", "SRV", "TXT", "AFSDB", "CERT", "DHCID", "DLV", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "IPSECKEY", "KEY", "KX", "LOC", "MINFO", "MR", "NAPTR", "NSEC", "NSEC3", "NSEC3PARAM", "OPT", "PTR", "RKEY", "RP", "RRSIG", "SSHFP", "TLSA", "TSIG", "WKS"); } $a = Array("SOA", "NS", "MX", "A", "AAAA", "CNAME", "URL", "IFRAME", "SPF", "SRV", "TXT", "AFSDB", "CERT", "DHCID", "DLV", "DNSKEY", "DS", "EUI48", "EUI64", "HINFO", "IPSECKEY", "KEY", "KX", "LOC", "MINFO", "MR", "NAPTR", "NSEC", "NSEC3", "NSEC3PARAM", "OPT", "PTR", "RKEY", "RP", "RRSIG", "SSHFP", "TLSA", "TSIG", "WKS"); if (empty($this->options->ws_ipv4) || !filter_var($this->options->ws_ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { unset($a[array_search("URL", $a)]); unset($a[array_search("IFRAME", $a)]); } return $a; } private function trimDomain($text, $domain, $r = true) { if (substr($text, strlen("." . $domain) / -1) == "." . $domain) { return substr($text, 0, strlen("." . $domain) / -1); } if (substr($text, strlen($domain) / -1) == $domain) { return substr($text, 0, strlen($domain) / -1); } if (!$r) { return $text; } return $this->trimDomain($text, $this->idn($domain), false); } public function addRecord($domain, $record, $hidden = 0, $admin = true) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $record = $this->sanitizeRecord($domain, $record, $admin); if (!$record) { return false; } $name = $db->real_escape_string($record[0]); $type = $db->real_escape_string($record[1]); $content = $db->real_escape_string($this->idn($record[2])); $ttl = $db->real_escape_string($record[3]); $prio = $db->real_escape_string($record[4]); if ($type == "URL" || $type == "IFRAME") { $type = "A"; $hidden = 2; $content = $this->options->ws_ipv4; if (!empty($this->options->ws_ipv6) && filter_var($this->options->ws_ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $this->addRecord($domain, Array($record[0], "AAAA", $this->options->ws_ipv6, $record[3], $record[4]), 2); } $db->query("INSERT INTO redirects (hostname, type, target) VALUES ('" . $db->real_escape_string($record[0]) . "', '" . ($record[1] == "URL" ? "REDIRECT" : "FRAME") . "', '" . $db->real_escape_string($record[2]) . "')"); } if ($db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `hidden`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", $hidden)")) { $record[0] = $this->trimDomain($record[0], $domain); $this->refreshZone($domain); return $record; } return false; } private function sanitizeRecord($domain, $record, $admin = false) { $domain = $this->idn($domain); $record[0] = $this->trimDomain($record[0], $domain); if (!ctype_alnum(str_replace(Array(".", "-", "_", '@', '*'), "", $record[0]) . "a")) { return false; } if ($record[0] == "@") { $record[0] = ""; } if (!empty($record[0])) { $record[0] .= "."; } $record[0] .= $domain; if (!in_array($record[1], $this->recordTypes(), $admin)) { return false; } if ($record[1] == "A" && !filter_var($record[2], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { return false; } if ($record[1] == "AAAA" && !filter_var($record[2], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { return false; } if (!is_numeric($record[3]) || $record[3] < 180) { $record[3] = 3600; } if (!is_numeric($record[4]) || $record[4] < 0) { $record[4] = 0; } return $record; } private function refreshZone($domain) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT * FROM records WHERE name = '" . $db->real_escape_string($domain) . "' AND type = 'SOA'"); while ($row = $sql->fetch_object()) { $ex = explode(" ", $row->content); $old = $ex[2]; $soa = date("Ymd") . "01"; while ($old >= $soa) { $soa++; } $ex[2] = $soa; $db->query("UPDATE records SET content = '" . $db->real_escape_string(implode(" ", $ex)) . "' WHERE id = {$row->id}"); } } public function editRecord($domain, $record, $new, $force = 0) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $new = $this->sanitizeRecord($domain, $new); if (!$new) { return false; } $name = $db->real_escape_string($new[0]); $type = $db->real_escape_string($new[1]); $content = $db->real_escape_string($this->idn($new[2])); $ttl = $db->real_escape_string($new[3]); $prio = $db->real_escape_string($new[4]); $hidden = $force ? "" : " AND hidden != -1 AND dyndns = ''"; $sql = $db->query("SELECT * FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id)); if ($sql->num_rows != 1) { return false; } $info = $sql->fetch_object(); if ($type == "URL" || $type == "IFRAME") { if ($info->hidden == 2) { $db->query("UPDATE redirects SET type = '" . ($type == "URL" ? "REDIRECT" : "FRAME") . "', target = '" . $db->real_escape_string($content) . "' WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); } else { $content = $db->real_escape_string($this->options->ws_ipv4); $db->query("UPDATE records SET `name` = '$name', `type` = 'A', `content` = '$content', `ttl` = $ttl, `prio` = $prio, `hidden` = 2 WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1"); if (!empty($this->options->ws_ipv6) && filter_var($this->options->ws_ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $db->query("INSERT INTO records (`domain_id`, `name`, `type`, `content`, `ttl`, `prio`, `hidden`) VALUES (" . intval($id) . ", '$name', 'AAAA', '" . $db->real_escape_string($this->options->ws_ipv6) . "', $ttl, $prio, 2)"); } $db->query("INSERT INTO redirects (hostname, type, target) VALUES ('" . $db->real_escape_string($name) . "', '" . ($type == "URL" ? "REDIRECT" : "FRAME") . "', '" . $db->real_escape_string($new[2]) . "')"); } return true; } else if ($info->hidden == 2) { $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'AAAA' AND content = '" . $db->real_escape_string($this->options->ws_ipv6) . "' AND id != " . intval($record)); $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'A' AND content = '" . $db->real_escape_string($this->options->ws_ipv4) . "' AND id != " . intval($record)); $db->query("UPDATE records SET `hidden` = 0 WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1"); } $this->refreshZone($domain); if ($db->query("UPDATE records SET `name` = '$name', `type` = '$type', `content` = '$content', `ttl` = $ttl, `prio` = $prio WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1")) { return $new; } return false; } public function editHidden($domain, $record, $hidden = 0) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; if ($db->query("UPDATE records SET `hidden` = " . ($hidden ? "1" : "0") . " WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . " LIMIT 1")) { return true; } return false; } public function removeRecord($domain, $record, $force = 0) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $hidden = $force ? "" : " AND hidden != -1 AND dyndns = ''"; $sql = $db->query("SELECT * FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id)); if ($sql->num_rows != 1) { return false; } $info = $sql->fetch_object(); if ($info->type == "A" && $info->content == $this->options->ws_ipv4) { $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'AAAA' AND content = '" . $db->real_escape_string($this->options->ws_ipv6) . "'"); $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); } else if ($info->type == "AAAA" && $info->content == $this->options->ws_ipv6) { $db->query("DELETE FROM records WHERE name LIKE '" . $db->real_escape_string($info->name) . "' AND type = 'A' AND content = '" . $db->real_escape_string($this->options->ws_ipv4) . "'"); $db->query("DELETE FROM redirects WHERE hostname LIKE '" . $db->real_escape_string($info->name) . "'"); } $this->refreshZone($domain); if ($db->query("DELETE FROM records WHERE id = " . intval($record) . " AND domain_id = " . intval($id) . "$hidden LIMIT 1")) { return true; } return false; } public function removeZone($domain) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; return $db->query("DELETE FROM records WHERE domain_id = " . intval($id)) && $db->query("DELETE FROM domains WHERE id = " . intval($id)); } public function addDynDNS($domain, $sub, $password) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $name = $db->real_escape_string($sub) . "." . $db->real_escape_string($domain); $type = "A"; $content = "127.0.0.1"; $ttl = "180"; $prio = "0"; $password = $db->real_escape_string($password); if ($db->query("SELECT 1 FROM `records` WHERE `name` = '$name' AND `dyndns` != ''")->num_rows > 0) { return false; } $db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `dyndns`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", '$password')"); $type = "AAAA"; $content = "::1"; $db->query("INSERT INTO `records` (`name`, `type`, `content`, `ttl`, `prio`, `domain_id`, `dyndns`) VALUES ('$name', '$type', '$content', $ttl, $prio, " . intval($id) . ", '$password')"); return true; } public function getDynDNS($domain) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $a = Array(); $sql = $db->query("SELECT * FROM `records` WHERE `type` = 'A' AND `domain_id` = $id AND `dyndns` != ''"); while ($row = $sql->fetch_object()) { array_push($a, Array($this->trimDomain($row->name, $domain), $row->content, $db->query("SELECT * FROM `records` WHERE `type` = 'AAAA' AND `domain_id` = $id AND `dyndns` != ''")->fetch_object()->content, $row->dyndns)); } return $a; } public function delDynDNS($domain, $sub) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } $sql = $db->query("SELECT id FROM domains WHERE name = '" . $db->real_escape_string($domain) . "'"); if ($sql->num_rows != 1) { return false; } $id = $sql->fetch_object()->id; $name = $db->real_escape_string($sub) . "." . $db->real_escape_string($domain); $db->query("DELETE FROM `records` WHERE `domain_id` = $id AND (`type` = 'A' OR `type` = 'AAAA') AND `dyndns` != '' AND `name` = '$name'"); } public function updateDynDNS($domain, $password, $ip, $ip6) { $domain = $this->idn($domain); $db = $this->getConnection(); if (!$db) { return false; } if (!empty($ip) && filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { $db->query("UPDATE `records` SET `content` = '" . $db->real_escape_string($ip) . "' WHERE `dyndns` = '" . $db->real_escape_string($password) . "' AND name = '" . $db->real_escape_string($domain) . "' AND `type` = 'A'"); } if (!empty($ip6) && filter_var($ip6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { $db->query("UPDATE `records` SET `content` = '" . $db->real_escape_string($ip6) . "' WHERE `dyndns` = '" . $db->real_escape_string($password) . "' AND name = '" . $db->real_escape_string($domain) . "' AND `type` = 'AAAA'"); } } public function pushToSlave($domain) { $db = $this->getConnection(); if (!$db) { return false; } $db->query("UPDATE domains SET notified_serial = 0 WHERE name = '" . $db->real_escape_string($domain) . "' LIMIT 1"); return (bool) $db->affected_rows; } }