Updating my dynamic IP in Cloudflare

Hello to the community!
I’ve recently made the switch to IPFire and love it. It is running on a little cheapie black box (literally) 4GB mini PC from Amazon. I made the switch from OPNsense as FreeBSD had an annoying issue with the hardware.
Anyway, the only issue I’ve encountered so far is lack of support for Cloudflare in the list of Dynamic DNS providers. Since I have everything setup with Cloudflare, I would love to be able to just manage this on my IPFire and not have to run a daemon on some other server.
I see there is an API that can be used (ref here: How to Setup Cloudflare Dynamic DNS). I would love to be able to contribute to the code but I’m a systems guy, not a programmer. Shell scripting is as fancy as I get. :grinning:
Any possibility of getting this in a future version?

https://community.ipfire.org/t/cloudflare-ddns/893

1 Like

Thanks for the reply!
I did see that post, but not really sure what to do with it. Like I said, programming isn’t my niche. Is it just a python script that I can copy somewhere? I don’t want to mess around in the OS if I dontt need to. Also, will it be overwritten when I update?

-Mike

It’s code that should be patched into the python script that IPFire uses to deal with the DDNS providers. Unfortunately it requires also the installation of other Python libraries.

A suggestion, maybe you could open a bug report linking to that post and asking the developers to consider including that code into the script. I am sure the quality is not good enough to be used as it was posted, but at least your request is logged in the system and maybe it will be considered in the future.

You can use a DDNS bug report (like this one) as a model to write your request to include Cloudflare as a provider.

1 Like

I suggest a bug report, also.
The DDNS code is a ‘solid block’ for non-programmers. Inside it is expandable for other DDNS providers. But this should be done by devs knownig the internals. Further there is great probability, that this modification survives core updates.

I did not find a bug report, so I will try to add one :slight_smile:
EDIT: Now it is here: 13071 – Could we add Cloudflare dynamic DNS

Hi! I do not really know how to add stuff to the Ipfire web pages, but I did this script that can update the IP in Cloudflare. Maybe it can help a developer to add Cloudflare to the DDNS flavors.

cat ddns-cloudflare.sh

#!/bin/bash

# This script is originaly from:
# https://dev.to/ordigital/cloudflare-ddns-on-linux-4p0d

# Check for current external IP
IP=`dig +short txt ch whoami.cloudflare @1.0.0.1| tr -d '"'`

# === TOKEN ===
# Get an API Token with permissions to modify DNS records:
# Go to https://dash.cloudflare.com/profile/api-tokens and Create
# a new Token. Click on Edit zone DNS template and then add your
# preferred zone

# === DNS_ZONE_ID ===
# The "DNS_ZONE_ID" can be found in Cloudflare Dashboard, logged in
# the Cloudflare Dashboard, check the Domain page, "Zone ID"
# information will appearance at API block, right hand side.
# For more info, see:
# https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/

# === DNS_ENTRY_ID ===
# Run this command to find the "DNS_ENTRY_ID":
# curl https://api.cloudflare.com/client/v4/zones/DNS_ZONE_ID/dns_records -H "Authorization: Bearer TOKEN"
#
# It should show something like this:
# "result":[{"id":"here_is_the_DNS_ENTRY_ID","zone_id":"here_is_the_DNS_ZONE_ID",
# "zone_name":"some.domain.org","name":"www.some.domain.org","type":"A",
# "content":"1.1.1.1", etc, etc

# Set Cloudflare API
DNS_ZONE_ID="qwertyqwertyqwertyqwerty"
DNS_ENTRY_ID="wertyqwertyqwertyqwerty"
TOKEN="ertyqwertyqwertyqwertyqwerty"
NAME="www.some.domain.org"

URL="https://api.cloudflare.com/client/v4/zones/$DNS_ZONE_ID/dns_records/$DNS_ENTRY_ID"


# Connect to Cloudflare
cf() {
curl -X ${1} "${URL}" \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${TOKEN}" \
      ${2} ${3}
}

# Get current DNS data
RESULT=$(cf GET)
IP_CF=$(jq -r '.result.content' <<< ${RESULT})

DATE=`date +"%b %_d %T"`

# Compare IPs
if [ "$IP" = "$IP_CF" ]; then
    echo "$DATE ipfire ddns[0]: No change. Checked IP $IP = IP in DNS $IP_CF. $RESULT" | tee -a /var/log/messages
else
    RESULT=$(cf PUT --data "{\"type\":\"A\",\"name\":\"${NAME}\",\"content\":\"${IP}\"}")
    echo "$DATE ipfire ddns[0]: DNS updated: $RESULT" | tee -a /var/log/messages
