DDNS: Membuat Sendiri
Sumber: http://andrwe.org/linux/own-ddns
HOW-TO: be your own DDNS provider Summary
This how-to explains a way to build your own dynamic DNS server. Main
Hi, since some time my DDNS provider has problems which cause the loss of the connection to my home server. To prevent this loss I've read some manpages and build my own DDNS server.
- !: This is not a how-to about DNS, bind or any other software I've used. :!:
Warranty There is no warranty that this how-to works for any system. I'm just providing these information because it worked for me this way. If you have questions you can leave a message here but I decide whether I'll answer and help or not.
Requirements:
own server with static IP own domain resolving (e.g.: example.org) subdomain delegated to to your server (e.g.: dyndns.example.org) php5 webserver supporting PHP (I use Lighttpd, but any will do) bind>=9 dnsutils
Configurations
You have to change all 'dyndns.example.org' to your domain. bind
the bind user requires write-access to bind working directory:
// named.conf options { ... ; working directory of bind directory "/var/named"; ... };
chmod 770 /var/named/
we generate a TSIG-key in a new directory which is used to verify the server and client:
mkdir -p /etc/named/ cd /etc/named/ dnssec-keygen -a hmac-sha512 -b 512 -n HOST dyndns.example.org # webserver-group needs read access to file containing TSIG-key chown root:<webserver-group> /etc/named/Kdyndns.example.org*.private chmod 640 /etc/named/Kdyndns.example.org*.private # get and remember the key grep Key /etc/named/Kdyndns.example.org*.private
create zone in named.conf
key mykey { algorithm hmac-sha512; secret "the-generated-key"; }; zone "dyndns.example.org" IN { type master; file "dyndns.example.org.zone"; allow-query { any; }; allow-transfer { none; }; allow-update { key mykey; }; };
create zone-file
/var/named/dyndns.example.org.zone
$ORIGIN . $TTL 86400 ; 1 day dyndns.example.org IN SOA localhost. root.localhost. ( 52 ; serial 3600 ; refresh (1 hour) 900 ; retry (15 minutes) 604800 ; expire (1 week) 86400 ; minimum (1 day) ) NS localhost. $ORIGIN dyndns.example.org.
Webserver
Create a subdomain (dyndns.example.org) and a vhost for the updating script. For security purpose and compatibility of the php-script the vhost has to be protected by http-authentication. For Lighttpd you can use the script provided here to generate the users. Save this PHP-script in the vhost-directory:
index.php
<?php // configuration of user and domain $user_domain = array( 'user' => array('subdomain','sub2'), 'user2' => array('sub4') ); // main domain for dynamic DNS $dyndns = "dyndns.example.org"; // DNS server to send update to $dnsserver = "localhost"; // port of DNS server $dnsport = ""; // short sanity check for given IP function checkip($ip) { $iptupel = explode(".", $ip); foreach ($iptupel as $value) { if ($value < 0 || $value > 255) return false; } return true; } // retrieve IP $ip = $_SERVER['REMOTE_ADDR']; // retrieve user if ( isset($_SERVER['REMOTE_USER']) ) { $user = $_SERVER['REMOTE_USER']; } else if ( isset($_SERVER['PHP_AUTH_USER']) ) { $user = $_SERVER['PHP_AUTH_USER']; } else { syslog(LOG_WARN, "No user given by connection from $ip"); exit(0); } // open log session openlog("DDNS-Provider", LOG_PID | LOG_PERROR, LOG_LOCAL0); // check for given domain if ( isset($_POST['DOMAIN']) ) { $subdomain = $_POST['DOMAIN']; } else if ( isset($_GET['DOMAIN']) ) { $subdomain = $_GET['DOMAIN']; } else { syslog(LOG_WARN, "User $user from $ip didn't provide any domain"); exit(0); } // check for needed variables if ( isset($subdomain) && isset($ip) && isset($user) ) { // short sanity check for given IP if ( preg_match("/^(\d{1,3}\.){3}\d{1,3}$/", $ip) && checkip($ip) && $ip != "0.0.0.0" && $ip != "255.255.255.255" ) { // short sanity check for given domain if ( preg_match("/^[\w\d-_\*\.]+$/", $subdomain) ) { // check whether user is allowed to change domain if ( in_array("*", $user_domain[$user]) or in_array($subdomain, $user_domain[$user]) ) { if ( $subdomain != "-" ) $subdomain = $subdomain . '.'; else $subdomain = ; // shell escape all values $subdomain = escapeshellcmd($subdomain); $user = escapeshellcmd($user); $ip = escapeshellcmd($ip); // prepare command $data = "<<EOF server $dnsserver $dnsport zone $dyndns update delete $subdomain$user.$dyndns A update add $subdomain$user.$dyndns 300 A $ip send EOF"; // run DNS update exec("/usr/bin/nsupdate -k /etc/named/K$dyndns*.private $data", $cmdout, $ret); // check whether DNS update was successful if ($ret != 0) { syslog(LOG_INFO, "Changing DNS for $subdomain$user.$dyndns to $ip failed with code $ret"); } } else { syslog(LOG_INFO, "Domain $subdomain is not allowed for $user from $ip"); } } else { syslog(LOG_INFO, "Domain $subdomain for $user from $ip with $subdomain was wrong"); } } else { syslog(LOG_INFO, "IP $ip for $user from $ip with $subdomain was wrong"); } } else { syslog(LOG_INFO, "DDNS change for $user from $ip with $subdomain failed because of missing values"); } // close log session closelog(); ?>
Usage
If you've configured all correctly you can update domains using this command:
wget --no-check-certificate --http-user="user" --http-passwd="password" --post-data "DOMAIN=example" -q https://dyndns.example.com
Some examples:
Script configuration:
$user_domain = array( 'user' => array('subdomain') ); $dyndns = "dyndns.example.org"
Result: The user 'user' can update the IP for the domain subdomain.user.dyndns.example.org.
Script configuration:
$user_domain = array( 'user' => array('subdomain'), 'user2' => array('test', 'foobar') ); $dyndns = "dyndns.example.org"
Result: The user 'user' can update the IP for the domain subdomain.user.dyndns.example.org. The user 'user2' can update the IP for the domains test.user2.dyndns.example.org and foobar.user2.dyndns.example.org.
Script configuration:
$user_domain = array( 'user' => array('*'), 'user2' => array('test', 'foobar') ); $dyndns = "dyndns.example.org"
Result: The user 'user' can update the IP for the wildcard domain *.user.dyndns.example.org which means all subdomains of user.dyndns.example.org are resolved to the IP set for *. The user 'user2' can update the IP for the domains test.user2.dyndns.example.org and foobar.user2.dyndns.example.org.
Script configuration:
$user_domain = array( 'user' => array('-','subdomain'), 'user2' => array('test', 'foobar') ); $dyndns = "dyndns.example.org"
Result: The user 'user' can update the IP for the domains subdomain.user.dyndns.example.org and user.dyndns.example.org. The user 'user2' can update the IP for the domains test.user2.dyndns.example.org and foobar.user2.dyndns.example.org.