OpenWRT DDNS: Difference between revisions
mNo edit summary |
|||
(12 intermediate revisions by the same user not shown) | |||
Line 20: | Line 20: | ||
opkg update | opkg update | ||
Client: opkg install ddns-scripts ddns- | Client: opkg install ddns-scripts ddns-scripts-nsupdate luci-app-ddns wget curl * | ||
Server: opkg install bind-server bind-tools (bind-tools includes: bind-rndc bind-check, plus dependencies are all installed)** | Server: opkg install bind-server bind-tools (bind-tools includes: bind-rndc bind-check, plus dependencies are all installed)** | ||
Line 35: | Line 35: | ||
<nowiki>**</nowiki> It is necessary to disable the DNS functionality of DNSMASQ for BIND / NAMED to function properly. If DHCPD is used, and none of DNSMASQ's functionality is necessary, it is highly recommended to remove DNSMASQ instead of disabling it. Odd issues seem to crop up if it remains installed, even if disabled. | <nowiki>**</nowiki> It is necessary to disable the DNS functionality of DNSMASQ for BIND / NAMED to function properly. If DHCPD is used, and none of DNSMASQ's functionality is necessary, it is highly recommended to remove DNSMASQ instead of disabling it. Odd issues seem to crop up if it remains installed, even if disabled. | ||
====Directories and Configuration File Locations==== | |||
*/etc/config/ddns: File for configuring DDNS (this file is the one the LuCI GUI uses, but can be manually edited too) | |||
*/usr/share/ddns: Location for other DDNS items (do not edit these) | |||
*/usr/lib/ddns: Location for DDNS Scripts (do not edit these) | |||
*/tmp/run/ddns (Default storage location for DDNS information, can be changed) | |||
*/tmp/log/ddns (Default location for log files, can be changed) | |||
====DDNS References from OpenWRT==== | |||
Various Options Defined: https://openwrt.org/docs/guide-user/base-system/ddns (keep in mind for this page, it seems to be a bit out of date, there are errors like the stated directory for services files is /usr/lib/ddns/services/"WhatEverFileName" which is actually /usr/share/ddns/list | |||
====Configuration for Client==== | ====Configuration for Client==== | ||
Below is a working /etc/config/ddns configuration file for DDNS Scripts; <syntaxhighlight lang="text"> | Below is a working /etc/config/ddns configuration file for DDNS Scripts (with Domain Names removed); <syntaxhighlight lang="text"> | ||
config ddns 'global' | config ddns 'global' | ||
option ddns_dateformat '%F %R' | option ddns_dateformat '%F %R' | ||
Line 137: | Line 148: | ||
*chown bind:bind /etc/bind (for example, as the location for files can anywhere) | *chown bind:bind /etc/bind (for example, as the location for files can anywhere) | ||
*chmod 644 WhatEverMasterDirectoryForBIND and WhatEverFilesInThatDirectory | |||
The bind User and Group are configured when the bind-server package is installed. If the BIND / NAMED Daemon / Service doesn't have write permissions, the journal file cannot be created. It results in a very, very obscure error in one of the below mentioned log files. | The bind User and Group are configured when the bind-server package is installed. If the BIND / NAMED Daemon / Service doesn't have write permissions, the journal file cannot be created. It results in a very, very obscure error in one of the below mentioned log files. | ||
Line 377: | Line 389: | ||
*https://www.foell.org/justin/diy-dynamic-dns-with-openwrt-bind/ and https://github.com/sleinen/openwrt-nsupdate (Nice examples, but older article, and is seems the DDNS Scripts have essentially addressed the custom DDNS script the authors describe, so don't actually follow the instructions) | *https://www.foell.org/justin/diy-dynamic-dns-with-openwrt-bind/ and https://github.com/sleinen/openwrt-nsupdate (Nice examples, but older article, and is seems the DDNS Scripts have essentially addressed the custom DDNS script the authors describe, so don't actually follow the instructions) | ||
*https://stackoverflow.com/questions/11153958/how-to-enable-named-bind-dns-full-logging (the first person, [https://stackoverflow.com/users/1618161/steven-carr Steven Carr], that answers the question is greate, and I hate, hate, hate the idiot user ( [https://stackoverflow.com/users/1439767/alexsergeyev alexsergeyev]) that replied to this great answer by questioning why it is configured such that the logging to go to separate files. Well alexsergeyev, you're too stupid to understand the answer. So shut up and let smart users like [https://stackoverflow.com/users/1618161/steven-carr Steven Carr] answer the questions and quit bothering them since you have nothing useful to contribute.) | *https://stackoverflow.com/questions/11153958/how-to-enable-named-bind-dns-full-logging (the first person, [https://stackoverflow.com/users/1618161/steven-carr Steven Carr], that answers the question is greate, and I hate, hate, hate the idiot user ( [https://stackoverflow.com/users/1439767/alexsergeyev alexsergeyev]) that replied to this great answer by questioning why it is configured such that the logging to go to separate files. Well alexsergeyev, you're too stupid to understand the answer. So shut up and let smart users like [https://stackoverflow.com/users/1618161/steven-carr Steven Carr] answer the questions and quit bothering them since you have nothing useful to contribute.) | ||
====Testing Things Using NSUPDATE==== | |||
*Create a "Key File" in Bind Format using the Key to test against a BIND / NAMED DDNS server; | |||
<syntaxhighlight lang="text"> | |||
key "WhatEverKeyName" { | |||
algorithm WhatEverAlgorithmType; | |||
secret "WhatEverSecret"; | |||
}; | |||
</syntaxhighlight> | |||
*Create a "Script File" for NSUPDATE (so the individual commands do not need to be entered); | |||
<syntaxhighlight lang="text"> | |||
server IPAddressOrURLofWhatEverDNSServer (Example: 1.2.3.4 My.DNSServer.com) | |||
key WhatEverAlgorithm:KeyName KeySecret (Example hmac-sha256:DDNS weiu1-9{}@#$!adk==) | |||
debug yes | |||
zone WhatEverZoneName.Whatever (Example: google.com) | |||
update add WhatEverHostName.DomainName.DomainSuffix. 86400 CNAME ns1 (Example: www.google.com 86400 CNAME ns1) | |||
show | |||
send | |||
</syntaxhighlight> | |||
*Run the Command: nsupdate -v WhatScriptFileName -y | |||
*Or ''exclude'' the above key directive in the 'Script File", then run the Command: nsupdate -k WhatEverKeyFileName -v WhatScriptFileName -y | |||
====Funky Errors with NSUPDATE?==== | |||
<syntaxhighlight lang="text"> | |||
nsupdate --version | |||
Error loading shared library libisc-9.18.7.so: No such file or directory (needed by /usr/bin/nsupdate) | |||
Error loading shared library libdns-9.18.7.so: No such file or directory (needed by /usr/bin/nsupdate) | |||
Error loading shared library libisccfg-9.18.7.so: No such file or directory (needed by /usr/bin/nsupdate) | |||
Error loading shared library libirs-9.18.7.so: No such file or directory (needed by /usr/bin/nsupdate) | |||
Error loading shared library libbind9-9.18.7.so: No such file or directory (needed by /usr/bin/nsupdate) | |||
</syntaxhighlight>Try reinstalling the bind-libs package: opkg update bind-libs (or remove it and reinstall it, etc.) | |||
Also make sure nslookup is installed: opkg install bind-nslookup | |||
Oh, and just noticed (because generally BIND / NAMED is installed on all documented OpenWRT Routers, not DNSMASQ, it looks like full blown BIND / NAMED must be installed too with DNSMASQ disabled for the Network and Interface Method(s) to function. | |||
===Script Error for NSUPDATE (and possibly other scripts too)=== | |||
If a DDNS update is being sent to a "non-default" port, IE instead of port 53 (udp or tcp), say port 5353, how is that done? | |||
...well, the OpenWRT LuCI interface doesn't give any sort of hint. But, if one looks inside the /usr/lib/ddns/dynamic_dns_lucihelper.sh Script, there's a line that says this: -d DNS-SERVER => dns_server=SERVER[:PORT] | |||
OK, great. The dns_server / DNS-SERVER variable(s) equate to the DNS-Server Field in the LuCI GUI, so the format would be: W.X.Y.Z:WhatEverPort (where W.X.Y.Z can be an IP Address or Host Name) Right? Nope. It will give this error when the DDNS service is restarted: CRIT<span> </span>: sanitize on dns_server found characters outside allowed subset - TERMINATE | |||
<nowiki>Hmmm, what could it be. Ah! "Behind the scenes", the OpenWRT DDNS update scripts are using the NSUPDATE command / binary from BIND / NAMED (look closely at what gets installed when the ddns-scripts-nsupdate package is installed and you'll notice that the bind-tools package is also installed, which includes the NSUPDATE command). So how does NSUPDATE format the IPAddress:Port thing? They use a space, instead of a colon ( : ). From NSUPDATE help: server address [port]</nowiki> | |||
OK, great! So instead of W.X.Y.Z:WhatEverPort, it would be W.X.Y.Z WhatEverPort. Nope. Same error: CRIT<span> </span>: sanitize on dns_server found characters outside allowed subset - TERMINATE | |||
Why is that? | |||
So in conclusion, here's are the issues; | |||
*The LuCI GUI gives no indication of what the Host / IP Address [Port] Syntax should be (maybe because nothing will work) | |||
*The dynamic_dns_lucihelper.sh script has a clear indication of the syntax. But sadly it doesn't work (anymore?, maybe it did in the past or someone has it in mind for the future?). | |||
*The Regular Express in the dynamic_dns_functions.sh script file does not facilitate or allow spaces or colons (it shouldn't allow colons, but should allow a space because the NSUPDATE command allows for spaces), so this makes it impossible to add / change the default DNS port number (which is NECESSARY sometimes!, see comment below) | |||
*The "NSUPDATE Script" that is generated and "temporarily" (it only seems to keep the script there if there is an error, otherwise the IP address is stored there) stored in /tmp/run/ddns/WhateverName.DAT contains the NSUPDATE commands, one line of which is: server W.X.Y.Z [and can have the port number, but isn't put there by OpenWRT's DDNS script, but could be put there, but a space, not a colon is the correct syntax]. This means the "NSUPDATE Script" generated by OpenWRT's DDNS script never has the port number included (but it could). | |||
Solution: Change the "Sanitize Regular Expression" (DNS_CHARSET, about twenty or thirty lines down in /usr/lib/ddns/dynamic_dns_functions.sh) to include a space! | |||
*Current Line of Code: DNS_CHARSET="[@a-zA-Z0-9._-]" | |||
*Should modified to be (allowing a single space to occur in-between an IP Address or Host Name and a Port Number, in the range of allowed port numbers 0-65535); | |||
**Allows multiple spaces anywhere: [@a-zA-Z0-9 ._-] | |||
**Allows a single space in-between the IP Address OR Host Name and Port Number: [@a-zA-Z0-9]*([ ][0-9._-]*) | |||
**To add to the one immediately above, if one wanted to strip spaces before and after, something like this (but NSUPDATE doesn't seem to care, and in fairness doesn't seem to care about multiple spaces in-between the IP / Host and Port); | |||
***[@a-zA-^Z0-9]*([ ][0-9._-]*)[\n]$ | |||
And I must say, it's easy to change the original Regular Expression to allow a space. But to also restrict the position of the space and the range of numbers is tough. So thanks to this site: https://regexr.com/ for making that testing possible. | |||
* | |||
* | |||
It should also be mentioned that there's a comment in the dynamic_dns_functions.sh file that states: # dns character set. "-" must be the last character, so that's why the ._- is at the end of the Regular Expression. Best guess is that it's equivalent to the ; in C or similar type languages, etc. to mark the end of a line. | |||
...didn't want to get too deep into the regular expression stuff, because even the beginning one doesn't check for a valid IPv4 'dotted' IP Address, etc., so there's a limit to the validation here. Decided to cap it at W.X.Y.Z "a single space only here" and a port number. IE, not going to check for or validate a good IPv4 'dotted' IP Address or a Host.DomainName.DomainSuffix, or DomainName.DomainSuffix, etc., again IE, it will be up to the user to establish / know what a valid IPv4 Address is, the proper Domain Name format, and the limit of Port ranges. | |||
Also thought some of the characters in the Regular Expression might need to be escaped with a backslash for the sake of PHP or something, but didn't need to, for example: [@a-zA-^Z0-9]\*\([ ][0-9._-]\*\)[\n]$ | |||
And all of the above might be putting the cart before the horse, so here's the 'cart' (IE, the problem that being able to put in a different port number solves): Some internet providers like Comcast use some type of 'transparent' (in real world terms that would be evil and selfish) DNS proxy service that interferes with OpenWRT DDNS updates. This is a known 'issue' (Google it) was tested extensively to verify (a subject for another article coming soon). | |||
Below is a submission to the OpenWRT maintainer of the code to modify the DDNS code to allow for a custom port number;<syntaxhighlight lang="text"> | |||
Maintainer: Michal Vasilek, AKA paper42 | |||
Environment: OpenWRT 22.03.0 r19685-512e76967f (Linksys WRT3200ACM, Marvell mvebu CortexA9) | |||
Source: feeds/packages/net/ddns-scripts | |||
Section: net | |||
Package Version: 2.8.2-25 (It could be solved in other versions, past and future, but this one has the issue) | |||
Description: Neither the LuCI GUI or editing the /etc/config/ddns File allow for including a custom Port Number for the DNS Server. | |||
Why?: Because there is 'sanitation code' in the dynamic_dns_functions.sh file on line 74 in the form of a Regular Expression Variable definition that prevents this from being done. | |||
The LuCI GUI makes no mention of being able to configure a custom port. However, the dynamic_dns_lucihelper.sh File includes the following line, which implies adding a custom Port Number is allowable or intended or used to be a feature, etc.; | |||
``` | |||
-d DNS-SERVER => dns_server=SERVER[:PORT] | |||
``` | |||
But as noted above, the 'sanitation code' does not allow for a Port Number to be added after the IP Address or Host Name of the DNS Server. | |||
Good News! The underlying BIND / NAMED command (NSUPDATE) that the script uses, does allow for a custom port number to be used, so this should be easy to implement. This is from the NSUPDATE help information: server address [port] (set primary server for zone). | |||
Possible Solution? | |||
The current code for /etc/lib/ddns/dynamic_dns_functions.sh Line 74 is below; | |||
``` | |||
DNS_CHARSET="[@a-zA-Z0-9._-]" | |||
``` | |||
Suggested Change would be to modify the Regular Expression to allow for a single space between the IP Address OR Host and a Port Number; | |||
``` | |||
DNS_CHARSET=[@a-zA-Z0-9]*([ ][0-9._-]*) | |||
``` | |||
Important Note: As noted above the dynamic_dns_lucihelper.sh File specifies: SERVER[:PORT] That should be changed to SERVER [PORT] The simplest solution seems to be to use a space since NSUPDATE uses a space instead of a colon. Even though the convention is to use a colon as a separator between the SERVER and [:PORT], there would have to be additional code written to change the colon to a space for the sake of NSUPDATE. | |||
I'm also assuming since it's a script rather than a compile binary file that the package is the same across all distribution of OpenWRT, so is hopefully a quick fix. This is implied in the package file with this comment in the control section: Architecture: all | |||
And finally: Why make this change? / Why would it be helpful?: There are several internet providers like Comcast X-Finity that impose a 'transparent' DNS proxy service that prevents NSUPDATE, and thus the OpenWRT DDNS Scripts from passing updates to a DNS server like BIND / NAMED. Without going into detail, the proxy service strips out the TSIG information NSUPDATE sends so when it arrives at the destination DNS server, the update or change request is rejected. | |||
Example(s) of some tests of this 'transparent' DNS proxy service are below; | |||
Attempted DDNS update via NSUPDATE via TCP port 53 through Comcast internet; | |||
;; TSIG PSEUDOSECTION: | |||
ddns. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1668702339 300 16 vG1mnvKCwArp+t3IFL5NbQ== 32700 NOERROR 0 | |||
; TSIG error with server: expected a TSIG or SIG(0) | |||
Reply from update query: | |||
;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id: 32700 | |||
;; flags: qr ra; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 | |||
Answer: | |||
;; ->>HEADER<<- opcode: UPDATE, status: REFUSED, id: 32700 | |||
;; flags: qr ra; ZONE: 0, PREREQ: 0, UPDATE: 0, ADDITIONAL: 0 | |||
Attempted DDNS update via NSUPDATE via TCP port 5353 through Comcast internet; | |||
;; TSIG PSEUDOSECTION: | |||
ddns. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1668702432 300 16 U2Zm8vhayWBDSKAB1yJNlg== 50001 NOERROR 0 | |||
Answer: | |||
;; ->>HEADER<<- opcode: UPDATE, status: NOERROR, id: 50001 | |||
;; flags: qr; ZONE: 1, PREREQ: 0, UPDATE: 0, ADDITIONAL: 1 | |||
;; ZONE SECTION: | |||
;fsddns.us. IN SOA | |||
;; TSIG PSEUDOSECTION: | |||
ddns. 0 ANY TSIG hmac-md5.sig-alg.reg.int. 1668702432 300 16 U2Zm8vhayWBDSKAB1yJNlg== 50001 NOERROR 0 | |||
In conclusion, I believe this small modification of the Regular Expression that 'sanitizes' the DNS Server ( DNS-SERVER / dns_server ) Variable(s) and allowing for a custom DNS Port Number to be included could save a lot people from a lot of wasted time. | |||
</syntaxhighlight><br /> |