OpenWRT DDNS: Difference between revisions

mNo edit summary
 
(13 intermediate revisions by the same user not shown)
Line 1: Line 1:
READ THE BELOW "SPECIAL NOTES" SECTION FIRST!!! (to make sure some pre-requisites are taken care of)
This article was written about DDNS (Dynamic DNS (Domain Naming System (''not'' Service))) on OpenWRT, but some of it could apply to DDNS using other platforms.  On the server side, BIND / NAMED is used instead of the default OpenWRT DNS Daemon / Service, DNSMASQ.  DDNS-SCRIPTS is / are the service(s) used on the client side.
This article was written about DDNS (Dynamic DNS (Domain Naming System (''not'' Service))) on OpenWRT, but some of it could apply to DDNS using other platforms.  On the server side, BIND / NAMED is used instead of the default OpenWRT DNS Daemon / Service, DNSMASQ.  DDNS-SCRIPTS is / are the service(s) used on the client side.


Line 22: Line 20:
opkg update
opkg update


Client: opkg install ddns-scripts ddns-scripts_nsupdates luci-app-ddns wget curl *
Client: opkg install ddns-scripts ddns-scripts-nsupdate luci-app-ddns wget curl bind-nslookup ip-full (Reboot after installation)


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)**


If it isn't obvious, the client and server software will not be installed on the same router as DNS server software such as BIND / NAMED rely on having a static IP Address assigned to the OS they're installed on.
If it isn't obvious, the client software will be installed on different devices.  The Server will be running BIND / NAMED and should also have a static IP Address assigned to the WAN interface.