fi

I had a quick look at the cloudflare info and at the IPFire DDNS system.

Currently the IPFire DDNS providers fit into one of two categories.

The first category requires

  • Hostname
  • Username
  • Password

The second category requires

  • Hostname
  • Token

The Cloudflare DDNS provider requires

  • Email
  • Token
  • Domain
  • Record

I think the Record is the same as Hostname in the previous two categories and the Token will be dealt with the same.

It might be that Domain can be extracted from the Record input although I am not certain without more detailed investigation.

However then there is the Email input that is required.

So it is not just a simple case of adding another provider into the list. The code for interfacing with the provider also needs to have an additional section to deal with the Email and to extract the domain from the record (hopefully) and then provide the four items in the correct way to the Cloudflare provider API.

I suspect that will require the expertise of some specific IPFire developers who are involved in other priority activities in their todo lists currently.

If there is anyone on the forum who has the skills to understand the existing DDNS updater code and to create/submit a patch(s) for the required changes, they would be welcomed to provide the input.

Details on how to clone the IPFire-2.x git repo and make changes, evaluate them and then submit the patch(s) to the IPFire dev mailing list are described in the Development section of the wiki.

2 Likes

In my script i do not actually use email, I use:

  • DNS_ZONE_ID=“qwertyqwertyqwertyqwerty”
  • DNS_ENTRY_ID=“wertyqwertyqwertyqwerty”
  • Token = TOKEN=“ertyqwertyqwertyqwertyqwerty”
  • Domain = NAME=“www.some.domain.org

I wonder if they mean that "X-Auth-Email is just a required header name at Cloudflare API Documentation

I have just realised that what I thought was a link to cloudflare info in the first post in this thread was actually a non cloudflare website.
In the section headed “Running the Script” it mentions the items I listed.

If these are what cloudflare says to use ( I will have another look at the actual cloudflare info) then maybe the item labelled domain is the same as Hostname but it could also be different.

DNS_ZONE_ID & DNS_ENTRY_ID are definitely different to anything used by any of the other DDNS providers.

2 Likes

If i try to follow the code at Cloudflare DDNS it seems like in that code it uses another approach:

It uses only these three infos to do everything

  • self.username = X-Auth-Email = myemail@somewhere.org
  • self.password = X-Auth-Key = Global API Key = Go to Your profile → Overview → Get your API token → Global API Key = qwertyqwertyqwertyqwerty
  • self.hostname = www.mydomain.org

First with “self.username = X-Auth-Email” and “self.password = X-Auth-Key” it does something like this:
curl https://api.cloudflare.com/client/v4/zones -H "X-Auth-Email: myemail@somewhere.org" -H "X-Auth-Key: qwertyqwertyqwertyqwerty" -H "Content-Type: application/json"

And it gets:

  • zone_id = zdzdzdzdzdzdzdzdzdzd

With this new info it does something like this:
curl https://api.cloudflare.com/client/v4/zones/zdzdzdzdzdzdzdzdzdzd/dns_records -H "X-Auth-Email: myemail@somewhere.org" -H "X-Auth-Key: qwertyqwertyqwertyqwerty" -H "Content-Type: application/json"

And with the info from above command and the help of self.hostname it gets

  • host_id = hdhdhdhhdhdhdhdhdhd

And now it has everything it needs to check IP and change if needed

EDIT
I also just realized that the code in Cloudflare DDNS is very similar to the code in providers.py « ddns « src - ddns.git - Dynamic DNS client for IPFire. (if this is the right place to look).

In my naive eyes it looks like copying all code from the post to providers.py and changing stuff like:

