mirror of
https://github.com/fernwerker/ownDynDNS.git
synced 2025-07-09 21:55:13 +02:00
* rewrite the hole script:
** use .env file for config so we can retrieve updates ** add config and payload DTO with validators ** allow registrable domains as DynDNS ** update IPv4/6 only if changed (or really forced) ** remove obsolete failed_logins counter ** save logs with timestamp ** save only the newest 100 log entries for each domain
This commit is contained in:
parent
0c58ee7009
commit
05e326abe6
9 changed files with 528 additions and 149 deletions
8
.env.dist
Normal file
8
.env.dist
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
username="max_mustermann"
|
||||||
|
password="s3cr3t"
|
||||||
|
apiKey="netcup DNS API Key"
|
||||||
|
apiPassword="netcup DNS API Password"
|
||||||
|
customerId="netcup customer ID"
|
||||||
|
debug=true
|
||||||
|
log=true
|
||||||
|
logFile=log.json
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.idea
|
||||||
|
.env
|
29
README.md
29
README.md
|
@ -1,32 +1,37 @@
|
||||||
# ownDynDNS
|
# ownDynDNS
|
||||||
Self-hosted dynamic DNS php script for FRITZ!Box and netcup DNS API
|
Self-hosted dynamic DNS php script to update netcup DNS API from Router like AVM FRITZ!Box
|
||||||
|
|
||||||
## Authors
|
## Authors
|
||||||
* Felix Kretschmer [@fernwerker](https://github.com/fernwerker)
|
* Felix Kretschmer [@fernwerker](https://github.com/fernwerker)
|
||||||
* Philipp Tempel [@philipptempel](https://github.com/philipptempel)
|
* Philipp Tempel [@philipptempel](https://github.com/philipptempel)
|
||||||
|
* Branko Wilhelm [@b2un0](https://github.com/b2un0)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
### Installation
|
### Installation
|
||||||
* Copy all files to your webspace
|
* Copy all files to your webspace
|
||||||
* Edit the first lines of update.php
|
* create a copy of `.env.dist` as `.env` and configure:
|
||||||
* username -> The username for your FRITZ!Box to authenticate (so not everyone can update your DNS)
|
* `username` -> The username for your Router to authenticate (so not everyone can update your DNS)
|
||||||
* password -> password for your FRITZ!Box
|
* `password` -> password for your Router
|
||||||
* debug -> enables debug mode and generates output of update.php (normal operation has no output)
|
* `apiKey` -> API key which is generated in netcup CCP
|
||||||
* apiKey -> API key which is generated in netcup CCP
|
* `apiPassword` -> API password which is generated in netcup CCP
|
||||||
* apiPassword -> API password which is generated in netcup CCP
|
* `customerId` -> your netcup Customer ID
|
||||||
|
* `debug` -> true|false enables debug mode and generates output of update.php (normal operation has no output)
|
||||||
|
|
||||||
* Create each host record in your netcup CCP before using the script. The script does not create non-existent records.
|
* Create each host record in your netcup CCP before using the script. The script does not create any missing records.
|
||||||
|
|
||||||
### FRITZ!Box Settings
|
### AVM FRITZ!Box Settings
|
||||||
* Go to "Internet" -> "DynDNS"
|
* Go to "Internet" -> "Freigaben" -> "DynDNS"
|
||||||
* Choose "custom"
|
* Choose "Benutzerdefiniert"
|
||||||
* Update-URL: `https://<url of your webspace>/update.php?user=<username>&password=<pass>&ipv4=<ipaddr>&ipv6=<ip6addr>&domain=<domain>`
|
* Update-URL: `https://<url of your webspace>/update.php?user=<username>&password=<pass>&ipv4=<ipaddr>&ipv6=<ip6addr>&domain=<domain>`
|
||||||
* only the url needs to be adjusted, the rest is automatically filled by the FRITZ!Box
|
* only the url needs to be adjusted, the rest is automatically filled by your AVM FRITZ!Box
|
||||||
* http or https is possible if valid SSL certificate (e.g. Let's Encrypt)
|
* http or https is possible if valid SSL certificate (e.g. Let's Encrypt)
|
||||||
* Domainname: `<host record that is supposed to be updated>`
|
* Domainname: `<host record that is supposed to be updated>`
|
||||||
* Username: `<username as defined in update.php>`
|
* Username: `<username as defined in update.php>`
|
||||||
* Password: `<password as definied in update.php>`
|
* Password: `<password as definied in update.php>`
|
||||||
|
|
||||||
|
# run as cronjob on a **nix based device
|
||||||
|
* see [examples](./examples)
|
||||||
|
|
||||||
## References
|
## References
|
||||||
* DNS API Documentation: https://ccp.netcup.net/run/webservice/servers/endpoint.php
|
* DNS API Documentation: https://ccp.netcup.net/run/webservice/servers/endpoint.php
|
||||||
* Source of dnsapi.php: https://ccp.netcup.net/run/webservice/servers/endpoint.php?PHPSOAPCLIENT
|
* Source of dnsapi.php: https://ccp.netcup.net/run/webservice/servers/endpoint.php?PHPSOAPCLIENT
|
||||||
|
|
25
examples/update-dyndns.sh
Executable file
25
examples/update-dyndns.sh
Executable file
|
@ -0,0 +1,25 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# you can run this script from **ix bases device to update (different) Records
|
||||||
|
|
||||||
|
USER="max_mustermann"
|
||||||
|
PASS="s3cr3t"
|
||||||
|
DOMAIN="my-home-nas.de"
|
||||||
|
#DOMAIN="nas.my-home.de"
|
||||||
|
SCRIPT="https://<url of your webspace>/update.php"
|
||||||
|
FORCE=0
|
||||||
|
|
||||||
|
IPV4=$(curl -4 -q ident.me)
|
||||||
|
IPV6=$(curl -6 -q ident.me)
|
||||||
|
|
||||||
|
echo ${IPV4}
|
||||||
|
echo ${IPV6}
|
||||||
|
|
||||||
|
# PAYLOAD_IPV4="force=${FORCE}&user=${USER}&password=${PASS}&ipv4=${IPV4}&domain=${DOMAIN}"
|
||||||
|
# curl -X POST --data "${PAYLOAD_IPV4}" ${SCRIPT}
|
||||||
|
|
||||||
|
# PAYLOAD_IPV6="force=${FORCE}&user=${USER}&password=${PASS}&ipv6=${IPV6}&domain=${DOMAIN}"
|
||||||
|
# curl -X POST --data "${PAYLOAD_IPV6}" ${SCRIPT}
|
||||||
|
|
||||||
|
PAYLOAD_BOTH="force=${FORCE}&user=${USER}&password=${PASS}&ipv4=${IPV4}&ipv6=${IPV6}&domain=${DOMAIN}"
|
||||||
|
curl -X POST --data "${PAYLOAD_BOTH}" ${SCRIPT}
|
122
src/Config.php
Normal file
122
src/Config.php
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace netcup\DNS\API;
|
||||||
|
|
||||||
|
final class Config
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $apiKey;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $apiPassword;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private $customerId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $logFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $debug;
|
||||||
|
|
||||||
|
public function __construct(array $config)
|
||||||
|
{
|
||||||
|
foreach (get_object_vars($this) as $key => $val) {
|
||||||
|
if (isset($config[$key])) {
|
||||||
|
$this->$key = $config[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
!empty($this->username) &&
|
||||||
|
!empty($this->password) &&
|
||||||
|
!empty($this->apiKey) &&
|
||||||
|
!empty($this->apiPassword) &&
|
||||||
|
!empty($this->customerId) &&
|
||||||
|
!empty($this->logFile);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUsername()
|
||||||
|
{
|
||||||
|
return $this->username;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPassword()
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getApiKey()
|
||||||
|
{
|
||||||
|
return $this->apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getApiPassword()
|
||||||
|
{
|
||||||
|
return $this->apiPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getCustomerId()
|
||||||
|
{
|
||||||
|
return $this->customerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getLogFile()
|
||||||
|
{
|
||||||
|
return $this->logFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isDebug()
|
||||||
|
{
|
||||||
|
return $this->debug;
|
||||||
|
}
|
||||||
|
}
|
181
src/Handler.php
Normal file
181
src/Handler.php
Normal file
|
@ -0,0 +1,181 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace netcup\DNS\API;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
final class Handler
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Config
|
||||||
|
*/
|
||||||
|
private $config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Payload
|
||||||
|
*/
|
||||||
|
private $payload;
|
||||||
|
|
||||||
|
public function __construct(array $config, array $payload)
|
||||||
|
{
|
||||||
|
$this->config = new Config($config);
|
||||||
|
|
||||||
|
if (!$this->config->isValid()) {
|
||||||
|
throw new RuntimeException('configuration invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->payload = new Payload($payload);
|
||||||
|
|
||||||
|
if (!$this->payload->isValid()) {
|
||||||
|
throw new RuntimeException('payload invalid');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
$this->config->getUsername() !== $this->payload->getUser() ||
|
||||||
|
$this->config->getPassword() !== $this->payload->getPassword()
|
||||||
|
) {
|
||||||
|
throw new RuntimeException('credentials wrong');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_readable($this->config->getLogFile())) {
|
||||||
|
$this->log = json_decode(file_get_contents($this->config->getLogFile()), true);
|
||||||
|
} else {
|
||||||
|
$this->log[$this->payload->getDomain()] = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
$this->doExit();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $msg
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
private function doLog($msg)
|
||||||
|
{
|
||||||
|
$this->log[$this->payload->getDomain()][] = sprintf('[%s] %s', date('c'), $msg);
|
||||||
|
|
||||||
|
if ($this->config->isDebug()) {
|
||||||
|
printf('[DEBUG] %s %s', $msg, PHP_EOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doExit()
|
||||||
|
{
|
||||||
|
// save only the newest 100 log entries for each domain
|
||||||
|
$this->log[$this->payload->getDomain()] = array_reverse(array_slice(array_reverse($this->log[$this->payload->getDomain()]), 0, 100));
|
||||||
|
|
||||||
|
if (!is_writable($this->config->getLogFile()) || !file_put_contents($this->config->getLogFile(), json_encode($this->log, JSON_PRETTY_PRINT))) {
|
||||||
|
printf('[ERROR] unable to write %s %s', $this->config->getLogFile(), PHP_EOL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
public function doRun()
|
||||||
|
{
|
||||||
|
$clientRequestId = md5($this->payload->getDomain() . time());
|
||||||
|
|
||||||
|
$dnsClient = new Soap\DomainWebserviceSoapClient();
|
||||||
|
|
||||||
|
$loginHandle = $dnsClient->login(
|
||||||
|
$this->config->getCustomerId(),
|
||||||
|
$this->config->getApiKey(),
|
||||||
|
$this->config->getApiPassword(),
|
||||||
|
$clientRequestId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (2000 === $loginHandle->statuscode) {
|
||||||
|
$this->doLog('api login successful');
|
||||||
|
} else {
|
||||||
|
$this->doLog(sprintf('api login failed, message: %s', $loginHandle->longmessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
$infoHandle = $dnsClient->infoDnsRecords(
|
||||||
|
$this->payload->getHostname(),
|
||||||
|
$this->config->getCustomerId(),
|
||||||
|
$this->config->getApiKey(),
|
||||||
|
$loginHandle->responsedata->apisessionid,
|
||||||
|
$clientRequestId
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
$changes = false;
|
||||||
|
|
||||||
|
foreach ($infoHandle->responsedata->dnsrecords as $key => $record) {
|
||||||
|
$recordHostnameReal = ($record->hostname !== '@') ? $record->hostname . '.' . $this->payload->getHostname() : $this->payload->getHostname();
|
||||||
|
|
||||||
|
if ($recordHostnameReal === $this->payload->getDomain()) {
|
||||||
|
|
||||||
|
// update A Record if exists and IP has changed
|
||||||
|
if ('A' === $record->type && $this->payload->getIpv4() &&
|
||||||
|
(
|
||||||
|
$this->payload->isForce() ||
|
||||||
|
$record->destination !== $this->payload->getIpv4()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$record->destination = $this->payload->getIpv4();
|
||||||
|
$this->doLog(sprintf('IPv4 for %s set to %s', $recordHostnameReal, $this->payload->getIpv4()));
|
||||||
|
$changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update AAAA Record if exists and IP has changed
|
||||||
|
if ('AAAA' === $record->type && $this->payload->getIpv6() &&
|
||||||
|
(
|
||||||
|
$this->payload->isForce()
|
||||||
|
|| $record->destination !== $this->payload->getIpv6()
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$record->destination = $this->payload->getIpv6();
|
||||||
|
$this->doLog(sprintf('IPv6 for %s set to %s', $recordHostnameReal, $this->payload->getIpv6()));
|
||||||
|
$changes = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true === $changes) {
|
||||||
|
$recordSet = new Soap\Dnsrecordset();
|
||||||
|
$recordSet->dnsrecords = $infoHandle->responsedata->dnsrecords;
|
||||||
|
|
||||||
|
$dnsClient->updateDnsRecords(
|
||||||
|
$this->payload->getHostname(),
|
||||||
|
$this->config->getCustomerId(),
|
||||||
|
$this->config->getApiKey(),
|
||||||
|
$loginHandle->responsedata->apisessionid,
|
||||||
|
$clientRequestId,
|
||||||
|
$recordSet
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->doLog('dns recordset updated');
|
||||||
|
} else {
|
||||||
|
$this->doLog('dns recordset NOT updated (no changes)');
|
||||||
|
}
|
||||||
|
|
||||||
|
$logoutHandle = $dnsClient->logout(
|
||||||
|
$this->config->getCustomerId(),
|
||||||
|
$this->config->getApiKey(),
|
||||||
|
$loginHandle->responsedata->apisessionid,
|
||||||
|
$clientRequestId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (2000 === $logoutHandle->statuscode) {
|
||||||
|
$this->doLog('api logout successful');
|
||||||
|
} else {
|
||||||
|
$this->doLog(sprintf('api logout failed, message: %s', $loginHandle->longmessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
156
src/Payload.php
Normal file
156
src/Payload.php
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace netcup\DNS\API;
|
||||||
|
|
||||||
|
final class Payload
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $user;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $domain;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $ipv4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private $ipv6;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $force = false;
|
||||||
|
|
||||||
|
public function __construct(array $payload)
|
||||||
|
{
|
||||||
|
foreach (get_object_vars($this) as $key => $val) {
|
||||||
|
if (isset($payload[$key])) {
|
||||||
|
$this->$key = $payload[$key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValid()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
!empty($this->user) &&
|
||||||
|
!empty($this->password) &&
|
||||||
|
!empty($this->domain) &&
|
||||||
|
(
|
||||||
|
(
|
||||||
|
!empty($this->ipv4) && $this->isValidIpv4()
|
||||||
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
!empty($this->ipv6) && $this->isValidIpv6()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getUser()
|
||||||
|
{
|
||||||
|
return $this->user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getPassword()
|
||||||
|
{
|
||||||
|
return $this->password;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDomain()
|
||||||
|
{
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* there is no good way to get the correct "registrable" Domain without external libs!
|
||||||
|
*
|
||||||
|
* @see https://github.com/jeremykendall/php-domain-parser
|
||||||
|
*
|
||||||
|
* this method is still tricky, because:
|
||||||
|
*
|
||||||
|
* works: nas.tld.com
|
||||||
|
* works: nas.tld.de
|
||||||
|
* works: tld.com
|
||||||
|
* failed: nas.tld.co.uk
|
||||||
|
* failed: nas.home.tld.de
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getHostname()
|
||||||
|
{
|
||||||
|
// hack if top level domain are used for dynDNS
|
||||||
|
if (1 === substr_count($this->domain, '.')) {
|
||||||
|
return $this->domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
$domainParts = explode('.', $this->domain);
|
||||||
|
array_shift($domainParts); // remove sub domain
|
||||||
|
return implode('.', $domainParts);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIpv4()
|
||||||
|
{
|
||||||
|
return $this->ipv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValidIpv4()
|
||||||
|
{
|
||||||
|
return (bool)filter_var($this->ipv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getIpv6()
|
||||||
|
{
|
||||||
|
return $this->ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValidIpv6()
|
||||||
|
{
|
||||||
|
return (bool)filter_var($this->ipv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isForce()
|
||||||
|
{
|
||||||
|
return $this->force;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,10 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
namespace netcup\DNS\API\Soap;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use SoapClient;
|
||||||
|
use SoapFault;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example client to access the domain reselling API.
|
* Example client to access the domain reselling API.
|
149
update.php
149
update.php
|
@ -1,145 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
require_once "dnsapi.php";
|
|
||||||
//
|
|
||||||
// CONFIG SECTION
|
|
||||||
// Info:
|
|
||||||
// Hostname record needs to exist before script is working
|
|
||||||
// This script will not create missing hostnames in the DNS zone
|
|
||||||
//
|
|
||||||
|
|
||||||
$username = "dyndns.username";
|
error_reporting(-1);
|
||||||
$password = "secret";
|
ini_set('display_errors', 1);
|
||||||
$dataFile = "data.json";
|
ini_set('html_errors', 0);
|
||||||
$debug = false;
|
|
||||||
|
|
||||||
// netcup API information
|
header('Content-Type: text/plain; charset=utf-8');
|
||||||
$apiKey = "netcup DNS API Key";
|
|
||||||
$apiPassword = "netcup DNS API Password";
|
|
||||||
$customerId = "netcup customer id";
|
|
||||||
|
|
||||||
//
|
require_once __DIR__ . '/src/Soap.php';
|
||||||
// NO CONFIGURATION BEYOND THIS LINE
|
require_once __DIR__ . '/src/Config.php';
|
||||||
//
|
require_once __DIR__ . '/src/Payload.php';
|
||||||
$getUsername = $_GET['user'];
|
require_once __DIR__ . '/src/Handler.php';
|
||||||
$getPassword = $_GET['password'];
|
|
||||||
$getDomain = $_GET['domain'];
|
|
||||||
$getIpv4 = $_GET['ipv4'];
|
|
||||||
$getIpv6 = $_GET['ipv6'];
|
|
||||||
|
|
||||||
// FUNCTIONS
|
if (!file_exists('.env')) {
|
||||||
// is called to write dataFile and exit
|
throw new RuntimeException('.env file missing');
|
||||||
function write_and_exit(){
|
|
||||||
global $dataFile, $data;
|
|
||||||
if(!@file_put_contents($dataFile, json_encode($data))){
|
|
||||||
echo("[ERROR] unable to write $dataFile <br>");
|
|
||||||
}
|
|
||||||
exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// is called to append log to data object and enable debug output
|
$config = parse_ini_file('.env', false, INI_SCANNER_TYPED);
|
||||||
function logging($text){
|
|
||||||
global $data, $debug, $getDomain;
|
|
||||||
array_push($data[$getDomain]['log'], $text);
|
|
||||||
if($debug == true){
|
|
||||||
echo("[DEBUG] $text <br>");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// function to get domain and reduce host from it
|
|
||||||
function reduceHost($domain){
|
|
||||||
$domainParts = explode('.', $domain);
|
|
||||||
array_shift($domainParts);
|
|
||||||
$tld = implode('.', $domainParts);
|
|
||||||
return $tld;
|
|
||||||
}
|
|
||||||
|
|
||||||
// INIT
|
(new netcup\DNS\API\Handler($config, $_REQUEST))->doRun();
|
||||||
if($debug == true){
|
|
||||||
error_reporting( E_ALL );
|
|
||||||
ini_set('display_errors', 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRESET VALIDATION
|
|
||||||
// get data from object, create if not existent
|
|
||||||
if(file_exists($dataFile)){
|
|
||||||
$data = json_decode(@file_get_contents($dataFile), true);
|
|
||||||
} else {
|
|
||||||
touch($dataFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for domain parameter and exit if NULL
|
|
||||||
if(empty($getDomain)){
|
|
||||||
logging("no domain given. exiting...");
|
|
||||||
write_and_exit();
|
|
||||||
}
|
|
||||||
// init log array
|
|
||||||
$data[$getDomain]['log'] = [];
|
|
||||||
|
|
||||||
// authenticate, store number of failed logins
|
|
||||||
if($getUsername != $username or $getPassword != $password){
|
|
||||||
logging("authentication failed. exiting...");
|
|
||||||
$data[$getDomain]['failed_logins']++;
|
|
||||||
write_and_exit();
|
|
||||||
} else {
|
|
||||||
$data[$getDomain]['failed_logins']=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// DOMAIN SPECIFIC PROCESSING
|
|
||||||
// write current timestamp to data array
|
|
||||||
$data[$getDomain]['timestamp'] = time();
|
|
||||||
|
|
||||||
// validate IP addresses (v4 and v6) and write to data array
|
|
||||||
if(filter_var($getIpv4, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){
|
|
||||||
logging("valid IPv4");
|
|
||||||
// write to data array
|
|
||||||
$data[$getDomain]['ipv4'] = $getIpv4;
|
|
||||||
} else {
|
|
||||||
logging("no valid IPv4");
|
|
||||||
// write to data array
|
|
||||||
$data[$getDomain]['ipv4'] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(filter_var($getIpv6, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){
|
|
||||||
logging("valid IPv6");
|
|
||||||
// write to data array
|
|
||||||
$data[$getDomain]['ipv6'] = $getIpv6;
|
|
||||||
} else {
|
|
||||||
logging("no valid IPv6");
|
|
||||||
// write to data array
|
|
||||||
$data[$getDomain]['ipv6'] = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if($data[$getDomain]['ipv4'] == NULL && $data[$getDomain]['ipv6'] == NULL){
|
|
||||||
logging("no valid IP found");
|
|
||||||
write_and_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// broadcast new IP to DNS API
|
|
||||||
$clientRequestId = md5($getDomain);
|
|
||||||
$dnsClient = new DomainWebserviceSoapClient();
|
|
||||||
$clientHandle = $dnsClient->login($customerId, $apiKey, $apiPassword, $clientRequestId);
|
|
||||||
$infoHandle = $dnsClient->infoDnsRecords(reduceHost($getDomain), $customerId, $apiKey, $clientHandle->responsedata->apisessionid, $clientRequestId);#
|
|
||||||
|
|
||||||
$dnsrecords = $infoHandle->responsedata->dnsrecords;
|
|
||||||
foreach($dnsrecords as $key => &$record){
|
|
||||||
// write IPv4 update set if valid address and existent record
|
|
||||||
if($record->hostname == explode('.', "$getDomain")[0] && $record->type == "A" && $data[$getDomain]['ipv4'] != NULL){
|
|
||||||
$record->destination = $data[$getDomain]['ipv4'];
|
|
||||||
}
|
|
||||||
// write IPv6 update set if valid address and existent record
|
|
||||||
if($record->hostname == explode('.', "$getDomain")[0] && $record->type == "AAAA" && $data[$getDomain]['ipv6'] != NULL){
|
|
||||||
$record->destination = $data[$getDomain]['ipv6'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//$clientHandle->clientrequestid = md5(microtime(true));
|
|
||||||
$recordSet = new Dnsrecordset();
|
|
||||||
$recordSet->dnsrecords = $dnsrecords;
|
|
||||||
|
|
||||||
$updateHandle = $dnsClient->updateDnsRecords(reduceHost($getDomain), $customerId, $apiKey, $clientHandle->responsedata->apisessionid, $clientRequestId, $recordSet);
|
|
||||||
logging("dns recordset updated");
|
|
||||||
|
|
||||||
$result = $dnsClient->logout($customerId, $apiKey, $clientHandle->responsedata->apisessionid, $clientRequestId);
|
|
||||||
logging("api logout");
|
|
||||||
// finish
|
|
||||||
write_and_exit();
|
|
||||||
?>
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue