diff --git a/.htaccess b/.htaccess index 8267f69..60cbedb 100644 --- a/.htaccess +++ b/.htaccess @@ -1,18 +1,37 @@ -RewriteEngine on +RewriteEngine on -RewriteCond %{REQUEST_FILENAME} (/(?:add|delete|update|ip))\.(xml|html|gif|txt|csv|json) [OR] -RewriteCond %{REQUEST_FILENAME} (/admin/(?:cleanup|sync|parse))\.(xml|html|gif|txt|csv|json) [OR] -RewriteCond %{REQUEST_FILENAME} (/admin/get)\.(xml|html|gif|txt|csv|png|json) [OR] -RewriteCond %{REQUEST_FILENAME} (/admin/stats/types)\.(xml|html|gif|txt|csv|png|json) -RewriteRule .* %1.php?format=%2 [QSA] +# Frontend +RewriteCond %{REQUEST_URI} ^/simple$ [OR] +RewriteCond %{REQUEST_URI} ^/expert$ +RewriteRule (.*) $1.php [QSA] +# Actions +RewriteCond %{REQUEST_URI} ^/ip [OR] +RewriteCond %{REQUEST_URI} ^/add [OR] +RewriteCond %{REQUEST_URI} ^/delete [OR] +RewriteCond %{REQUEST_URI} ^/update [OR] +RewriteCond %{REQUEST_URI} ^/admin/cleanup [OR] +RewriteCond %{REQUEST_URI} ^/admin/sync [OR] +RewriteCond %{REQUEST_URI} ^/admin/parse [OR] +RewriteCond %{REQUEST_URI} ^/admin/get [OR] +RewriteCond %{REQUEST_URI} ^/admin/stats/types [OR] +RewriteCond %{REQUEST_URI} ^/admin/stats/hosts +RewriteRule (.*)\.(xml|html|gif|png|txt|csv|json|) $1.php?format=$2 [QSA,S=1] + +# Tiny URL +RewriteCond %{HTTP_HOST} ^(s|t).(0l.de)$ +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} /(.+) +RewriteRule .* index.php?host=%1 + +# Querystring RewriteCond %{QUERY_STRING} !zone=(0l.de) -RewriteCond %{HTTP_HOST} (0l.de)$ [NC] -RewriteRule (.*)(\?)? $1?zone=%1 [QSA] +RewriteCond %{HTTP_HOST} (0l.de)$ +RewriteRule (.*)(\?)? $1?zone=%1 [QSA] -RewriteCond %{QUERY_STRING} !host=[a-z0-9.-]+ -RewriteCond %{HTTP_HOST} !^(d|dns|sddns|u|url)\.(0l.de)$ [NC] -RewriteCond %{HTTP_HOST} ([a-z0-9.-]+)\.(0l.de)$ [NC] -RewriteRule (.*) $1?host=%1 [QSA] +RewriteCond %{QUERY_STRING} !host=[a-z0-9.-]+ +RewriteCond %{HTTP_HOST} !^(d|s|t|ip4|ip6)\.(0l.de)$ +RewriteCond %{HTTP_HOST} ([a-z0-9.-]+)\.(0l.de)$ +RewriteRule (.*)(\?)? $1?host=%1 [QSA] ExpiresActive Off diff --git a/add.php b/add.php index 4a31a3c..7ad1b74 100755 --- a/add.php +++ b/add.php @@ -28,87 +28,92 @@ require_once 'include/init.php'; $output = Output::start(); -if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { - $zone = $config['sddns']['zones'][$_REQUEST['zone']]; - $type = (empty($_REQUEST['type'])) ? $config['sddns']['std']['type'] : $_REQUEST['type']; - $rdata = (empty($_REQUEST['rdata']) && $type = 'A') ? $_SERVER['REMOTE_ADDR'] : $_REQUEST['rdata']; - $host = (empty($_REQUEST['host'])) ? Host::unique($zone, $db) : new Host($_REQUEST['host'], $zone); - $pw = (empty($_REQUEST['pw'])) ? randomString(8) : $_REQUEST['pw']; - - if (isset($_REQUEST['lifetime']) && is_numeric($_REQUEST['lifetime'])) { - $lifetime = (int) $_REQUEST['lifetime']; +// zone +if (!empty($_REQUEST['zone'])) { + if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { + $zone = $config['sddns']['zones'][$_REQUEST['zone']]; } else { - $lifetime = $config['sddns']['std']['lifetime']; - } - - if ($lifetime < 0) { - $output->add('invalid lifetime', 'error', $lifetime); - $output->send(); - die(); - } - - if (($lifetime > $config['sddns']['max_lifetime'] || $lifetime == 0) && !isAuthentificated()) { - $output->add('lifetime exceeds limit', 'error'); - $output->send(); - die(); - } - - if ($host->isRegistred($db)) { - if ($type == 'URL') { - $output->add('host is already registred', 'error', $host); - $output->send(); - die(); - } - - $host = new DBHost($host->isRegistred($db), $db); - $output->add('found existing host' ,'notice', $host); - - if (!$host->checkPassword($pw) && !isAuthentificated()) { - $output->add('not authentificated for host', 'error', $host); - $output->send(); - die(); - } - } - else { - $host = $host->add($pw, $db); // returns new DBHost - $output->add('host added to db' ,'notice', $host); - - if (empty($_REQUEST['pw'])) { - $output->add('generated password' ,'notice', $pw); - } - } - - if ($type != 'URL') { // pseudo type to create url redirection - $ttl = (empty($_REQUEST['ttl'])) ? $config['sddns']['std']['ttl'] : (int) $_REQUEST['ttl']; - $class = (empty($_REQUEST['class'])) ? $config['sddns']['std']['class'] : $_REQUEST['class']; - - $record = new Record($host, $ttl, $class, $type, $rdata); - - if (!$record->isRegistred($db)) { - $record = $record->add($db, $lifetime); - $output->add('record added to db', 'success', $record); - - $zone->cleanup($db); - $zone->sync($db); - } - else { - $output->add('record already exists in db', 'error', $record); - $output->send(); - die(); - } - } - else { - $uri = new Uri($rdata, $host); - $uri->frame = (isset($_REQUEST['frame']) && $_REQUEST['frame']) ? 1 : 0; - $uri = $uri->add($db, $lifetime); - $output->add('uri redirection added to db', 'success', $uri); + throw new UserException('invalid zone'); } } else { - $output->add('zone not found', 'error', $_REQUEST['zone']); + throw new UserException('missing zone'); } -$output->send(); +$host = (!empty($_REQUEST['host'])) ? new Host($_REQUEST['host'], $zone) : Host::unique($zone, $db); +$pw = (!empty($_REQUEST['pw'])) ? $_REQUEST['pw'] : randomString(8); +$ttl = (!empty($_REQUEST['ttl'])) ? (int) $_REQUEST['ttl'] : $config['sddns']['std']['ttl']; +$class = (!empty($_REQUEST['class'])) ? $_REQUEST['class'] : $config['sddns']['std']['class']; +$rdata = (!empty($_REQUEST['rdata'])) ? $_REQUEST['rdata'] : $_SERVER['REMOTE_ADDR']; -?> +// type +if (isset($_REQUEST['type'])) { + if (in_array($_REQUEST['type'], $config['sddns']['types'])) { + $type = $_REQUEST['type']; + } + else { + throw new UserException('invalid type'); + } +} +else if (IpV4::isValid($rdata)) { + $type = 'A'; +} +else if (IpV6::isValid($rdata)) { + $type = 'AAAA'; +} +else { + throw new UserException('missing type'); +} + +// lifetime +$lifetime = (isset($_REQUEST['lifetime']) && is_numeric($_REQUEST['lifetime'])) ? (int) $_REQUEST['lifetime'] : $config['sddns']['std']['lifetime']; +if ($lifetime < 0) { + throw new UserException('invalid lifetime', $lifetime); +} +else if (($lifetime > $config['sddns']['max_lifetime'] || $lifetime == 0) && !isAuthentificated()) { + throw new UserException('lifetime exceeds limit'); +} + +// host +if ($host->isRegistred($db)) { + if ($type == 'URL') { + throw new UserException('hosts is already registred', $host); + } + + $host = new DBHost($host->isRegistred($db), $db); + $output->add('found existing host' ,'notice', $host); + + if (!$host->checkPassword($pw) && !isAuthentificated()) { + throw new AuthentificationException('not authentificated for host', $host); + } +} +else { + $host = $host->add($pw, $db); // returns new DBHost + $output->add('host added to db' ,'notice', $host); + + if (empty($_REQUEST['pw'])) { + $output->add('generated password' ,'notice', $pw); + } +} + +if ($type == 'URL') { // pseudo type to create url redirection + $uri = new Uri($rdata, $host); + $uri->frame = (isset($_REQUEST['frame']) && $_REQUEST['frame']) ? 1 : 0; + + $uri = $uri->add($db, $lifetime); + $output->add('uri redirection added to db', 'success', $uri); +} +else { + $record = new Record($host, $ttl, $class, $type, $rdata); + + if ($record->isRegistred($db)) { + throw new UserException('record already exists in db', $record); + } + + $record = $record->add($db, $lifetime); + $output->add('record added to db', 'success', $record); + + $zone->cleanup($db); + $zone->sync($db); +} diff --git a/admin/cleanup.php b/admin/cleanup.php index 8dfdaf3..833047e 100755 --- a/admin/cleanup.php +++ b/admin/cleanup.php @@ -42,7 +42,3 @@ foreach ($zones as $name => $zone) { $output->add('cleaning zone', 'notice', $zone); $zone->cleanup($db); } - -$output->send(); - -?> diff --git a/admin/get.php b/admin/get.php index 0026b05..06f50aa 100755 --- a/admin/get.php +++ b/admin/get.php @@ -255,7 +255,3 @@ else { } } } - -$output->send(); - -?> diff --git a/admin/index.php b/admin/index.php index d1b03a1..e43cd2c 100755 --- a/admin/index.php +++ b/admin/index.php @@ -59,7 +59,3 @@ if (isAuthentificated()) { search plugin
- -send(); -?> diff --git a/admin/parse.php b/admin/parse.php index d5c0c6e..bcf49f2 100755 --- a/admin/parse.php +++ b/admin/parse.php @@ -36,7 +36,7 @@ $sql = 'SELECT * $result = $db->query($sql); -$pattern = '/^queries: info: client ([:.0-9a-f]+)#(\d+): query: ([+.-\w]+) ([A-Z]+) ([0-9A-Z]+) ([-+A-Z]+) \(([:.0-9a-f]+)\)$/'; +$pattern = '/^queries: info: client ([:.0-9a-f]+)#(\d+):(?: view \w+:)? query: ([^ ]+) (IN|CH|HS) ([A-Z]+) ([-+A-Z]+) \(([:.0-9a-f]+)\)$/'; $queries = array(); $update = array(); $delete = array(); @@ -58,7 +58,7 @@ foreach ($result as $log) { 'options' => $matches[6], 'queried' => strtotime($log['logged'])); - $db->execute('INSERT IGNORE INTO queries (ip, port, hostname, class, type, options, queried) VALUES (\'' . $query['ip'] . '\', ' . $query['port'] . ', \'' . $query['hostname'] . '\', \'' . $query['class'] . '\', \'' . $query['type'] . '\', \'' . $query['options'] . '\', \'' . date('Y-m-d H:i:s', $query['queried']) . ')'); + $db->execute('INSERT IGNORE INTO queries (ip, port, hostname, class, type, options, queried) VALUES (\'' . $query['ip'] . '\', ' . $query['port'] . ', \'' . $query['hostname'] . '\', \'' . $query['class'] . '\', \'' . $query['type'] . '\', \'' . $query['options'] . '\', \'' . date('Y-m-d H:i:s', $query['queried']) . '\')'); $output->add('query parsed', 'debug', 3, $log['logged'], $log['message']); array_push($delete, $log['id']); @@ -113,7 +113,3 @@ if ($updated > 0) { else { $output->add('no records updated', 'warning'); } - -$output->send(); - -?> diff --git a/admin/query.php b/admin/query.php index 3b89d41..1816586 100755 --- a/admin/query.php +++ b/admin/query.php @@ -43,7 +43,3 @@ $results = $zone->getRecordsFromNS(); foreach ($results as $result) { $output->add('', 'data', $result); } - -$output->send(); - -?> diff --git a/admin/stats/hosts.php b/admin/stats/hosts.php index db350e3..5b8aae3 100755 --- a/admin/stats/hosts.php +++ b/admin/stats/hosts.php @@ -32,7 +32,3 @@ $result = $db->query('SELECT DISTINCT hostname, COUNT(hostname) AS sum FROM quer foreach ($result as $row) { $output->add($row['hostname'], 'data', $row['sum']); } - -$output->send(); - -?> diff --git a/admin/stats/types.php b/admin/stats/types.php index 43b4501..9ea431c 100755 --- a/admin/stats/types.php +++ b/admin/stats/types.php @@ -67,7 +67,3 @@ else { $output->add($row['type'], 'data', round(($row['sum'] / $count) * 100, 5) . ' %', $row['sum']); } } - -$output->send(); - -?> diff --git a/admin/sync.php b/admin/sync.php index 84dde60..e7bba67 100755 --- a/admin/sync.php +++ b/admin/sync.php @@ -38,7 +38,3 @@ foreach ($zones as $zone) { $output->add('syncing zone', 'notice', $zone); $zone->sync($db); } - -$output->send(); - -?> diff --git a/delete.php b/delete.php index 6f9412a..9e7b0b8 100755 --- a/delete.php +++ b/delete.php @@ -27,59 +27,96 @@ require_once 'include/init.php'; $output = Output::start(); -$pw = @$_REQUEST['pw']; -if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { - $zone = $config['sddns']['zones'][$_REQUEST['zone']]; +// default arguments +$rdata = @$_REQUEST['rdata']; +$class = @$_REQUEST['class']; +$type = @$_REQUEST['type']; +$ttl = @$_REQUEST['ttl']; - if (!empty($_REQUEST['host'])) { - if (list($host) = DBHost::get($db, array('host' => $_REQUEST['host'], 'zone' => $zone))) { - if ($host->checkPassword($pw) || isAuthentificated()) { - if (isset($_REQUEST['class']) && in_array($_REQUEST['class'], $config['sddns']['classes'])) - $class = $_REQUEST['class']; - - if (isset($_REQUEST['type']) && in_array($_REQUEST['type'], $config['sddns']['types'])) { - $type = $_REQUEST['type']; - - if (isset($_REQUEST['rdata']) && Record::isRData($_REQUEST['rdata'], $type)) - $rdata = $_REQUEST['rdata']; - } - - if (@$type == 'URL' || empty($type)) { - $uris = DBUri::get($db, array('zone' => $zone, 'host' => $host)); - foreach ($uris as $uri) { - $uri->delete(); - $output->add('uri deleted from db', 'success', $uri); - } - } - - if (@$type != 'URL' || empty($type)) { - $records = DBRecord::get($db, array('zone' => $zone, 'host' => $host, 'type' => @$type, 'class' => @$class, 'rdata' => @$rdata)); - foreach ($records as $record) { - $record->delete(); - $output->add('record deleted from db', 'success', $record); - } - } - - $zone->cleanup($db); - $zone->sync($db); - } - else { - $output->add('not authentificated for host', 'error', $host); - } - } - else { - $output->add('host not found', 'error', $_REQUEST['host']); - } +// zone +if (!empty($_REQUEST['zone'])) { + if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { + $zone = $config['sddns']['zones'][$_REQUEST['zone']]; } else { - $output->add('no host specified', 'error'); + throw new UserException('invalid zone', $_REQUEST['zone']); } } else { - $output->add('zone not found', 'error', $_REQUEST['zone']); + throw new UserException('missing zone'); } -$output->send(); +// password +if (!empty($_REQUEST['pw'])) { + $pw = $_REQUEST['pw']; +} +else if (!empty($_SERVER['PHP_AUTH_PW'])) { + $pw = $_SERVER['PHP_AUTH_PW']; +} +else { + throw new AuthentificationException('missing password'); +} -?> +// type +if (!empty($type) && !in_array($type, $config['sddns']['types'])) { + throw new UserException('invalid type'); +} +else if (IpV4::isValid($rdata)) { + $type = 'A'; +} +else if (IpV6::isValid($rdata)) { + $type = 'AAAA'; +} + +if (!empty($rdata) && !Record::isRdata($rdata, $type)) { + throw new UserException('invalid rdata', $rdata); +} + +// search host +if (!empty($_REQUEST['host'])) { + $host = new Host($_REQUEST['host'], $zone); + + if ($host->isRegistred($db)) { + $host = new DBHost($host->isRegistred($db), $db); + $output->add('found existing host', 'success', $host); + } + else { + throw new UserException('host not found', $_REQUEST['host']); + } +} +else { + throw new UserException('missing host'); +} + +if ($host->checkPassword($pw) || isAuthentificated()) { + // search + $uris = DBUri::get($db, array('zone' => $zone, 'host' => $host)); + $records = DBRecord::get($db, array('zone' => $zone, 'host' => $host, 'type' => $type, 'class' => $class, 'rdata' => $rdata, 'ttl' => $ttl)); + + if (empty($type)) { + $entries = array_merge($uris, $records); + } + else if ($type == 'URL') { + $entries = $uris; + } + else { + $entries = $records; + } + + if (empty($entries)) { + $output->add('no records found to delete', 'warning'); + } + else { + foreach ($entries as $entry) { + $entry->delete(); + $output->add('entry deleted from db', 'success', $entry); + } + + $zone->cleanup($db); + $zone->sync($db); + } +} +else { + throw new AuthentificationException('not authentificated for host', $host); +} diff --git a/expert.php b/expert.php index ce0af66..683358b 100755 --- a/expert.php +++ b/expert.php @@ -31,86 +31,109 @@ $output = Output::start('html'); $output->add('hits since launch', 'notice', $site['hits']); if (isAuthentificated()) { - $output->add('authetificated as', 'notice', $_SERVER['PHP_AUTH_USER']); + $output->add('authentificated as', 'notice', $_SERVER['PHP_AUTH_USER']); } -$ttl = (isset($_REQUEST['ttl'])) ? $_REQUEST['ttl'] : $config['sddns']['std']['ttl']; -$lifetime = (isset($_REQUEST['lifetime'])) ? $_REQUEST['lifetime'] : (isAuthentificated()) ? 0 : $config['sddns']['std']['lifetime']; -$checkedClass = (isset($_REQUEST['class'])) ? $_REQUEST['class'] : $config['sddns']['std']['class']; -$checkedType = (isset($_REQUEST['type'])) ? $_REQUEST['type'] : $config['sddns']['std']['type']; +$ttl = (!empty($_REQUEST['ttl'])) ? $_REQUEST['ttl'] : $config['sddns']['std']['ttl']; +$lifetime = (!empty($_REQUEST['lifetime'])) ? $_REQUEST['lifetime'] : (isAuthentificated()) ? 0 : $config['sddns']['std']['lifetime']; +$class = (!empty($_REQUEST['class'])) ? $_REQUEST['class'] : $config['sddns']['std']['class']; +$rdata = (!empty($_REQUEST['rdata'])) ? $_REQUEST['rdata'] : $_SERVER['REMOTE_ADDR']; +// type +if (!empty($_REQUEST['type'])) { + if (in_array($_REQUEST['type'], $config['sddns']['types'])) { + $type = $_REQUEST['type']; + } + else { + throw new UserException('invalid type'); + } +} +else if (IpV4::isValid($rdata)) { + $type = 'A'; +} +else if (IpV6::isValid($rdata)) { + $type = 'AAAA'; +} +else { + $type = $config['sddns']['std']['type']; +} ?> +
-
/dev/nulll
-

