├── ip.html
├── data.json
├── .gitignore
├── ip.template.html
├── README.md
└── update.php
/ip.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data.json:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
--------------------------------------------------------------------------------
/ip.template.html:
--------------------------------------------------------------------------------
1 | %IP%
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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);
--------------------------------------------------------------------------------