30 python lines Dynamic DNS
by Emile `iMil' Heitor - 2017-02-20
Here in Spain, I chose Movistar as my Internet provider, I must say I’m pretty happy with it, symmetric 300Mbps fiber optics and good service. The only annoying aspect is that they do not provide static IP for free, something I was used to and was very convenient.
In order to reach my network from places where I can’t connect to my VPN, I wrote a very simple Dynamic DNS system using dnspython, and it turned out to be fairly easy.
This is the code running on my public server:
$ cat ddns.py
from flask import Flask
import dns.update
import dns.query
import dns.tsigkeyring
import dns.resolver
app = Flask(__name__)
@app.route('/query/<t>/<fqdn>')
def query(t, fqdn):
resolver = dns.resolver.Resolver(configure=False)
resolver.nameservers = ['127.0.0.1']
answer = dns.resolver.query(fqdn, t)
if t == 'a':
return '{0}\n'.format(answer.rrset[0].address)
@app.route("/update/<domain>/<host>/<ip>", methods=['POST'])
def update(domain, host, ip):
keyring = dns.tsigkeyring.from_text({
'rndc-key' : 'myRNDCkey=='
})
update = dns.update.Update('{0}.'.format(domain), keyring=keyring)
update.replace(host, 300, 'A', ip)
response = dns.query.tcp(update, '127.0.0.1', timeout=10)
return "update with {0}\n".format(ip)
if __name__ == "__main__":
app.run()
This code is served by gunicorn:
$ gunicorn ddns:app
Behind an nginx reverse proxy:
location /dyndns/ {
auth_basic "booh.";
auth_basic_user_file /etc/nginx/htpasswd;
proxy_pass http://private-server:8000/;
}
On the client side (home), I wrote this very simple shell script:
#!/bin/sh
PATH=${PATH}:/sbin:/usr/sbin:/bin:/usr/bin:/usr/pkg/bin
name="mybox"
domain="mydomain"
fqdn="${name}.${domain}"
auth="user:mymagicpassword"
# here retrieve your actual public IP from a website like httpbin.org
curip=$(curl -s -o- http://some.website.like.httpbin.org/ip)
# fetch recorded IP address
homeip=$(curl -u ${auth} -s -o- https://my.public.server/dyndns/query/a/${fqdn})
if [ "${curip}" != "${homeip}" ]; then
warnmsg="/!\\ home IP changed to ${curip} /!\\"
echo "${warnmsg}"|mail -s "${warnmsg}" me@mydomain.net
curl -u ${auth} \
-X POST https://my-public.server/dyndns/update/${domain}/${name}/${curip}
fi
Which is cron’ed to run every 5 minutes.
And here I am with my own cheap Dynamic DNS system.