Tiny DNS & URL

-

Expert interface

-

by Steffen Vogel

-
-
+
+ + /dev/nulll + +
+

Tiny DNS & URL

+

Expert interface

+

by Steffen Vogel

+
+ + } ?> + + - - - + + + + + + + + + + + + + + + + ' . $c . ''; + } ?> + + ' . $t . ''; + } ?> + + + + + + + + + + + - - -
include debugging information
.optional; random or servername
secondstime to live in cache; max seconds
secondslifetime of a record/url without being updated/touched; max
.optional; random or servername
secondstime to live in cache; max seconds
secondslifetime of a record/url without being updated/touched; max
hide uri in a frameset
optional; random generated
hide uri in a frameset
optional; random generated
@@ -126,7 +149,3 @@ $checkedType = (isset($_REQUEST['type'])) ? $_REQUEST['type'] : $config['sddns']
- -send(); -?> diff --git a/include/config.php b/include/config.php index 4ae01dc..d989d28 100755 --- a/include/config.php +++ b/include/config.php @@ -30,7 +30,7 @@ $config['path']['web'] = ''; $config['db']['host'] = 'localhost'; $config['db']['user'] = 'sddns'; $config['db']['pw'] = 'RjRXDa68hnS5A8mX'; -$config['db']['db'] = 'st_sddns'; +$config['db']['db'] = 'sddns'; $config['db']['tbl']['prefix'] = ''; $config['db']['tbl']['records'] = $config['db']['tbl']['prefix'] . 'records'; $config['db']['tbl']['hosts'] = $config['db']['tbl']['prefix'] . 'hosts'; @@ -40,6 +40,7 @@ $config['sddns']['htpasswd'] = $site['path']['server'] . '/../.htpasswd'; $key = array('hmac' => 'gDlXSZtESw78I47O68UEigpPofn0XbpSpo5Vba+9IY38EYagPO/2C2Ch lZL+AvtN/ozRdra+p3+wLOKvVvqdrA==', 'name' => 'info.steffenvogel.de.'); $zones = array('0l.de'); + $config['sddns']['ns']['hostname'] = 'localhost'; $config['sddns']['ns']['port'] = 53; @@ -50,7 +51,7 @@ foreach ($zones as $zone) { $config['sddns']['max_lifetime'] = 6 * 30 * 24 * 60 * 60; // in seconds; 6 months $config['sddns']['max_ttl'] = 60 * 60; // in seconds; 1 hour $config['sddns']['classes'] = array('IN', 'CH', 'HS'); -$config['sddns']['types'] = array('A', 'AAAA', 'NS', 'TXT', 'MX', 'SRV', 'CNAME', 'LOC', 'HINFO', 'URL' /* pseudo type for url redirection */); +$config['sddns']['types'] = array('A', 'AAAA', 'NS', 'TXT', 'MX', 'SRV', 'CNAME', 'LOC', 'HINFO', 'URL' /* pseudo type for url redirection */); $config['sddns']['std']['class'] = 'IN'; $config['sddns']['std']['type'] = 'A'; @@ -58,6 +59,6 @@ $config['sddns']['std']['ttl'] = 2 * 60; // in seconds; 2 minutes; < max_ttl! $config['sddns']['std']['lifetime'] = 1 * 30 * 24 * 60 * 60; // in seconds; 1 month; < max_lifetime! $config['sddns']['cmds'] = array('add', 'delete', 'update'); // available cmds -$config['sddns']['formats'] = array('html', 'xml', 'gif', 'txt', 'csv'); // available formats (keep in sync with .htaccess!) +$config['sddns']['formats'] = array('html', 'xml', 'gif', 'txt', 'csv', 'png', 'json'); // available formats (keep in sync with .htaccess!) +$config['sddns']['blacklist'] = array_merge($zones, array('steffenvogel.de', 'griesm.de', 'vogel.cc', 'icann.org', 'isc.org')); -?> diff --git a/include/db.php b/include/db.php index e49ec66..6d2766a 100755 --- a/include/db.php +++ b/include/db.php @@ -165,5 +165,3 @@ abstract class Database implements IDatabase { */ protected $statements = array(); } - -?> diff --git a/include/dbhost.php b/include/dbhost.php index 93ca20c..36a409f 100755 --- a/include/dbhost.php +++ b/include/dbhost.php @@ -32,7 +32,7 @@ class DBHost extends Host implements DBObject { private $db; public function __construct($id, Database $db) { - $config = Registry::get('config'); + global $config; $this->db = $db; @@ -45,16 +45,12 @@ class DBHost extends Host implements DBObject { parent::__construct($host['hostname'], $config['sddns']['zones'][$host['zone']], $host['generated']); } else { - throw new CustomException('Host with id ' . $id . ' not found!'); + throw new CustomException('host not found by id', $id); } } - public function __destruct() { - //$this->update(); - } - public function update() { - $config = Registry::get('config'); + global $config; $sql = 'UPDATE ' . $config['db']['tbl']['hosts'] . ' SET @@ -68,13 +64,13 @@ class DBHost extends Host implements DBObject { } public function delete() { - $config = Registry::get('config'); + global $config; if ($this->getRecordsFromDB() > 0) { - throw new UserException('Host has records!'); + throw new UserException('host has records'); } elseif ($this->getUrisFromDB() > 0) { - throw new UserException('Host has uris!'); + throw new UserException('host has uris'); } else { $sql = 'DELETE FROM ' . $config['db']['tbl']['hosts'] . ' @@ -84,7 +80,7 @@ class DBHost extends Host implements DBObject { } public function checkPassword($pw) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT password FROM ' . $config['db']['tbl']['hosts'] . ' @@ -105,7 +101,7 @@ class DBHost extends Host implements DBObject { } public static function get(Database $db, $filter = false, $order = array()) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT id FROM ' . $config['db']['tbl']['hosts'] . ' @@ -149,5 +145,3 @@ class DBHost extends Host implements DBObject { return $xmlRecord; } } - -?> diff --git a/include/dbobject.php b/include/dbobject.php index 525eda7..a08f9e8 100755 --- a/include/dbobject.php +++ b/include/dbobject.php @@ -28,7 +28,6 @@ interface DBObject extends Object { public static function get(Database $db, $filter); public function delete(); - public function __destruct(); public function update(); } -?> + diff --git a/include/dbrecord.php b/include/dbrecord.php index 83cfde5..2b7e87a 100755 --- a/include/dbrecord.php +++ b/include/dbrecord.php @@ -25,6 +25,7 @@ */ class DBRecord extends Record implements DBObject { + public $id; public $lifetime; public $lastAccessed; @@ -32,13 +33,11 @@ class DBRecord extends Record implements DBObject { private $db; public function __construct($id, Database $db) { - $config = Registry::get('config'); + global $config; $this->db = $db; - $sql = 'SELECT * - FROM ' . $config['db']['tbl']['records'] . ' - WHERE id = ' . (int) $id; + $sql = 'SELECT * FROM ' . $config['db']['tbl']['records'] . ' WHERE id = ' . (int) $id; $result = $this->db->query($sql, 1); $record = $result->first(); @@ -51,12 +50,8 @@ class DBRecord extends Record implements DBObject { parent::__construct($this->host, (int) $record['ttl'], $record['class'], $record['type'], $record['rdata']); } - public function __destruct() { - //$this->update(); - } - public function update() { - $config = Registry::get('config'); + global $config; $sql = 'UPDATE ' . $config['db']['tbl']['records'] . ' SET @@ -70,6 +65,8 @@ class DBRecord extends Record implements DBObject { WHERE id = ' . (int) $this->id; $this->db->execute($sql); + + return $this->db->affectedRows(); } public function toXml(DOMDocument $doc) { @@ -84,16 +81,14 @@ class DBRecord extends Record implements DBObject { } public function delete() { - $config = Registry::get('config'); - - $sql = 'DELETE FROM ' . $config['db']['tbl']['records'] . ' - WHERE id = ' . (int) $this->id; + global $config; + $sql = 'DELETE FROM ' . $config['db']['tbl']['records'] . ' WHERE id = ' . (int) $this->id; $this->db->execute($sql); } public static function get(Database $db, $filter = false, $order = array()) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT r.id FROM ' . $config['db']['tbl']['records'] . ' AS r @@ -137,5 +132,3 @@ class DBRecord extends Record implements DBObject { return $records; } } - -?> diff --git a/include/dburi.php b/include/dburi.php index bb827fc..5d4d91c 100755 --- a/include/dburi.php +++ b/include/dburi.php @@ -33,7 +33,7 @@ class DBUri extends Uri implements DBObject { private $db; public function __construct($id, Database $db) { - $config = Registry::get('config'); + global $config; $this->db = $db; @@ -54,12 +54,8 @@ class DBUri extends Uri implements DBObject { parent::__construct($uri['uri'], $this->host); } - public function __destruct() { - //$this->update(); - } - public function update() { - $config = Registry::get('config'); + global $config; $sql = 'UPDATE ' . $config['db']['tbl']['uris'] . ' SET @@ -86,7 +82,7 @@ class DBUri extends Uri implements DBObject { } public function delete() { - $config = Registry::get('config'); + global $config; $sql = 'DELETE FROM ' . $config['db']['tbl']['uris'] . ' WHERE id = ' . (int) $this->id; @@ -95,7 +91,7 @@ class DBUri extends Uri implements DBObject { } public static function get(Database $db, $filter = false, $order = array()) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT u.id FROM ' . $config['db']['tbl']['uris'] . ' AS u @@ -134,5 +130,3 @@ class DBUri extends Uri implements DBObject { return $uris; } } - -?> diff --git a/include/exceptions.php b/include/exceptions.php index 45def3d..25c5552 100755 --- a/include/exceptions.php +++ b/include/exceptions.php @@ -24,11 +24,19 @@ * along with sddns. If not, see . */ -class UserException extends CustomException {} -class ValidationException extends UserException {} -class NameServerException extends CustomException {} - class CustomException extends Exception { + + protected $data; + + function __construct($message = '', $data = array(), $code = 0) { + $this->data = $data; + parent::__construct($message, $code); + } + + public function getData() { + return $this->data; + } + public function toXml(DOMDocument $doc) { $xmlRecord = $doc->createElement('exception'); $xmlRecord->setAttribute('code', $this->code); @@ -37,7 +45,7 @@ class CustomException extends Exception { $xmlRecord->appendChild($doc->createElement('line', $this->line)); $xmlRecord->appendChild($doc->createElement('file', $this->file)); - $xmlRecord->appendChild(backtrace2xml($this->getTrace(), $doc)); + $xmlRecord->appendChild(backtrace2xml($this->getTrace(), $doc)); return $xmlRecord; } @@ -47,4 +55,9 @@ class CustomException extends Exception { } } -?> +class NameServerException extends CustomException {} +class UserException extends CustomException { +} +class AuthentificationException extends UserException {} +class ValidationException extends UserException {} +class MissingArgumentException extends UserException {} diff --git a/include/functions.php b/include/functions.php index 8430dd0..db1368f 100755 --- a/include/functions.php +++ b/include/functions.php @@ -30,15 +30,14 @@ function doAuthentification() { } function isAuthentificated() { - $config = Registry::get('config'); - $htpasswd = file($config['htpasswd']); + global $config; + $htpasswd = file($config['htpasswd'], FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); foreach ($htpasswd as $line) { - list($user, $crypt) = explode(':', $line); - $salt = substr($crypt, 0, 2); + list($user, $sha1) = explode(':', $line); if ($user == @$_SERVER['PHP_AUTH_USER'] && - trim($crypt) == crypt(@$_SERVER['PHP_AUTH_PW'], $salt)) { + $sha1 == '{SHA}' . base64_encode(sha1(@$_SERVER['PHP_AUTH_PW'], true))) { return true; } } @@ -49,9 +48,11 @@ function isAuthentificated() { function randomString($length, $characters='abcdefghijklmnopqrstuvwxyz0123456789') { $random_string = ''; $characters_length = strlen($characters); + for($i = 0; $i<$length; $i++) { $random_string .= $characters[mt_rand(0, $characters_length - 1)]; } + return $random_string; } @@ -101,4 +102,3 @@ function backtrace2html($traces) { return $trace; } -?> diff --git a/include/host.php b/include/host.php index 13622e2..eeed8e6 100755 --- a/include/host.php +++ b/include/host.php @@ -25,6 +25,7 @@ */ class Host implements Object { + public $punycode; public $zone; public $generated; @@ -41,14 +42,14 @@ class Host implements Object { } else { if (strlen($hostname) > 63) - throw new UserException('Invalid hostname: too long'); + throw new UserException('invalid hostname', 'too long'); else - throw new UserException('Invalid hostname: ' . idn_to_ascii($hostname)); + throw new UserException('invalid hostname', idn_to_ascii($hostname)); } } public static function unique(Zone $zone, Database $db) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT hostname FROM ' . $config['db']['tbl']['hosts'] . ' @@ -84,7 +85,7 @@ class Host implements Object { } public function isRegistred(Database $db) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT * FROM ' . $config['db']['tbl']['hosts'] . ' @@ -100,7 +101,7 @@ class Host implements Object { * Database */ public function add($pw, Database $db) { - $config = Registry::get('config'); + global $config; $sql = 'INSERT INTO ' . $config['db']['tbl']['hosts'] . ' (hostname, zone, password, generated) VALUES ( @@ -144,4 +145,3 @@ class Host implements Object { } } -?> diff --git a/include/init.php b/include/init.php index d70f052..0a3d2c4 100755 --- a/include/init.php +++ b/include/init.php @@ -30,7 +30,6 @@ $site['path']['server'] = dirname(dirname(__FILE__)); require_once $site['path']['server'] . '/include/functions.php'; require_once $site['path']['server'] . '/include/exceptions.php'; -require_once $site['path']['server'] . '/include/registry.php'; require_once $site['path']['server'] . '/include/mysql.php'; require_once $site['path']['server'] . '/include/output.php'; @@ -50,7 +49,6 @@ require_once $site['path']['server'] . '/include/nameserver.php'; require_once $site['path']['server'] . '/include/zone.php'; require_once $site['path']['server'] . '/include/config.php'; -Registry::set('config', $config); // get relevant runtime information $site['hostname'] = @$_SERVER['SERVER_NAME']; @@ -58,16 +56,11 @@ $site['path']['web'] = $config['path']['web']; $site['url'] = 'http://' . $site['hostname'] . $site['path']['web']; // debug mode -if (@isset($_REQUEST['debug'])) { +if (isset($_REQUEST['debug'])) { $site['debug'] = (int) $_REQUEST['debug']; } else { - if (isAuthentificated()) { - $site['debug'] = 3; - } - else { - $site['debug'] = 0; - } + $site['debug'] = (isAuthentificated()) ? 3 : 0; } // simple hit counting @@ -79,8 +72,6 @@ fseek($handle, 0); fwrite($handle, $site['hits']) ; fclose($handle); -Registry::set('site', $site); - // set locale setlocale(LC_TIME, 'de_DE.UTF8'); @@ -92,6 +83,3 @@ date_default_timezone_set('Europe/Berlin'); // database $db = new MySql($config['db']['host'], $config['db']['user'], $config['db']['pw'], $config['db']['db']); -Registry::set('db', $db); - -?> diff --git a/include/ip.php b/include/ip.php index 9b4fefd..ae5247d 100755 --- a/include/ip.php +++ b/include/ip.php @@ -25,6 +25,7 @@ */ class IpV4 implements Object { + public $tuples = array(); public function __construct($ipString) { @@ -45,7 +46,7 @@ class IpV4 implements Object { } public function toHtml() { - return '' . $this . ''; + return '' . $this . ''; } public function toXml(DOMDocument $doc) { @@ -57,14 +58,15 @@ class IpV4 implements Object { } class IpV6 implements Object { + private $ip; public function __construct($ipString) { if (self::isValid($ipString)) { - $this->ip = $ipString; + $this->ip = strtolower($ipString); } else { - throw new ValidationException('Invalid IP: ', $ipString); + throw new ValidationException('invalid ip', $ipString); } } @@ -77,7 +79,7 @@ class IpV6 implements Object { } public function toHtml() { - return '' . $this . ''; + return '' . $this . ''; } public function toXml(DOMDocument $doc) { @@ -87,5 +89,3 @@ class IpV6 implements Object { return $xmlIpV6; } } - -?> diff --git a/include/mysql.php b/include/mysql.php index e799dda..2c30932 100755 --- a/include/mysql.php +++ b/include/mysql.php @@ -29,8 +29,7 @@ require_once dirname(__FILE__) . '/db.php'; /** * @brief base exception for mysql queries */ -class MySqlException extends DatabaseException -{ +class MySqlException extends DatabaseException { function __construct($message = null, $code = 0) { $message = sprintf('%04d: %s', mysql_errno(), mysql_error()); parent::__construct($message, mysql_errno()); @@ -40,8 +39,7 @@ class MySqlException extends DatabaseException /** * @brief resultset of a mysql query */ -class MySqlResult extends DBResultSet -{ +class MySqlResult extends DBResultSet { /** * @param resource $resource mysql resultset */ @@ -81,6 +79,7 @@ class MySql extends Database { public function connect($host, $user, $pw) { $this->close(); $__er = error_reporting(E_ERROR); + if (!$this->resource = mysql_connect($host, $user, rawurlencode($pw))) { error_reporting($__er); throw new MySqlException(); @@ -93,8 +92,10 @@ class MySql extends Database { * @brief close database connection */ public function close() { - if (!$this->resource) + if (!$this->resource) { return; + } + mysql_close($this->resource); $this->resource = false; } @@ -104,8 +105,10 @@ class MySql extends Database { * @param string $name database name */ public function select($db) { - if (!mysql_select_db($db, $this->resource)) + if (!mysql_select_db($db, $this->resource)) { throw new MySqlException(); + } + $this->database = $db; } @@ -115,11 +118,13 @@ class MySql extends Database { * @return mixed */ public function execute($sql) { - if ($output = Registry::get('output')) - $output->add('db query', 'debug', 8, $sql); + global $output; - if (!($result = mysql_unbuffered_query($sql, $this->resource))) + if ($output) $output->add('db query', 'debug', 8, $sql); + + if (!($result = mysql_unbuffered_query($sql, $this->resource))) { throw new MySqlException(); + } return $result; } @@ -132,8 +137,10 @@ class MySql extends Database { * @return TDatabaseResultSet */ public function query($sql, $limit = -1, $offset = 0) { - if ($limit != -1) + if ($limit != -1) { $sql .= sprintf(' LIMIT %d, %d', $offset, $limit); + } + return new MySqlResult($this->execute($sql)); } @@ -153,5 +160,3 @@ class MySql extends Database { return mysql_affected_rows($this->resource); } } - -?> diff --git a/include/nameserver.php b/include/nameserver.php index 832e21b..cf682f6 100755 --- a/include/nameserver.php +++ b/include/nameserver.php @@ -25,6 +25,7 @@ */ class NameServer implements Object { + protected $process; protected $pipes; @@ -34,83 +35,103 @@ class NameServer implements Object { public $port; public function __construct($hostname, $port = 53) { - $config = Registry::get('config'); + global $config; $this->hostname = $hostname; $this->port = $port; } - protected function initialize() { - $output = Registry::get('output'); - $config = Registry::get('config'); + protected function open() { + global $output; - $descriptorspec = array(0 => array('pipe', 'r'), // stdin - 1 => array('pipe', 'w'), // stdout - 2 => array('pipe', 'w')); // stderr + $descriptorspec = array( + 0 => array('pipe', 'r'), // stdin + 1 => array('pipe', 'w'), // stdout + 2 => array('pipe', 'w') // stderr + ); if ($this->isRunning()) { - $this->close(); + throw new NameserverException('ns connection' , 'already established'); } $this->process = proc_open('nsupdate -d -v', $descriptorspec, $this->pipes); - $output->add('ns initialized', 'debug', 1); + + if ($this->isRunning()) { + $output->add('ns connection', 'debug', 3, 'established'); + } + else { + throw new NameserverException('ns connection', 'failed'); + } + + return true; + } + + protected function close() { + global $output; + + if (!$this->isRunning()) { + throw new NameserverException('there is no running process to close'); + } + + fclose($this->pipes[0]); + + $result['stdout'] = stream_get_contents($this->pipes[1]); + $result['stderr'] = stream_get_contents($this->pipes[2]); + + fclose($this->pipes[1]); + fclose($this->pipes[2]); + + $result['code'] = proc_close($this->process); + + $output->add('ns connection', 'debug', 3, 'closed'); + + $this->process = null; + + return $result; + } + + protected function initQueue() { + global $config; + + $this->queue = array(); $this->queueCommand('server ' . $this->hostname . ' ' . $this->port); $this->queueCommand('class ' . $config['sddns']['std']['class']); + $this->queueCommand('ttl ' . $config['sddns']['std']['ttl']); } - protected final function close() { - $output = Registry::get('output'); - - if ($this->isRunning()) { - fclose($this->pipes[0]); - - $return['stdout'] = stream_get_contents($this->pipes[1]); - $return['stderr'] = stream_get_contents($this->pipes[2]); - - fclose($this->pipes[1]); - fclose($this->pipes[2]); - - $return['code'] = proc_close($this->process); - - $this->process = null; - - $output->add('connection to ns closed', 'debug', 1); - - return $return; - } - else { - throw new CustomException('There is no running process to close.'); + private function sendQueue() { + while ($command = array_shift($this->queue)) { + $this->sendCommand($command); } } - protected final function sendQueue() { - $output = Registry::get('output'); - $site = Registry::get('site'); + protected function commitQueue() { + $this->open(); - if ($output->debug > 2) - $this->queueCommand('show'); + $this->queueCommand('show'); $this->queueCommand('send'); - $output->add('send queue to ns', 'debug', 1); + $this->queueCommand('answer'); + + $this->sendQueue(); return $this->close(); } - protected final function queueCommand($command) { - $output = Registry::get('output'); + private function sendCommand($command) { + global $output; - if (!$this->isRunning()) { - $this->initialize(); - } - - fwrite($this->pipes[0], $command . "\n"); - $this->queue[] = $command; + fwrite($this->pipes[0], $command . "\n"); if (substr($command, 0, 3) != 'key') { - $output->add('added command to ns queue', 'debug', 3, $command); + $output->add('ns command', 'debug', 3, $command); } } + protected function queueCommand($command) { + $this->queue[] = $command; + } + protected function add(Record $record) { $this->queueCommand('update add ' . $record); } @@ -124,15 +145,16 @@ class NameServer implements Object { } public function query($host, $type = 'A', $class = 'IN') { - $output = Registry::get('output'); - $config = Registry::get('config'); + global $output; + global $config; $cli = 'dig -c ' . $class . ' -t ' . $type . ' ' . $host . ' @' . $this->hostname . ' +noall +answer'; $output->add('execute dig', 'debug', 2, $cli); exec(escapeshellcmd($cli), $return, $returnCode); - if ($returnCode != 0) - throw new NameServerException('dig query failed with code: ' . $returnCode); + if ($returnCode != 0) { + throw new NameServerException('dig query', 'failed', $returnCode); + } $results = array(); @@ -170,4 +192,3 @@ class NameServer implements Object { } } -?> diff --git a/include/object.php b/include/object.php index c41b8d3..5989e9b 100755 --- a/include/object.php +++ b/include/object.php @@ -32,4 +32,3 @@ interface Object { } -?> diff --git a/include/output.php b/include/output.php index 818cc81..8eb2b05 100755 --- a/include/output.php +++ b/include/output.php @@ -25,6 +25,7 @@ */ class JsonOutput extends Output { + public function __construct($debug) { parent::__construct('application/json', 'UTF-8', $debug); } @@ -48,6 +49,7 @@ class JsonOutput extends Output { } class XmlOutput extends Output { + public function __construct($debug) { parent::__construct('text/xml', 'UTF-8', $debug); } @@ -86,11 +88,12 @@ class XmlOutput extends Output { // needs JPGraph >= 3.0.7! class GraphOutput extends Output { + private $graph; public function __construct($debug) { parent::__construct('text/html', 'UTF-8', $debug); - $site = Registry::get('site'); + global $site; require_once 'jpgraph/jpgraph.php'; } @@ -110,20 +113,21 @@ class GraphOutput extends Output { public function showGraph() { - if (@isset($this->graph)) + if (isset($this->graph)) $this->graph->Stroke(); } - protected function getOutput() { // TODO beautify - if (count($this->getMessages()) > 0) { - echo '
';
-		print_r($this->getMessages());
-		echo '
'; - } + protected function getOutput() { // TODO + if (count($this->getMessages()) > 0) { + echo '
';
+			print_r($this->getMessages());
+			echo '
'; + } } } class GifOutput extends Output { + public function __construct() { parent::__construct('image/gif'); } @@ -140,6 +144,7 @@ class GifOutput extends Output { } class PlainLineOutput extends Output { + public function __construct($debug, $fields = array('index', 'time', 'type', 'description', 'data'), $delimiter = "\t", $lineDelimiter = "\n", $escape = true) { parent::__construct('text/plain', 'UTF-8', $debug); $this->fields = $fields; @@ -159,7 +164,7 @@ class PlainLineOutput extends Output { foreach ($this->fields as $fieldIndex => $field) { switch ($field) { case 'type': - fwrite($fd, $message['type']); + fwrite($fd, '[' . $message['type'] . ']'); break; case 'index': @@ -175,9 +180,7 @@ class PlainLineOutput extends Output { break; case 'data': - foreach ($message['data'] as $object) { - fwrite($fd, $this->delimiter . $object); - } + fwrite($fd, implode(', ', $message['data'])); break; default: fwrite($fd, $message[$field]); @@ -199,6 +202,7 @@ class PlainLineOutput extends Output { } class HtmlOutput extends Output { + public function __construct($debug) { parent::__construct('text/html', 'UTF-8', $debug); @@ -206,7 +210,8 @@ class HtmlOutput extends Output { } protected function getOutput() { - $site = Registry::get('site'); + global $site; + $columnCount = 0; $messages = $this->getMessages(); $html = ob_get_clean(); @@ -271,6 +276,7 @@ class HtmlOutput extends Output { } abstract class Output { + protected $messages = array(); public $debug = 0; public $format; @@ -282,7 +288,6 @@ abstract class Output { $this->encoding = $encoding; $this->debug = $debug; - if ($this->contentType != null) header('Content-type: ' . $this->contentType . (($this->encoding != null) ? '; charset=' . $this->encoding : '')); } @@ -300,8 +305,7 @@ abstract class Output { } for ($i = ($type == 'debug') ? 3 : 2; $i < $argc; $i++) { - if (empty($argv[$i])) - continue; + if (empty($argv[$i])) continue; if (!is_array($argv[$i])) { $message['data'][] = $argv[$i]; @@ -315,19 +319,16 @@ abstract class Output { } protected function getMessages($exclude = true, $args = null) { - $types = array('notice', 'success', 'error', 'exception', 'warning', 'data'); // 'debug'); + $types = array('notice', 'success', 'error', 'exception', 'warning', 'data', 'debug'); if ($args == null) - $args = array(); + $args = array(); - if ($exclude) - $types = array_diff($types, $args); - else - $types = $args; + $types = ($exclude) ? array_diff($types, $args) : $args; $messages = array(); foreach ($this->messages as $message) { - if (in_array($message['type'], $types) || ($message['type'] == 'debug' && $message['level'] <= $this->debug)) { + if (in_array($message['type'], $types) && ($message['type'] != 'debug' || $message['level'] <= $this->debug)) { $messages[] = $message; } } @@ -342,17 +343,13 @@ abstract class Output { break; case 'txt': - return new PlainLineOutput($debug, array('index', 'time', 'type', 'description', 'data'), "\t", "\n"); + return new PlainLineOutput($debug, array('type', 'description', 'data'), "\t", "\n"); break; case 'csv': return new PlainLineOutput($debug, array('time', 'type', 'description', 'data'), ";", "\n"); break; - case 'dyndns': - return new DynDnsOutput(); - break; - case 'png': return new GraphOutput($debug); break; @@ -374,27 +371,26 @@ abstract class Output { static function start($forced = null) { global $argc; - - $site = Registry::get('site'); + global $site; if (isset($forced)) $format = $forced; elseif (isset($argc)) $format = 'txt'; - elseif ($_SERVER['SERVER_NAME'] === 'members.dyndns.org') - $format = 'dyndns'; elseif (empty($_REQUEST['format']) || @$_REQUEST['format'] == 'php') $format = 'html'; else $format = $_REQUEST['format']; $output = self::getInstance($format, $site['debug']); - Registry::set('output', $output); // errorhandling set_exception_handler(array($output, 'exception_handler')); set_error_handler(array($output, 'error_handler'), E_ALL); + // shutdown + register_shutdown_function(array($output, 'send')); + // debugging $parameters = array(); foreach ($_REQUEST as $parName => $parValue) { @@ -408,16 +404,27 @@ abstract class Output { } function exception_handler($exception) { - $this->add('unhandled ' . get_class($exception), 'exception', (array) $exception); - $this->debug = 7; // increase verbosity in case of an exception - $this->send(); + if (is_subclass_of($exception, 'CustomException')) { + $this->add($exception->getMessage(), 'error', $exception->getData()); + } + else { + $this->debug = 7; // increase verbosity in case of an exception + $this->add(get_class($exception), 'exception', (array) $exception); + } + + switch (get_class($exception)) { + case 'CustomException': http_response_code(500); break; + case 'UserException': http_response_code(400); break; + case 'ValidationException': http_response_code(400); break; + case 'AuthentificationException': http_response_code(403); break; + default: $code = 500; break; + } + + exit(1); } function error_handler($errno, $errstr, $errfile, $errline) { - if (($errno & error_reporting()) == 0) { - return; - } - else { + if (($errno & error_reporting()) != 0) { switch ($errno) { case E_USER_WARNING: case E_WARNING: @@ -438,7 +445,7 @@ abstract class Output { $str = $type; break; } - $this->add($str . ' in script', $type, $errstr . ' in ' . $errfile . ':' . $errline); + $this->add($str, $type, $errstr . ' in ' . $errfile . ':' . $errline); } } @@ -448,5 +455,3 @@ abstract class Output { echo $this->getOutput(); } } - -?> diff --git a/include/record.php b/include/record.php index 3bdc50e..12a5f3a 100755 --- a/include/record.php +++ b/include/record.php @@ -25,32 +25,33 @@ */ class Record implements Object { + public $host, $ttl, $class, $type, $rdata; /* * Constructors */ public function __construct(Host $host, $ttl, $class, $type, $rdata) { - $config = Registry::get('config'); + global $config; $this->host = $host; if (is_int($ttl) && $ttl > 0 && $ttl <= $config['sddns']['max_ttl']) { $this->ttl = $ttl; } else { - throw new UserException('Invalid ttl: ' . $ttl); + throw new UserException('Invalid ttl', $ttl); } if (in_array($class, $config['sddns']['classes'])) { $this->class = $class; } else { - throw new UserException('Invalid class: ' . $class); + throw new UserException('invalid class', $class); } if (in_array($type, $config['sddns']['types'])) { $this->type = $type; } else { - throw new UserException('Invalid type: ' . $type); + throw new UserException('invalid type', $type); } $this->setRData($rdata); @@ -72,22 +73,31 @@ class Record implements Object { $this->rdata = $rdata; } } else { - throw new ValidationException('Invalid rdata: ' . $rdata); + throw new ValidationException('invalid rdata', $rdata); } } + public function setTtl($ttl) { + if (is_numeric($ttl)) { + $this->ttl = $ttl; + } + else { + throw new ValidationException('invalid ttl', $ttl); + } + } + + /* * Database */ public function add(Database $db, $lifetime) { - $config = Registry::get('config'); - $db = Registry::get('db'); + global $config; if ($this->host->isRegistred($db)) { $host = new DBHost($this->host->isRegistred($db), $db); } else { - throw new UserException('Unable to add record: Host is not registred!'); + throw new UserException('unable to add record: host is not registred!'); } $sql = 'INSERT INTO ' . $config['db']['tbl']['records'] . ' (host_id, ttl, class, type, rdata, created, last_accessed, lifetime, ip) VALUES ( @@ -144,7 +154,7 @@ class Record implements Object { } public function isRegistred(Database $db) { - $config = Registry::get('config'); + global $config; $sql = 'SELECT * FROM ' . $config['db']['tbl']['records'] . ' AS r @@ -200,7 +210,7 @@ class Record implements Object { } public function toHtml() { - $html = '' . $this->host->toHtml() . ' ' . $this->ttl . ' ' . $this->class . ' ' . $this->type . ''; + $html = '' . $this->host->toHtml() . ' ' . $this->ttl . ' ' . $this->class . ' ' . $this->type . ''; $html .= ' '; switch ($this->type) { @@ -211,7 +221,7 @@ class Record implements Object { case 'NS': case 'CNAME': - $html .= '' . $this->rdata . ''; + $html .= '' . $this->rdata . ''; break; default: @@ -223,4 +233,3 @@ class Record implements Object { } } -?> diff --git a/include/registry.php b/include/registry.php deleted file mode 100755 index 0dcdccc..0000000 --- a/include/registry.php +++ /dev/null @@ -1,108 +0,0 @@ - - * @link http://www.steffenvogel.de - */ -/* - * This file is part of sddns - * - * sddns is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * any later version. - * - * sddns is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with sddns. If not, see . - */ - -/** - * Registry class to pass global variables between classes. - */ -abstract class Registry { - /** - * Object registry provides storage for shared objects - * - * @var array - */ - private static $registry = array(); - - /** - * Adds a new variable to the Registry. - * - * @param string $key Name of the variable - * @param mixed $value Value of the variable - * @throws Exception - * @return bool - */ - public static function set($key, $value) { - if (!isset(self::$registry[$key])) { - self::$registry[$key] = $value; - return true; - } else { - throw new Exception('Unable to set variable `' . $key . '`. It was already set.'); - } - } - - /** - * Returns the value of the specified $key in the Registry. - * - * @param string $key Name of the variable - * @return mixed Value of the specified $key - */ - public static function get($key) - { - if (isset(self::$registry[$key])) { - return self::$registry[$key]; - } - return null; - } - - /** - * Returns the whole Registry as an array. - * - * @return array Whole Registry - */ - public static function getAll() - { - return self::$registry; - } - - /** - * Removes a variable from the Registry. - * - * @param string $key Name of the variable - * @return bool - */ - public static function remove($key) - { - if (isset(self::$registry[$key])) { - unset(self::$registry[$key]); - return true; - } - return false; - } - - /** - * Removes all variables from the Registry. - * - * @return void - */ - public static function removeAll() - { - self::$registry = array(); - return; - } -} - -?> diff --git a/include/script.js b/include/script.js index 1ba4820..6586980 100644 --- a/include/script.js +++ b/include/script.js @@ -2,17 +2,6 @@ function submit_expert(form) { form.action = form.elements['command'].value + '.' + form.format.value; } -function submit_simple(form) { - var matches = form.elements['rdata'].value.match(/^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$/); - - if (matches) { - form.elements['type'].value = 'A'; - } - else { - form.elements['type'].value = 'URL'; - } -} - function fade(elm) { if (ie) { elm.style.filter = 'alpha(opacity=' + op + ')'; diff --git a/include/uri.php b/include/uri.php index 2bed9b6..ef7cb2a 100755 --- a/include/uri.php +++ b/include/uri.php @@ -40,8 +40,7 @@ class Uri implements Object { * Database */ public function add(Database $db, $lifetime) { - $config = Registry::get('config'); - $db = Registry::get('db'); + global $config; $sql = 'INSERT INTO ' . $config['db']['tbl']['uris'] . ' (host_id, uri, frame, lifetime, last_accessed, created, ip) VALUES( ' . $this->host->id . ', @@ -99,4 +98,3 @@ class Uri implements Object { } } -?> diff --git a/include/zone.php b/include/zone.php index 127e7a2..163b57f 100755 --- a/include/zone.php +++ b/include/zone.php @@ -25,6 +25,7 @@ */ class Zone extends NameServer implements Object { + public $name; private $key; @@ -35,8 +36,8 @@ class Zone extends NameServer implements Object { $this->key = $key; } - protected function initialize() { - parent::initialize(); + protected function initQueue() { + parent::initQueue(); $this->queueCommand('zone ' . $this->name); $this->queueCommand('key ' . $this->key['name'] . ' ' . $this->key['hmac']); @@ -46,8 +47,8 @@ class Zone extends NameServer implements Object { * Maintenance */ function cleanup(Database $db) { - $config = Registry::get('config'); - $output = Registry::get('output'); + global $config; + global $output; // expired records & records without host $sql = 'DELETE r FROM ' . $config['db']['tbl']['records'] . ' AS r @@ -96,13 +97,21 @@ class Zone extends NameServer implements Object { } public function sync(Database $db) { - $output = Registry::get('output'); + global $output; $nsRecords = $this->getRecordsFromNS(); $dbRecords = $this->getRecordsFromDB($db); + $delete = array_diff($nsRecords, $dbRecords); $add = array_diff($dbRecords, $nsRecords); + if (empty($delete) && empty($add)) { + $output->add('ns in sync', 'success'); + return true; + } + + $this->initQueue(); + foreach ($add as $record) { $this->add($record); $output->add('record added to ns', 'success', $record); @@ -112,49 +121,47 @@ class Zone extends NameServer implements Object { $this->delete($record); $output->add('record deleted from ns', 'success', $record); } - } - public function add(Record $record) { - global $output; - $config = Registry::get('config'); + $result = $this->commitQueue(); - if ($record->host->zone->name != $this->name) { - throw new NameServerException('zone mismatch: trying to add record "' . $record . '" to zone "' . $this . '"'); - } - - parent::add($record); - $nsresult = $this->sendQueue(); - - if ($nsresult['code'] != 0) { - throw new NameServerException('error during nameserver update: ' . $nsresult['stderr']); + if ($result['code']) { + throw new NameServerException('error during nameserver update', $result); + } + + if (isAuthentificated()) { + $output->add('ns response', 'debug', 7, $result); // includes key! } + $output->add('ns synced', 'success'); return true; } + public function add(Record $record) { + global $config; + + if ($record->host->zone->name != $this->name) { + throw new NameServerException('zone mismatch: trying to add record ' . $record . ' to zone ' . $this); + } + + parent::add($record); + } + public function delete(Record $record) { - $config = Registry::get('config'); + global $config; if ($record->host->zone->name != $this->name) { throw new NameServerException('zone mismatch: trying to delete record ' . $record . ' from zone ' . $this); } parent::delete($record); - $nsresult = $this->sendQueue(); - - if($nsresult['code'] != 0) { - throw new NameServerException('error during nameserver update: ' . $nsresult['stderr']); - } - - return true; } /* * Getter */ public function getRecordsFromNS() { - $config = Registry::get('config'); - $output = Registry::get('output'); + global $config; + global $output; $records = array(); diff --git a/index.php b/index.php index 39f92eb..a5d01da 100755 --- a/index.php +++ b/index.php @@ -26,11 +26,13 @@ require_once 'include/init.php'; -$filter = array('host' => @$_REQUEST['host'], 'zone' => @$_REQUEST['zone']); -$uris = DBUri::get($db, $filter); +$host = $_REQUEST['host']; +$zone = $_REQUEST['zone']; + +$uris = DBUri::get($db, array('host' => $host, 'zone' => $zone)); if (count($uris) == 1) { - $uri = $uris[0]; + $uri = array_pop($uris); $uri->accessed++; $uri->lastAccessed = time(); @@ -38,7 +40,8 @@ if (count($uris) == 1) { $fullUri = $uri->uri; - if ($_SERVER['REQUEST_URI'] != '/') { + $realHost = substr($_SERVER['HTTP_HOST'], 0 , -(strlen($zone)+1)); + if (!in_array($realHost, array('s', 't')) && $_SERVER['REQUEST_URI'] != '/') { $fullUri .= $_SERVER['REQUEST_URI']; } @@ -62,12 +65,10 @@ else { $qs = '?' . $_SERVER['QUERY_STRING']; } - if (!isAuthentificated()) { - header('Location: simple' . $qs); + if (isAuthentificated()) { + header('Location: /expert' . $qs); } else { - header('Location: expert' . $qs); + header('Location: /simple' . $qs); } } - -?> diff --git a/ip.php b/ip.php index 2d82bce..f9de02b 100755 --- a/ip.php +++ b/ip.php @@ -39,6 +39,3 @@ else { $output->add('your current internet ip address', 'notice', $ip); -$output->send(); - -?> diff --git a/login.php b/login.php index 39a40e9..342f904 100755 --- a/login.php +++ b/login.php @@ -42,13 +42,9 @@ the credentials required.


' . $_SERVER['SERVER_SIGNATURE'] . '
'; - $output->add('authentification failed', 'error', 'user', @$_SERVER['PHP_AUTH_USER']); + throw new AuthentificationException('authentification failed', @$_SERVER['PHP_AUTH_USER']); } else { echo ''; $output->add('authentificated as', 'notice', $_SERVER['PHP_AUTH_USER']); } - -$output->send(); - -?> diff --git a/misc/dynip b/misc/dynip deleted file mode 100755 index 6eaa839..0000000 --- a/misc/dynip +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -## - # SDDNS update script - # - # @copyright 2013 Steffen Vogel - # @license http://www.gnu.org/licenses/gpl.txt GNU Public License - # @author Steffen Vogel - # @link http://www.steffenvogel.de - ## -## - # This file is part of sddns - # - # sddns is free software: you can redistribute it and/or modify - # it under the terms of the GNU General Public License as published by - # the Free Software Foundation, either version 3 of the License, or - # any later version. - # - # sddns is distributed in the hope that it will be useful, - # but WITHOUT ANY WARRANTY; without even the implied warranty of - # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # GNU General Public License for more details. - # - # You should have received a copy of the GNU General Public License - # along with sddns. If not, see . - ## - -################################################################################ -# Requirements -# -# This script requires bash, curl, dig -# -################################################################################ -# Settings - -# Password -PW=Ohsongei6 - -# Hostname -HOST=sea - -# Zone -ZONE=0l.de - -# Interface -IF=eth0 - -# Get ipv6 ip -#IPV6=$(ip -6 -o addr show dev eth0 dynamic scope global | sed -r 's/\s+/\t/g' | cut -f4 | cut -f1 -d/) - -################################################################################ -# Expert settings - -# Time to live value in seconds for the record -TTL=120 - -# Type (A for IPv4, AAAA for IPv6) -TYPE=AAAA - -################################################################################ -# Do not touch anything under this! - -RDATA=$(dig $TYPE $HOST.$ZONE @0l.de +short) - -# 2: eth0 inet6 2a02:908:f318:7201:52e5:49ff:feeb:740c/64 scope global dynamic valid_lft 7200sec preferred_lft 3600sec -REGEX='^[0-9]+: +([^ ]+) +(inet6?) +([^/]+)/([0-9]+) +scope +global +dynamic +valid_lft +([0-9]+)sec +preferred_lft +([0-9]+)sec' - -ip -o monitor address | while read ACTION; do - if [[ ${ACTION} =~ ${REGEX} ]]; then - if [ "${RDATA}" != "${BASH_REMATCH[3]}" ]; then - WAIT=1 - RDATA=${BASH_REMATCH[3]} - URL="http://d.0l.de/update.txt?host=$HOST&zone=$ZONE&ttl=$TTL&class=IN&type=$TYPE&rdata=$RDATA&pw=$PW" - - echo "Updating record: $URL" - while [ $WAIT -lt 60 ] && ! curl "$URL" 2>/dev/null | sed 's/^/ /'; do - sleep $WAIT; # wait until interface is ready - WAIT=$(($WAIT*2)) - done - else - echo "Address hasn't changed: ${RDATA}" - fi - fi -done diff --git a/simple.php b/simple.php index 7a29d24..eab444c 100755 --- a/simple.php +++ b/simple.php @@ -27,49 +27,39 @@ require_once 'include/init.php'; $output = Output::start('html'); ?> +
+
+ /dev/nulll +

Tiny DNS & URL

+
-
- /dev/nulll -

Tiny DNS & URL

-
+
+
+
+
+ . + +
+
+
- -
-
-
- . - -
+ +
+
+ +
-
-
- - -
'; -} -?> - -
- - - -
- - + + +
- -send(); -?> diff --git a/update.php b/update.php index 76a25c6..1b8bb04 100755 --- a/update.php +++ b/update.php @@ -25,104 +25,111 @@ */ require_once 'include/init.php'; + $output = Output::start(); +// default arguments +$ttl = (!empty($_REQUEST['ttl'])) ? $_REQUEST['ttl'] : $config['sddns']['std']['ttl']; +$class = (!empty($_REQUEST['class'])) ? $_REQUEST['class'] : $config['sddns']['std']['class']; +$rdata = (!empty($_REQUEST['rdata'])) ? $_REQUEST['rdata'] : $_SERVER['REMOTE_ADDR']; + +// zone +if (!empty($_REQUEST['zone'])) { + if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { + $zone = $config['sddns']['zones'][$_REQUEST['zone']]; + } + else { + throw new UserException('invalid zone', $_REQUEST['zone']); + } +} +else { + throw new UserException('missing zone'); +} + // password if (!empty($_REQUEST['pw'])) { $pw = $_REQUEST['pw']; } -else { - $pw = false; -} - -// host & zone -if (!empty($_REQUEST['hostname'])) { - foreach ($config['sddns']['zones'] as $z) { - if (substr($_REQUEST['hostname'], -strlen($z->name)) === $z->name) { - $zone = $z; - list($host) = DBHost::get($db, array('host' => substr($_REQUEST['hostname'], 0, -(strlen($zone->name)+1)), 'zone' => $zone)); - } - } -} -elseif (!empty($_REQUEST['host'])) { - if (array_key_exists($_REQUEST['zone'], $config['sddns']['zones'])) { - $zone = $config['sddns']['zones'][$_REQUEST['zone']]; - list($host) = DBHost::get($db, array('host' => $_REQUEST['host'], 'zone' => $zone)); - } -} - -// class -if (!empty($_REQUEST['class']) && in_array($_REQUEST['class'], $config['sddns']['classes'])) - $class = $_REQUEST['class']; - -// type, rdata and ip -if (!empty($_REQUEST['type']) && in_array($_REQUEST['type'], $config['sddns']['types'])) { - $type = $_REQUEST['type']; -} - -// ip -if (!empty($_REQUEST['myip'])) { - $rdata = $_REQUEST['myip']; -} -elseif (!empty($_REQUEST['ip'])) { - $rdata = $_REQUEST['ip']; -} -elseif (!empty($_REQUEST['rdata'])) { - $rdata = $_REQUEST['rdata']; +else if (!empty($_SERVER['PHP_AUTH_PW'])) { + $pw = $_SERVER['PHP_AUTH_PW']; } else { - $rdata = $_SERVER['REMOTE_ADDR']; + throw new AuthentificationException('missing password'); } -if (!empty($zone)) { - if (!empty($host)) { - if ($type == 'URL') { - $entries = DBUri::get($db, array('host' => $host, 'zone' => $zone)); - } - else { - $entries = DBRecord::get($db, array('host' => $host, 'zone' => $zone, 'class' => @$class, 'type' => @$type)); - } +// type +if (!empty($_REQUEST['type'])) { + if (in_array($_REQUEST['type'], $config['sddns']['types'])) { + $type = $_REQUEST['type']; + } + else { + throw new UserException('invalid type'); + } +} +else if (IpV4::isValid($rdata)) { + $type = 'A'; +} +else if (IpV6::isValid($rdata)) { + $type = 'AAAA'; +} +else { + throw new UserException('missing type'); +} - if (count($entries) > 0) { - $output->add('found host', 'success', $host); +// search host +if (!empty($_REQUEST['host'])) { + $host = new Host($_REQUEST['host'], $zone); - if (isAuthentificated() || $host->checkPassword($pw)) { - if ($type == 'URL') { - if (isset($_REQUEST['frame'])) $entries[0]->frame = $_REQUEST['frame']; - - $entries[0]->setUri($rdata); - } - else { - $entries[0]->setRData($rdata); - } - $entries[0]->lastAccessed = time(); - $entries[0]->update(); - - $output->add('entry updated in db', 'success', $entries[0]); - - for ($i = 1; $i < count($entries); $i++) { - $records[$i]->delete(); - $output->add('record deleted from db', 'warning', $entries[$i]); - } - - $zone->cleanup($db); - $zone->sync($db); - } - else { - $output->add('not authentificated for host', 'error', $host); - } - } - else { - $output->add('nothing found to update', 'warning'); - } + if ($host->isRegistred($db)) { + $host = new DBHost($host->isRegistred($db), $db); + $output->add('found existing host', 'success', $host); } else { - $output->add('host not found', 'error', @$_REQUEST['host'], @$_REQUEST['hostname']); + throw new UserException('host not found', $_REQUEST['host']); } } else { - $output->add('zone not found', 'error', $_REQUEST['host'], $_REQUEST['zone']); + throw new UserException('missing host'); } -$output->send(); -?> +if ($host->checkPassword($pw) || isAuthentificated()) { + // search entries + if ($type == 'URL') { + $entries = DBUri::get($db, array('host' => $host, 'zone' => $zone)); + } + else { + $entries = DBRecord::get($db, array('host' => $host, 'zone' => $zone, 'class' => $class, 'type' => $type)); + } + + if (empty($entries)) { + throw new UserException('no records found to update'); + } + + $entry = array_shift($entries); + + if ($type == 'URL') { + $entry->frame = (isset($_REQUEST['frame']) && $_REQUEST['frame']) ? 1 : 0; + $entry->setUri($rdata); + } + else { + $entry->setTtl($ttl); + $entry->setRData($rdata); + } + + $entry->lastAccessed = time(); + $entry->update(); + + $output->add('entry updated in db', 'success', $entry); + + // delete other entries + foreach ($entries as $entry) { + $entry->delete(); + $output->add('record deleted from db', 'warning', $entry); + } + + $zone->cleanup($db); + $zone->sync($db); +} +else { + throw new AuthentificationException('not authentificated for host', $host); +}