Dynamic DNS for home routers the hacker wayPosted on Oct 28, 2021, seven minutes to read.
Don’t rely on public DDNS services when you can achieve the same with a swiss-army knife in form of Python. In this writeup you will find how to modify DNS record, how to upload a zone file over ssh and how to expose it as a simple web service. All that using Python.
I have a Mikrotik router that gets a dynamic public IP address. I give it a domain name on my primary DNS, and my goal is to keep it up-to-date. Initially, I thought of pulling a dynamic DNS using a standard protocol. After some research, I had to abandon this idea. Mikrotik’s also provide a way to use their cloud services to get the similar result, yet I find it less convenient compared to my custom solution.
After a little research I came across a way to modify the zonefile using Python which lead me to the solution described in this post.
Modify DNS zone file
Python has a library for every possible problem. In this case, I am using
dnspython. In the examples below, I will only cover IPv4. Yet, I am
confident it’s a simple update to extend the solution to cover also IPv6.
In a nutshell, the solution can be summarized as follows:
- open the zone file
- modify the record
- store the file back
To put that in Python:
As for the actual update, it’s pretty straightforward as well:
- load a zonefile
- find the proper record
- modify the record - stop the operation if there’s no change
- update SOA
- convert the updated zone to string to return
Do not forget the SOA update. Without it, other DNS servers in your zone will not detect the change.
As for the details, I will post my code here. The
does the job, but the API is not my favourite cup of tea.
As for the SOA record, I keep the version as a date (
%Y%m%d) and a revision number.
So, if the date is still today, I increment the revision. If not, I start from zero for today.
Upload the zone file and reload DNS
Alright, the zone file is up-to-date, and now we are eager to publish it. By hand, you could ssh to the DNS server, update the file there and reload the server. That’s precisely the process I’ll cover with Python now.
Create a REST API
At this moment, we can update a zone file and upload it to the DNS server to perform a zone update. Now let’s put it all together.
Our happy execution path looks like this
keyfile come from config.
As I hinted already, the whole update is done via REST API. The router will send us a request, and based on that, we do a DNS update.
For security, the IP address to use will be taken from the request and the router will identify itself using a JWT token.
I am using
Flask to setup the API and
flask_jwt_extended for JWT.
In this example I will create new tokens each time the app is started
The endpoint with a happy execution path can look like this:
Once deployed, we set up a periodic call to such API from our Mikrotik. Keep in mind that you should at least add exception handling and input validation in the endpoint handler. I skipped those for conciseness.