System: Apache authorization with dynamic DNS
We've previously discussed the new Apache authorization schemes, presenting examples such as the following:
<RequireAll>
Require host example.org
Require not host blocked.example.org
</RequireAll>
When host is used in this way Apache will:
do a reverse DNS lookup on the IP address to find the associated hostname, and then do a forward lookup on the hostname to assure that it matches the original IP address.
This is great when you have a fixed IP address and properly configured DNS so that both the reverse and forward lookups return a valid response.
Apache2 Require host
Here you can see an example where host authentication will work out of the box:
$ host 8.8.8.8
8.8.8.8.in-addr.arpa domain name pointer google-public-dns-a.google.com.
$ host google-public-dns-a.google.com
google-public-dns-a.google.com has address 8.8.8.8
The highlighted addresses need to match, where the first is your browser ip address.
Where it all falls apart is for users with a dynamic ip address. Even if you have yourname.ddns.net pointing to your allocated IP address, a reverse lookup on the ip address will return something like dialup-123.example.net pointing to your ISP, so authentication will fail.
Tricking Apache
On our servers we're able to get around the problem of the reverse lookup by defining the dynamic address in our local /etc/hosts file:
127.0.0.1 localhost.localdomain localhost
...
# dyndns
1.2.3.XXX yourname.ddns.net
...
Now a lookup on our IP address (1.2.3.XXX) will return the dynamic address configured in /etc/hosts. The only problem being that we have to manually update /etc/hosts every time the router restarts.
Automatically updating /etc/hosts
This is where the magic comes in. We have set up a CRON script running every few minutes to check whether our DDNS address has updated, and if it has, to automatically update /etc/hosts with the new details:
#!/bin/bash
# script filename: /usr/local/sbin/ddns-update-hosts
# update DDNS ip address in /etc/hosts
HOSTS=/etc/hosts
TLD=ddns.net
DDNS="yourname.$TLD"
OLDIP=$(getent hosts $DDNS | awk '{print $1}')
# find authoritative name servers
DNSAUTH=$(dig +short ns $TLD | head -1 | egrep "^[a-z0-9.-]+\.$")
[ -z $DNSAUTH ] && echo "Error: Could not find authoritative name servers for $TLD" && exit 1
# query DNSAUTH for DDNS ip address
NEWIP=$(dig +short $DDNS @$DNSAUTH | egrep "^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$")
[ -z $NEWIP ] && echo "Error: Could not retrieve IP address for $DDNS from $DNSAUTH" && exit 1
# DDNS ip already correct in HOSTS file - no action needed
egrep -q "^$NEWIP\s+$DDNS$" $HOSTS && exit 0
# replace ip address in HOSTS file
sed -ri.bak "s/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+(\s+$DDNS)$/$NEWIP\1/" $HOSTS
echo "Success: Updated /etc/hosts $DDNS from $OLDIP to $NEWIP - previous version backed up to $HOSTS.bak"
Our script actually goes on to update some iptables chains to accept our DDNS address, but that's another story.
You will need a dynamic dns provider, of which there are many, and they will provide tools for updating the DNS records - usually called automatically by your router or manually using a Desktop app.
You will also need to add the 'dyndns' line/s described above to /etc/hosts before running the update script.
Dynamic DNS in PHP authentication
With our dynamic ip address hard-wired into /etc/hosts we can easily identify ourselves using PHP:
<?PHP
if(gethostbyaddr($_SERVER['REMOTE_ADDR']) == "yourname.ddns.net") {
// user recognised
}
?>
Even if you do have a static IP address, this may be a better approach than having it hard-coded in your PHP scripts.
Require forward-dns
If you're lucky enough to be running Apache 2.4.19 then a new authorization option forward-dns is available.
Require forward-dns yourname.ddns.net
Using this option a reverse DNS lookup is not used. As long as the forward look on the host name returns your (dynamic) ip address you will be granted access.
In this case the above changes to /etc/hosts and the CRON script should not be necessary.
References
Related Articles - Apache 2.4
- System Authenticating Apache Logins with PostgreSQL
- System Access authorization in Apache 2.4
- System Apache authorization with dynamic DNS
- System Re-naming vhost files to *.conf for Apache 2.4
- System Blocking Fake Googlebot and bingbot spiders
JJ 4 February, 2022
Thanks for this article. But I'm not having any luck getting the `Require forward-dns mydynamicdomain` to work.
What all should I add to my /etc/phpmyadmin/apache.conf to make it work?
Not sure. Perhaps something like this?
<Directory /usr/share/phpmyadmin>
Require forward-dns mydynamicdomain
</Directory>