├── .gitignore ├── README.md ├── data.json ├── ip.html ├── ip.template.html └── update.php /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Dynamic DNS Server 2 | ================== 3 | 4 | Upload this script to any PHP-enabled webspace and let FritzBox call it. *It will work with other DynDNS-Clients as well.* 5 | 6 | Usage 7 | ----- 8 | * Upload everything to your webspace 9 | * (you may want to hide data.json and ip.template.html from your webroot) 10 | * Update the config section in update.php 11 | * Update your Dynamic DNS FritzBox settings 12 | * If you want to broadcast the new IP to other services (e.g. your domain registrar or whatever) look for @todo and implement it here 13 | 14 | Domain Registrar APIs (@todo) 15 | ----------------------------- 16 | * https://www.inwx.de/de/download/file/api-current.zip 17 | * http://blog.philippklaus.de/blog/2011/05/31/access-the-internetworx-xml-rpc-api-via-python/ 18 | * https://github.com/pklaus/python-inwx-xmlrpc 19 | * http://patrick.oberdorf.net/2011/10/07/inwx-de-als-dyndns/ 20 | 21 | FritzBox 7360 Settings 22 | ---------------------- 23 | 24 | Name | Value 25 | ------------ | ------------- 26 | Update-URL | [http://example.com/update.php?ip4addr=<ipaddr>&ip6addr=<ip6addr>&user=<username>&password=<pass>&domain=<domain>](http://example.com) 27 | Domain | anything you want, but make sure its a valid URL, e.g. www.example.com 28 | User | username from your config (in update.php) 29 | Password | password from your config (in update.php) 30 | 31 | Example URL calls 32 | ----------------- 33 | * `http://example.com/update.php?user=XXX&password=XXX&ip4addr=0.0.0.0&ip6addr=0:0:0:0:0:0:0:0` 34 | * `http://example.com/update.php?user=XXX&password=XXX&ip4addr=0.0.0.0` 35 | * `http://example.com/update.php?user=XXX&password=XXX&ip6addr=0:0:0:0:0:0:0:0` 36 | * `http://example.com/update.php?user=XXX&password=XXX&reset=1` 37 | * `http://example.com/ip.html (if IP_HTML_PAGE is set)` 38 | 39 | License 40 | ------- 41 | Copyright 2012 Matthias Kadenbach 42 | Released under the MIT license 43 | 44 | 45 | -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattes/php-dynamic-dns-server/4cd7822a7c3dff78621339971bd086d2f85dddf6/data.json -------------------------------------------------------------------------------- /ip.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mattes/php-dynamic-dns-server/4cd7822a7c3dff78621339971bd086d2f85dddf6/ip.html -------------------------------------------------------------------------------- /ip.template.html: -------------------------------------------------------------------------------- 1 | %IP% -------------------------------------------------------------------------------- /update.php: -------------------------------------------------------------------------------- 1 | &ip6addr=&user=&password=&domain= 19 | * Domain: anything you want, but make sure its a valid URL, e.g. www.example.com 20 | * User: your username from your config below 21 | * Password: your password from your config below 22 | * 23 | */ 24 | 25 | // ------------------------------- 26 | // --- CONFIG -------------------- 27 | // ------------------------------- 28 | 29 | // set error reporting 30 | // E_ALL for debug, 0 for production 31 | error_reporting(E_ALL); 32 | 33 | // root directory with trailing slash! 34 | define("ROOT", dirname(__FILE__) . "/"); 35 | 36 | // data file in json format, you may want to hide it from webroot 37 | // make file writeable! 38 | define("DATA_FILE_PATH", ROOT . "data.json"); 39 | 40 | // create a html page with the current ip address 41 | // set to false to disable, make file writeable! 42 | define("IP_HTML_PAGE", ROOT . "ip.html"); 43 | 44 | // set an username 45 | define("USERNAME", "aladin"); 46 | 47 | // set a secure password 48 | define("PASSWORD", "magic"); 49 | 50 | // lock user after number of failed login attempts 51 | // if user got locked empty data.json manually 52 | define("MAX_FAILED_LOGINS_BEFORE_LOCK", 5); 53 | 54 | // use ip version 4 or 6? 55 | define("USE_IPV", "4"); 56 | 57 | // ------------------------------- 58 | // ------------------------------- 59 | 60 | // Set the HTTP response code 61 | if(!function_exists("http_response_code")) { 62 | function http_response_code($response_code = 200) { 63 | header(':', true, $response_code); 64 | return $response_code; 65 | } 66 | } 67 | 68 | // helper to check used IP version 69 | function ipv($v) { 70 | return $v == USE_IPV; 71 | } 72 | 73 | // send http status code and return text 74 | function send_status_and_exit($code, $text) { 75 | // see https://ssl.tiggerswelt.net/wiki/ddns/informationen_fuer_entwickler for return codes. 76 | // no idea where this is really specified... 77 | http_response_code($code); 78 | echo $text; 79 | exit(); 80 | } 81 | 82 | // ------------------------------- 83 | 84 | // check if files are writeable 85 | if(!is_writable(DATA_FILE_PATH) || !is_writable(IP_HTML_PAGE)) send_status_and_exit(500, "911 server is unable to write to files"); 86 | 87 | // load and restore values from data file 88 | $data = json_decode(@file_get_contents(DATA_FILE_PATH), true); 89 | if(!$data) { 90 | $data = array("current_ip4addr" => null, "current_ip6addr" => null, "last_update_timestamp" => null, "failed_logins" => 0); 91 | } 92 | 93 | // check failed logins and if username or password are not correct 94 | if($data["failed_logins"] > MAX_FAILED_LOGINS_BEFORE_LOCK || empty($_GET["user"]) || $_GET["user"] != USERNAME || empty($_GET["password"]) || $_GET["password"] != PASSWORD) { 95 | $data["failed_logins"]++; 96 | 97 | // write changes to file 98 | if(!file_put_contents(DATA_FILE_PATH, json_encode($data))) send_status_and_exit(500, "911 server is unable to write data file"); 99 | 100 | send_status_and_exit(401, "badauth"); 101 | } 102 | 103 | // if login was successful reset failed logins counter (lazily, because other errors may break process before save) 104 | $data["failed_logins"] = 0; 105 | 106 | // reset ips? 107 | if(!empty($_GET["reset"])) { 108 | $_GET["ip4addr"] = "0.0.0.0"; 109 | $_GET["ip6addr"] = "0:0:0:0:0:0:0:0"; 110 | } 111 | 112 | // get ip4 and ip6 address 113 | $ip4addr = filter_var((!empty($_GET["ip4addr"]) ? $_GET["ip4addr"] : null), FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); 114 | $ip6addr = filter_var((!empty($_GET["ip6addr"]) ? $_GET["ip6addr"] : null), FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); 115 | 116 | // if ip is invalid 117 | if(!$ip4addr && ipv(4)) send_status_and_exit(500, "911 ip4addr invalid"); 118 | if(!$ip6addr && ipv(6)) send_status_and_exit(500, "911 ip6addr invalid"); 119 | 120 | // if ip didnt change 121 | if($ip4addr == $data["current_ip4addr"] && ipv(4)) send_status_and_exit(200, "nochg " . $ip4addr); 122 | if($ip6addr == $data["current_ip6addr"] && ipv(6)) send_status_and_exit(200, "nochg " . $ip6addr); 123 | 124 | // fritzbox sends $_GET["domain"], too. ignore it. 125 | 126 | // write changes to data file 127 | $data["last_update_timestamp"] = time(); 128 | $data["current_ip4addr"] = $ip4addr; 129 | $data["current_ip6addr"] = $ip6addr; 130 | if(!@file_put_contents(DATA_FILE_PATH, json_encode($data))) send_status_and_exit(500, "911 server is unable to write data file"); 131 | 132 | // create ip html page 133 | if(IP_HTML_PAGE) { 134 | $html = @file_get_contents(ROOT . "ip.template.html"); 135 | if($html === false) send_status_and_exit(500, "911 server is unable to read ip.template.html"); 136 | 137 | if(ipv(4)) $html = str_replace(array("%IP%"), array($ip4addr), $html); 138 | if(ipv(6)) $html = str_replace(array("%IP%"), array($ip6addr), $html); 139 | 140 | if(!@file_put_contents(IP_HTML_PAGE, $html)) send_status_and_exit(500, "911 server is unable to create ip html page"); 141 | } 142 | 143 | // ready to broadcast the ip somewhere else ... 144 | 145 | // @todo 146 | 147 | 148 | // success! 149 | if(ipv(4)) send_status_and_exit(200, "good " . $ip4addr); 150 | if(ipv(6)) send_status_and_exit(200, "good " . $ip6addr); --------------------------------------------------------------------------------