skip to content

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

< System

User Comments

Post your comment or question

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>

top