Project

General

Profile

Bug #17096 ยป dyndns-upstream.patch

Alexander Gott, 09/12/2026 01:02 PM

View differences:

etc/inc/dyndns.class
var $_existingRecords;
var $_curlProxy;
/* host routes created by _exec(), see below */
var $_gwRoutes = array();
/*
* Public Constructor Function (added 12 July 05) [beta]
......
unlock($dyndnslck);
}
/* Route requests via the gateway of the monitored interface:
* CURLOPT_INTERFACE only binds the source IP address; locally
* generated traffic still follows the system routing table and
* therefore leaves via the default gateway. Upstreams with
* uRPF/BCP38 filtering silently drop such packets. _exec() now
* resolves the destination of every request, installs temporary
* host routes via the gateway of the monitored interface and
* pins the handle to those addresses (CURLOPT_RESOLVE). */
function _dyndns_gateway() {
if (!function_exists('get_interface_gateway')) {
require_once('gwlb.inc');
}
if ($this->_addressFamilyRequest == AF_INET6) {
$gw = get_interface_gateway_v6($this->_dnsRequestIf);
} else {
$gw = get_interface_gateway($this->_dnsRequestIf);
}
/* gateway group: use the gateway of the currently active member */
if (!is_ipaddr($gw) && function_exists('return_gateway_groups_array')) {
$groups = return_gateway_groups_array(true);
$gw = $groups[$this->_dnsRequestIf][0]['gateway'] ?? '';
}
return $gw;
}
function _gw_route_add($dest) {
$gw = $this->_dyndns_gateway();
if (!is_ipaddr($dest) || !is_ipaddr($gw) ||
(is_ipaddrv4($dest) != is_ipaddrv4($gw))) {
return;
}
/* never manipulate routing for private or reserved destinations */
if (!filter_var($dest, FILTER_VALIDATE_IP,
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
return;
}
$fam = ($this->_addressFamilyRequest == AF_INET6) ? '-inet6' : '';
if (mwexec("/sbin/route {$fam} add -host " . escapeshellarg($dest) .
" " . escapeshellarg($gw), true) == 0) {
/* route created by us, remove it again in _gw_routes_cleanup() */
$this->_gwRoutes[$dest] = true;
} else {
/* route already exists (e.g. leftover from a previous run):
* make sure it points at the correct gateway, but do not
* track it, so foreign static routes survive the cleanup */
mwexec("/sbin/route {$fam} change -host " . escapeshellarg($dest) .
" " . escapeshellarg($gw), true);
}
}
function _gw_routes_cleanup() {
$fam = ($this->_addressFamilyRequest == AF_INET6) ? '-inet6' : '';
foreach (array_keys($this->_gwRoutes) as $dest) {
mwexec("/sbin/route {$fam} delete -host " . escapeshellarg($dest), true);
}
$this->_gwRoutes = array();
}
/* curl_exec() wrapper: sends the request through a temporary host route
* via the monitored interface's gateway instead of the default gateway */
function _exec($ch) {
$url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
$host = trim(strval(parse_url($url, PHP_URL_HOST)), '[]');
$scheme = strtolower(strval(parse_url($url, PHP_URL_SCHEME)));
$port = parse_url($url, PHP_URL_PORT);
$port = empty($port) ? (($scheme == 'https') ? 443 : 80) : $port;
if (($this->_dnsService != 'ods') && !empty($this->_dnsRequestIf)) {
if (is_ipaddr($host)) {
$this->_gw_route_add($host);
} elseif (!empty($host)) {
$records = @dns_get_record($host,
($this->_addressFamilyRequest == AF_INET6) ? DNS_AAAA : DNS_A) ?: array();
$resolve = array();
foreach ($records as $record) {
$ip = ($this->_addressFamilyRequest == AF_INET6) ?
($record['ipv6'] ?? '') : ($record['ip'] ?? '');
if (!is_ipaddr($ip)) {
continue;
}
$this->_gw_route_add($ip);
$resolve[] = "{$host}:{$port}:{$ip}";
}
if (!empty($resolve)) {
/* pin the handle to the addresses we just routed */
curl_setopt($ch, CURLOPT_RESOLVE, $resolve);
}
}
}
$response = curl_exec($ch);
$this->_gw_routes_cleanup();
return $response;
}
function __destruct() {
$this->_gw_routes_cleanup();
}
/*
* Private Function (added 12 July 05) [beta]
* Send Update To Selected Service.
......
// Check if a record already exists for this host.
curl_setopt($ch, CURLOPT_URL, "{$namedotcom_api}?perPage=1000");
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = json_decode(curl_exec($ch), true);
$response = json_decode($this->_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($http_code != "200") {
logger(LOG_ERR, localize_text("Error message: %s", (is_array($response) ? implode('; ', $response) : $response)), LOG_PREFIX_DDNS);
......
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
$response = json_decode(curl_exec($ch), true);
$response = json_decode($this->_exec($ch), true);
$http_code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ($http_code != "200") {
logger(LOG_ERR, localize_text("Error message: %s", (is_array($response) ? implode('; ', $response) : $response)), LOG_PREFIX_DDNS);
......
curl_setopt($ch, CURLOPT_URL, "https://pddimp.yandex.ru/api2/admin/dns/list?domain={$this->_dnsDomain}");
curl_setopt($ch, CURLOPT_HTTPHEADER, array('PddToken: ' . $this->_dnsPass));
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch), true);
$output = json_decode($this->_exec($ch), true);
if (is_array($output["records"])) {
foreach($output["records"] as $record) {
if (($record["domain"] == $this->_dnsDomain) &&
......
$getZoneId = "https://{$dnsServer}/client/v4/zones/?name={$this->_dnsDomain}";
curl_setopt($ch, CURLOPT_URL, $getZoneId);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch));
$output = json_decode($this->_exec($ch));
$zone = $output->result[0]->id;
} else {
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
......
$getHostId = "https://{$dnsServer}/client/v4/zones/{$zone}/dns_records?name={$this->_FQDN}&type={$recordType}";
curl_setopt($ch, CURLOPT_URL, $getHostId);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch));
$output = json_decode($this->_exec($ch));
$host = $output->result[0]->id;
if ($host) { // If host ID was found update host
$hostData = array(
......
curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/login");
curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
//extract the cookies
preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
......
curl_setopt($ch, CURLOPT_URL, "https://www.hover.com/api/dns");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
$pregHost = preg_quote($this->_dnsHost);
$pregDomain = preg_quote($this->_dnsDomain);
preg_match("/^{\"succeeded\":true.*?domain_name\":\"{$pregDomain}.*?entries.*?{\"id\":\"([^\"]*?)\",\"name\":\"{$pregHost}\",\"type\":\"A\".*?\$/", $output, $hostID);
......
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
$last_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
// extract the cookies
......
curl_setopt($ch, CURLOPT_HEADER, 1); //return the full headers to extract the cookies
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
// extract the cookies
preg_match_all("/^Set-cookie: (.*?);/ism", $output, $cookies);
......
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_USERAGENT, $this->_UserAgent);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
$result = json_decode($output, true);
$records = $result['result']['data'];
......
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: Bearer {$this->_dnsPass}"));
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch));
$output = json_decode($this->_exec($ch));
if (!is_array($output->domain_records)) {
$output->domain_records = array();
}
......
echo "getting $_next\n";
curl_setopt($ch, CURLOPT_URL, $_next);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch));
$output = json_decode($this->_exec($ch));
if (!is_array($output->domain_records)) {
$output->domain_records = array();
}
......
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = json_decode(curl_exec($ch));
$output = json_decode($this->_exec($ch));
$recordID = key(get_object_vars($output));
// Step 2: Set the record
......
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_NOBODY, 1);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$output = curl_exec($ch);
$output = $this->_exec($ch);
$pattern = '/Bearer authorization_uri="https:\\/\\/login.windows.net\\/(?<tid>[^"]*)/i';
preg_match($pattern, $output, $result);
if (isset($result['tid'])) {
......
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$server_output = curl_exec($ch);
$server_output = $this->_exec($ch);
$httpcode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
preg_match("/\"access_token\":\"(?<tok>[^\"]*)\"/", $server_output, $result);
if (isset($result['tok'])) {
......
// get domain id
curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains");
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$domains_output = curl_exec($ch);
$domains_output = $this->_exec($ch);
$domains_result = json_decode($domains_output, TRUE);
foreach($domains_result["data"] as $domains_entry) {
if ($domains_entry["domain"] == $this->_dnsDomain) {
......
// get existing record if present
curl_setopt($ch, CURLOPT_URL, "{$linode_api}/domains/{$domain_id}/records");
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$records_output = curl_exec($ch);
$records_output = $this->_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
if ( $http_code != 200 )
{
......
/* Lookup Zone ID */
curl_setopt($ch, CURLOPT_URL, "{$server}/zones");
$response = curl_exec($ch);
$response = $this->_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
logger(LOG_ERR, localize_text("Could not get zone list"), LOG_PREFIX_DDNS);
......
/* Lookup Record ID */
curl_setopt($ch, CURLOPT_URL, "{$server}/zones/{$zone_id}/records");
$response = curl_exec($ch);
$response = $this->_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($http_code != 200) {
logger(LOG_ERR, localize_text("Could not get record list"), LOG_PREFIX_DDNS);
......
set_curlproxy($ch);
}
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$response = $this->_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
......
if ($remove_allowed) {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$response = $this->_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
......
if ($lookup_allowed) {
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FORBID_REUSE, true);
$response = curl_exec($ch);
$response = $this->_exec($ch);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $header_size);
$data = substr($response, $header_size);
    (1-1/1)