See the BIND / NAMED section in this [[Linksys AC Series Router Configuration Tips for OpenWRT#DNS ( BIND / NAMED )|article]] for additional information on configuration.
See the BIND / NAMED section in this [[Linksys AC Series Router Configuration Tips for OpenWRT#DNS ( BIND / NAMED )|article]] for additional information on configuration.
Line 36: Line 34:
<nowiki>*</nowiki> This OpenWRT [https://openwrt.org/docs/guide-user/services/ddns/client article] discusses and addresses several subjects related to WGET and CURL.  
<nowiki>*</nowiki> This OpenWRT [https://openwrt.org/docs/guide-user/services/ddns/client article] discusses and addresses several subjects related to WGET and CURL.  


<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, on Server installation 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 (and remember, the dns_server directive / option is NOT needed, just extra, it can be left out, but it depends on the RESOLV.CONF file paths to be working, which can be an issue if using DHCPD instead of DNSMASQ, see above notes) <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 64: Line 73:


=====Additional Configuration Example for a Router with Dual WAN Capability=====
=====Additional Configuration Example for a Router with Dual WAN Capability=====
The below example assumes the WAN interfaces (OpenWRT perspective, not from ''ifconfig'' perspective) are "wan" and "wwan", check using IFCONFIG or IP ADDR<syntaxhighlight lang="text">
The below example assumes the WAN interfaces (OpenWRT perspective, not from ''ifconfig'' perspective) are "wan" and "wwan"<syntaxhighlight lang="text">
config ddns 'global'
config ddns 'global'
option ddns_dateformat '%F %R'
option ddns_dateformat '%F %R'
Line 101: Line 110:
'''SPECIAL NOTES;'''
'''SPECIAL NOTES;'''


*'''Watch out if DNSMASQ isn't being used, IE BIND / NAMED and DHCPD are being used instead (see following bullet points for more)'''
*'''Do NOT use Netcat (remove if installed) and use the built in version available in BusyBox or install NCat and create some symbolic links (see following bullet points for more)'''
*The resolv.conf file is NOT 'updated' with a BIND / NAMED and DHCPD installation as it is with DNSMASQ.  Make sure the DHCPD /etc/init.d startup script has been modified to compensate.
**/etc/init.d/dhcpd: ln -sf "/tmp/resolv.conf.d/resolv.conf.auto" /tmp/resolv.conf (in the stop section, see [[Linksys AC Series Router Configuration Tips for OpenWRT|main WRT Series]] article on this subject)
**Also create a symbolic link in Startup
*The OpenWRT DDNS Scripts do NOT like or tolerate dashes or hyphens ( - ) in the service name (IE: ''config service 'What-Ever-Name' will not work and result in nothing showing up in the LuCI GUI)''
*The OpenWRT DDNS Scripts do NOT like or tolerate dashes or hyphens ( - ) in the service name (IE: ''config service 'What-Ever-Name' will not work and result in nothing showing up in the LuCI GUI)''
*DDNS Scripts (and maybe BIND / NAMED) do NOT like or tolerate underscores ( _ ) in the ''lookup_host'' or ''domain'' directives (IE: What_Ever_Host_Name.WhatEverDomain.WhatEverSuffix will cause an error)
*DDNS Scripts (and maybe BIND / NAMED) do NOT like or tolerate underscores ( _ ) in the ''lookup_host'' or ''domain'' directives (IE: What_Ever_Host_Name.WhatEverDomain.WhatEverSuffix will cause an error)
*dns_server Directive / Parameter
**First, below is the official OpenWRT explanation for this setting;<syntaxhighlight lang="text">
Since CC 15.05 Normally the current (in the internet) registered ip is detected using the local defined name lookup policies (i.e. /etc/resolve.conf etc.)
Specify here a DNS server to be used instead of the defaults.
You can use FQDN, hostname or IP address.
</syntaxhighlight><br />
**OK.  Question.  What F*!& does that mean?  Hmmm.  Let's rephrase: By default, the OpenWRT DDNS Client uses the DNS server for the WAN interface (defined via DHCP or as a 'Custom DNS Server')
**...let's go on and actually give an explanation for what the F$J! it does:
**Second, the parameter is NOT needed for DDNS to function properly
**If it is used, make sure the RESOLV.CONF file is configured, available, working, etc. (Hint, if one is using DHCPD instead of DNSMASQ, there has been a change as of v21 or v22 of OpenWRT)
*DHCPD and RESOLV.CONF
**If one chooses to use a ''full'' DNS Server and a full DHCP Server, such as BIND / NAMED and DHCPD, instead of DNSMASQ (perfectly wonderful, great, compact, fast, DNS Server), some issues arise.  See
*NETCAT "Full Version" VS NETCAT "BusyBox" Version VS NCAT
**First issue seems to be that something in OpenWRT v22.x.Whatever breaks NETCAT v0.7.1.  Speaking of NETCAT v0.7.1, the version of NETCAT in OpenWRT v22.x.Whatever is the same as OpenWRT v19.0.x, and earlier.  OpenWRT's problem?  Nope.  Netcat appears to have been last updated in 2004 with 0.7.1 being the latest version.  So what does OpenWRT do?  They do a great job in replacing it with NCAT.  And they keep it updated (v7.70 in OpenWRT 19.0.7 and v7.91 in OpenWRT 22.x.Whatever).  What they don't do is include a script that creates a symbolic link or overriding or whatever needs to be done to replace the version of NETCAT included with BusyBox.  IE, when NETCAT (as in the ancient 0.7.1 version) is installed, that replaces / overrides the BusyBox version of NETCAT.  Not so when installing NCAT.  Why not?  Who knows.  The solution is to do it yourself.  See
**Best as can be determined is that OpenWRT uses the PATH variable to control whether a BUSYBOX version or 'Full" Command version is used.  IE, when a command is run, the /USR/BIN Directory is searched first, if nothing is found, then the BusyBox version of the command is used.  Works great, if that's the strategy.  The really, really big issue is that unlike when installing the NCAT utility is installed, OpenWRT does NOT create a symbolic link from the NC Command to NCAT, instead leaving the NC symbolic link pointing to the Busybox version of the command.  So what should it do?  the below;
***nc > ncat (ln -s /usr/bin/ncat /usr/bin/nc)
***netcat > ncat (ln -s /usr/bin/ncat /usr/bin/netcat)
***Just so you know, the default is nc > ../../bin/busybox (with busybox NC implied)


====Configuration for Server====
====Configuration for Server====
Line 162: 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 402: 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 />