I think it is safe to say that most of IT professionals have some kind of lab environment and many of us have some kind of lab at home. Sometimes it is necessary to use resources from that lab outside of the house, which means they need to be exposed to the Internet and you should be able to reach them with relative ease. In my mind, home internet connection tend to have 2 main problems: 1) In some regions they simply don’t provide public IPv4 address, 2) IP addresses are dynamic and can change daily or even more often.
Traditional DDNS services can handle the issue #2 for IPv4 addresses, but there are very few services that do dynamic DNS for IPv6 for free. And even when they do – often times logical and simply to remember domain names are taken, which leads to some very non-intuitive names for services. So generally speaking, you may want to register your own domain and luckily it doesn’t cost that much.
Solution to the problem
Cloudflare is mainly a CDN provider, but they do offer DNS services as well, they have very nice API and most importantly – their free tier service does more than enough to solve the problem at hand. You can (and should) utilize their CDN functionality for web services, adding some caching and DDoS protection to them, as well as allowing you to host your services only via IPv6 and have Cloudflare proxy it to both IPv6 and IPv4 clients. One little issue – they don’t have DDNS client. But it shouldn’t be that hard to write your own, right?
A few more things to consider
Before starting to write the code though, there are a couple of more things that need to be figured out.
First of all, your host is very unlikely to have a public IPv4 address, so you need to figure out what it is. Luckily that’s not a problem – there are lots of services that would report the IP you are coming from, so you can just query one. As I discovered later, you need to do the same for your IPv6 address. Yes, your IPv6 address is public, but when your IPv6 prefix changes, at least Linux hosts tend to keep the old IP config in their memory and add a new one. So you can issue command “ip -6 addr” and observe 2 or more public IPv6 addresses. Only one of them would work and the system would properly use it for communication, but I was not able to figure out an easy way to query OS for the right IPv6 address. So instead I opted to use external service to ask which IPv6 address I am coming from.
Second of all, you probably don’t want to allow 80, 443 or whatever other port you are using to all of the systems with IPv6 addresses, so you would want to update your firewall rules dynamically along with the AAAA records in Cloudflare. In my case, I have a small Fortigate firewall at home, so I have added some code to handle that as well.
Last but not least, you may want to update A and AAAA records for some other device that can’t run your code. In my case, I want to be able to grab IPs from my Firewall’s external interface, which happens to act as a VPN concentrator. So I added some code to handle that if needed.
Writing the code
Writing the code turned out to be fairly simple. I already had a library for interfacing with Fortigate firewalls via API, so I used it. Cloudflare also has python library that also covers DDNS use case. I initially planned to just use it as it, but ended up modifying some of it for additional functionality. The result can be found here: https://github.com/eoprede/cf_dynamic
Using the code
In its most basic form, assuming that you have domain mydomain.com, e-mail of [email protected], token of 123 and you want to update host testhost, then you need to run the following command
python cf_dynamic --token 123 --email email@example.com --zone mydomain.com --hosts testhost
If you wanted to do only IPv6 or IPv4 updates, add arguments –ipv4 or –ipv6. If you wanted to use Cloudflare just as DNS provider and do not use CDN functionality, add argument –noproxy.
If you happened to have Fortigate firewall, then you can go further. Let’s assume you have a firewall rule allowing some inbound ports to address6 “webserver”. Let’s also assume that your firewall is at the address of 192.168.0.1 and username/password for it are admin/admin. In order to dynamically update the firewall object, add these arguments to your script: –un admin –pw admin –fw 192.168.0.1 –rule webserver and the script will update the object as needed. Lastly, if you want to update Cloudflare with external IP of your wan1 interface, remove –rule and instead add –fwint wan1 In this case you would want to use –noproxy as well, as there’s no point of using CDN proxy for your firewall connections.
Potential issues with this code
Probably biggest issue is that you are putting code with credentials to both your firewall and cloudflare account on a system that is externally accessible. It’s fine for home use, but definitely not acceptable for production. Another issue is that you are relying on external services to figure out your public IP, which are not guaranteed to be up. It can be changed if there is a reliable method of identifying the right IPv6 address on Linux hosts, I didn’t spend much time on it.
Another potential issue is that you are not doing any local caching and are making API call to cloudflare and Firewall every time you run the script. It would be hard to overload Firewall with these calls, Cloudflare seems to not care that you call their services every time as well (otherwise they wouldn’t post such an example of their code), so I doubt there’s a real-life issue with using it the way it it. Nevertheless, it can be optimized by making these API calls only when IPs have changed.
This is by no means the comprehensive solution to using cloudflare as DDNS provider, but hopefully this demonstrates how it can be done easily and how you can tie in some network automation with it. Hopefully this read was helpful or at least mildly interesting.