requests.put(self.url bla bla ...

To

self.send_request(self.url bla bla ...

And maybe it would work with a few changes in providers.py?

I’ve updated the bug report with a proposed modification of code to get the Cloudflare DDNS updates working.

I have been using this for the last three weeks and it seems to work well enough to let others have a play and probably find bugs and fix code. I have learnt python enough to get this to work, so the code could probably do with some polishing and better handling of things.

https://bugzilla.ipfire.org/show_bug.cgi?id=13071

At this stage I have no idea how to get this code into a review and into the codebase for ipfire.

2 Likes

Is Desmond Wongs code OK for introducing it in the next update? I am still using the script I did and it works OK, so no big problem. But if there is a built in alternative it would feel better :blush: Can I help somehow?

My script for future reference. Even if the script will not be used, maybe the comments can be used for info somewhere of how to get the needed ID:s:

1. Create /etc/fcron.hourly/ddns-cloudflare.sh, se below for content
2. chmod +x ddns-cloudflare.sh

cat ddns-cloudflare.sh
#!/bin/bash

# This script is originaly from:
# https://dev.to/ordigital/cloudflare-ddns-on-linux-4p0d

# Check for current external IP
IP=`dig +short txt ch whoami.cloudflare @1.0.0.1| tr -d '"'`

# === TOKEN ===
# Get an API Token with permissions to modify DNS records:
# Go to https://dash.cloudflare.com/profile/api-tokens and Create
# a new Token. Click on Edit zone DNS template and then add your
# preferred zone. Say it looks like this:
# xyzAPITokenWithPermissionsToModifyDNSxyz

# === DNS_ZONE_ID ===
# The "DNS_ZONE_ID" can be found in Cloudflare Dashboard, logged in
# the Cloudflare Dashboard, check the Domain page, "Zone ID"
# information will appearance at API block, right hand side.
# For more info, see:
# https://developers.cloudflare.com/fundamentals/setup/find-account-and-zone-ids/
# Say it looks like this:
# xyzDNSZoneIDxxxxxxxxxxxxxxxxxxxyz

# === DNS_ENTRY_ID ===
# Run this command to find the "DNS_ENTRY_ID":
# curl https://api.cloudflare.com/client/v4/zones/DNS_ZONE_ID/dns_records -H "Authorization: Bearer TOKEN"
# eg.
# curl https://api.cloudflare.com/client/v4/zones/xyzDNSZoneIDxxxxxxxxxxxxxxxxxxxyz/dns_records -H "Authorization: Bearer xyzAPITokenWithPermissionsToModifyDNSxyz"
#
# It should show something like this:
# "result":[{"id":"here_is_the_DNS_ENTRY_ID","zone_id":"here_is_the_DNS_ZONE_ID",
# "zone_name":"some.domain.org","name":"www.some.domain.org","type":"A",
# "content":"1.1.1.1", etc, etc
# eg.
#
# {"result":[{{"id":"xyzDNSEntryIDaaaaaaaaaaaaaaaaxyz",
# "zone_id":"xyzDNSZoneIDxxxxxxxxxxxxxxxxxxxyz",
# "zone_name":"myfirst.domain.com",
# "name":"www1.myfirst.domain.com",
# "type":"A","content":"129.168.0.234","proxiable":true,"proxied":false,"ttl":1,"locked":false,"meta":{"auto_added":false,"managed_by_apps":false,"managed_by_argo_tunnel":false},"comment":null,"tags":[],"created_on":"2023-10-24T12:09:09.071845Z","modified_on":"2023-10-24T12:55:16.370143Z"}
#

# Set Cloudflare API for www1.myfirst.domain.com
DNS_ZONE_ID="xyzDNSZoneIDxxxxxxxxxxxxxxxxxxxyz"
DNS_ENTRY_ID="xyzDNSEntryIDaaaaaaaaaaaaaaaaxyz"
TOKEN="xyzAPITokenWithPermissionsToModifyDNSxyz"
NAME="www1.myfirst.domain.com"

URL="https://api.cloudflare.com/client/v4/zones/$DNS_ZONE_ID/dns_records/$DNS_ENTRY_ID"

# Connect to Cloudflare
cf() {
curl -X ${1} "${URL}" \
     -H "Content-Type: application/json" \
     -H "Authorization: Bearer ${TOKEN}" \
      ${2} ${3}
}

# Get current DNS data
RESULT=$(cf GET)
IP_CF=$(jq -r '.result.content' <<< ${RESULT})

DATE=`date +"%b %_d %T"`

# Compare IPs
if [ "$IP" = "$IP_CF" ]; then
    echo "$DATE ipfire ddns[0]: No change. Checked IP $IP = IP in DNS $IP_CF. $RESULT" | tee -a /var/log/messages
else
    RESULT=$(cf PUT --data "{\"type\":\"A\",\"name\":\"${NAME}\",\"content\":\"${IP}\"}")
    echo "$DATE ipfire ddns[0]: DNS updated: $RESULT" | tee -a /var/log/messages
fi

I am having a look at it at the moment.

I will be first testing the code he provided to confirm that it works or not with the current IPFire.

If it works as expected then I will look at modifying it to use the self.send_request method as used with the other providers instead of the requests library so that all things are consistently used.
I will also at that point pick up the bug myself.

I have access to a cloudflare DDNS so will be able to evaluate the code with that.

2 Likes