forked from poweradmin/poweradmin
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dynamic_update.php
238 lines (216 loc) · 7.7 KB
/
dynamic_update.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
<?php
/* Poweradmin, a friendly web-based admin tool for PowerDNS.
* See <http://www.poweradmin.org> for more details.
*
* Copyright 2007-2010 Rejo Zenger <[email protected]>
* Copyright 2010-2014 Poweradmin Development Team
* <http://www.poweradmin.org/credits.html>
*
* This program 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
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Script that handles requests to update DNS records, required for clients
* with dynamic ip addresses
*
* @package Poweradmin
* @copyright 2007-2010 Rejo Zenger <[email protected]>
* @copyright 2010-2016 Poweradmin Development Team
* @license http://opensource.org/licenses/GPL-3.0 GPL
*/
require('inc/config.inc.php');
require('inc/database.inc.php');
require('inc/record.inc.php');
$db = dbConnect();
/** Make sql query safe
*
* @param mixed $value Unsafe Value
*
* @return mixed $value Safe Value
*/
function safe($value)
{
global $db, $db_type;
if ($db_type == 'mysql' || $db_type == 'sqlite') {
$value = $db->quote($value, 'text');
$value = substr($value, 1, -1); // remove quotes
} elseif ($db_type == 'pgsql') {
$value = pg_escape_string($value);
} else {
return status_exit('baddbtype');
}
return $value;
}
/** Get exit status message
*
* Print verbose status message for request
*
* @param string $status Short status message
*
* @return boolean false
*/
function status_exit($status)
{
$verbose_codes = array(
'badagent' => 'Your user agent is not valid.',
'badauth' => 'No username available.',
'badauth2' => 'Invalid username or password. Authentication failed.',
'notfqdn' => 'The hostname you specified was not valid.',
'dnserr' => 'A DNS error has occurred on our end. We apologize for any inconvenience.',
'!yours' => 'The specified hostname does not belong to you.',
'nohost' => 'The specified hostname does not exist.',
'good' => 'Your hostname has been updated.',
'911' => 'A critical error has occurred on our end. We apologize for any inconvenience.',
'nochg' => 'This update was identical to your last update, so no changes were made to your hostname configuration.',
'baddbtype' => 'Unsupported database type',
);
if (isset($_REQUEST['verbose'])) {
$pieces = preg_split('/\s/', $status);
$status = $verbose_codes[$pieces[0]];
}
echo "$status\n";
return false;
}
/** Check whether the given address is an IP address
*
* @param string $ip Given IP address
*
* @return string A if IPv4, AAAA if IPv6 or 0 if invalid
*/
function valid_ip_address($ip)
{
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$value = 'A';
} elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$value = 'AAAA';
} else {
$value = 0;
}
return $value;
}
if (!(isset($_SERVER)) && !$_SERVER['HTTP_USER_AGENT']) {
return status_exit('badagent');
}
// Grab username & password based on HTTP auth, alternatively the query string
if (isset($_SERVER['PHP_AUTH_USER'])) {
$auth_username = $_SERVER['PHP_AUTH_USER'];
} elseif (isset($_REQUEST['username'])) {
$auth_username = $_REQUEST['username'];
}
if (isset($_SERVER['PHP_AUTH_PW'])) {
$auth_password = $_SERVER['PHP_AUTH_PW'];
} elseif (isset($_REQUEST['password'])) {
$auth_password = $_REQUEST['password'];
}
// If we still don't have a username, throw up
if (!isset($auth_username)) {
header('WWW-Authenticate: Basic realm="DNS Update"');
header('HTTP/1.0 401 Unauthorized');
return status_exit('badauth');
}
$username = safe($auth_username);
// FIXME: supports only md5 hashes
$password = md5(safe($auth_password));
$hostname = safe($_REQUEST['hostname']);
// Grab IP to use
$given_ip = "";
$given_ip6 = "";
if (!empty($_REQUEST['myip'])) {
$given_ip = $_REQUEST['myip'];
} elseif (!empty($_REQUEST['ip'])) {
$given_ip = $_REQUEST['ip'];
}
if (!empty($_REQUEST['myip6'])) {
$given_ip6 = $_REQUEST['myip6'];
} elseif (!empty($_REQUEST['ip6'])) {
$given_ip6 = $_REQUEST['ip6'];
}
if (valid_ip_address($given_ip) === 'AAAA') {
$given_ip6 = $given_ip;
}
// Look for tag to grab the IP we coming from
if (($given_ip6 == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'AAAA')) {
$given_ip6 = $_SERVER['REMOTE_ADDR'];
}
if (($given_ip == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'A')) {
$given_ip = $_SERVER['REMOTE_ADDR'];
} elseif (($given_ip == "whatismyip") && (valid_ip_address($_SERVER['REMOTE_ADDR']) === 'AAAA') && (!(valid_ip_address($given_ip6) === 'AAAA'))) {
$given_ip6 = $_SERVER['REMOTE_ADDR'];
}
// Finally get safe version of the IP
$ip = safe($given_ip);
$ip6 = safe($given_ip6);
// Check its ok...
if ((!valid_ip_address($ip)) && (!valid_ip_address($ip6))) {
return status_exit('dnserr');
}
if (!strlen($hostname)) {
return status_exit('notfqdn');
}
$user_query = "
SELECT
users.id
FROM
users, perm_templ, perm_templ_items, perm_items
WHERE
users.username = '$username'
AND users.password = '$password'
AND users.active = 1
AND perm_templ.id = users.perm_templ
AND perm_templ_items.templ_id = perm_templ.id
AND perm_items.id = perm_templ_items.perm_id
AND (
perm_items.name = 'zone_content_edit_own'
OR perm_items.name = 'zone_content_edit_others'
)
";
$user = $db->queryRow($user_query);
if (!$user) {
return status_exit('badauth2');
}
$zones_query = "SELECT domain_id FROM zones WHERE owner='{$user["id"]}'";
$zones_result = $db->query($zones_query);
$was_updated = false;
$no_update_necessary = false;
while ($zone = $zones_result->fetchRow()) {
$zone_updated = false;
$name_query = "SELECT name, type, content FROM records WHERE domain_id='{$zone["domain_id"]}' and type = 'A' OR type = 'AAAA' ";
$result = $db->query($name_query);
while ($record = $result->fetchRow()) {
if ($hostname == $record['name']) {
if (($record['type'] == 'A') && (valid_ip_address($ip) === 'A')) {
if ($ip == $record['content']) {
$no_update_necessary = true;
} else {
$update_query = "UPDATE records SET content ='{$ip}' where name='{$record["name"]}' and type='A'";
$update_result = $db->query($update_query);
$zone_updated = true;
$was_updated = true;
}
} elseif (($record['type'] == 'AAAA') && (valid_ip_address($ip6) === 'AAAA')) {
if ($ip6 == $record['content']) {
$no_update_necessary = true;
} else {
$update_query = "UPDATE records SET content ='{$ip6}' where name='{$record["name"]}' and type='AAAA'";
$update_result = $db->query($update_query);
$zone_updated = true;
$was_updated = true;
}
}
}
}
if ($zone_updated) {
update_soa_serial($zone['domain_id']);
}
}
return (($was_updated || $no_update_necessary) ? status_exit('good') : status_exit('!yours'));