DDNS Cloudflare
-
Currently to use DDNS with Cloudflare users need provide Global API key witch is give to many unwanted permissions.
Is it possible to implement Cloudflare APIv4 for DDNS over Authorization Bearer API Tokens which can be limited by zone and permissions type? Like here: https://api.cloudflare.com/#dns-records-for-a-zone-update-dns-record.
As workaround: maybe there a way to trigger custom user script on WAN IP change in pfSense?
If I understand correct Shellcmd plugin provide such possibility >afterfilterchangeshellcmd
is what I need asfilter_configure()
run everyrc.newwanip
?
If yes, then I can solve this by running custom bash script =)Updated, link to FR:
https://redmine.pfsense.org/issues/9639 -
After testing, workaround with
afterfilterchangeshellcmd
working.
But it will be cool if pfSense will support Cloudflare APIv4 by native DDNS & store API token as a secret, not plaintext.
Maybe for someone my findings will be useful:
To create API tocket go to https://dash.cloudflare.com/profile/api-tokens
You need configure permissions for your token.Permission: Account -> Access: Organizations, Identity Providers, and Groups: Read Zone -> Zone: Read Zone -> DNS: Edit Account Resources: Include -> Your Account Zone Resources: Include -> Specific zone: Your DNS Zone
After this you need install ShellCmd plugin & pfBlockerNG-devel (needed to have JQ package) in pfSense.
afterfilterchangeshellcmd can be used only once in this plugin, so I created structure that can be scaled in future:- type afterfilterchangeshellcmd to run script
/bin/sh -c /root/shellcmd_after_filterchanges.sh
- type earlyshellcmd to create script itself. If you need in future run more then one script - add it HERE:
echo -e "#!/bin/sh \n/bin/sh -c /root/shellcmd_after_ddns.sh \n" > /root/shellcmd_after_filterchanges.sh; chmod 700 /root/shellcmd_after_filterchanges.sh
- type earlyshellcmd to create ddns script. NOTE Before use this part modify variables RECORD, ZONE and TOKEN, TTL & PROXIED to your needs! Proxied
true
mean hide IP behind Cloudflare, false by default.
echo -e '#!/bin/sh \n \nRECORD="dyn-ipv4.example.com" \nZONE="example.com" \nTOKEN="Get it from https://dash.cloudflare.com/profile/api-tokens" \nTTL="120" \nPROXIED="false" \nCHECK_IP_SERVICE="ifconfig.co" \nZONES=`curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$ZONE&status=active&match=all" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"` \nZONES_SUCCESS=`echo $ZONES | /usr/local/bin/jq -r ".success"` \nif [ "$ZONES_SUCCESS" = "true" ]; then \nZONE_ID=`echo $ZONES | /usr/local/bin/jq -r ".result | .[0].id"` \nDNS_RECORDS=`curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$RECORD&match=all" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"` \nDNS_RECORDS_SUCCESS=`echo $DNS_RECORDS | /usr/local/bin/jq -r ".success"` \nif [ "$DNS_RECORDS_SUCCESS" = "true" ]; then \nRECORD_ID=`echo $DNS_RECORDS | /usr/local/bin/jq -r ".result | .[0].id"` \nIP=`curl -4 $CHECK_IP_SERVICE` \nUPDDATE_DNS_RECORD=`curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --data "{\"type\":\"A\",\"name\":\"$RECORD\",\"content\":\"$IP\",\"ttl\":$TTL,\"proxied\":$PROXIED}"` \nUPDDATE_DNS_RECORD_SUCCESS=`echo $UPDDATE_DNS_RECORD | /usr/local/bin/jq -r ".success"` \nif [ "$UPDDATE_DNS_RECORD_SUCCESS" = "true" ]; then \necho "DynDNS updated: $RECORD to $IP" \nelse \necho "DynDNS update failed: $RECORD to $IP" \nexit 1 \nfi \nelse \necho "Error while tried to get DNS records of Zone: $ZONE_ID" \nexit 1 \nfi \nelse \necho "Error while tried to get Zones" \nfi \n' > /root/shellcmd_after_ddns.sh; chmod 700 /root/shellcmd_after_ddns.sh
-
@dragoangel /usr/local/bin/jq doesn't appear to be installed by default, at least on my box. Where did you install it from?
/root/shellcmd_after_ddns.sh: /usr/local/bin/jq: not found
echo: write error on stdout
Error while tried to get Zones -
@jkm hm, need look to my installed packages =) will reply soon
-
@jkm to have JQ you need install pfBlockerNG-devel, this package needed to parse JSON reply from Cloudflare API as object. I has it on all of my pfSense instances as must have package. Thanks for note, I updated How-to.
-
@dragoangel Thank you! This is working perfectly!
-
@jkm glad that it can help somebody
-
BTW: Netgate will add support for this in pfSense 2.5.0 release.
Till waiting for 2.5.0 release I enchanted workaround by using of Filer plugin will slightly help to manage BASH scripts. One-line ECHO workaround in ShellCMD is ugly. So:- Install Filer plugin
- Create script in pfSense Diagnostics=>Filer with name:
/root/shellcmd_after_filter_changes.sh
2.1. Permissions700
and DescriptionCreate AfterFilterChange Shellcmd script
2.2. File Contents: (all your scripts that must be run by AfterFilterChange Shellcmd script, change it to your need):
#!/bin/sh echo "Launching AfterFilterChange Shellcmd script" /bin/sh -c /root/shellcmd_ddns_sub1.example.com.sh /bin/sh -c /root/shellcmd_ddns_sub2.example.com.sh echo "AfterFilterChange Shellcmd script exited with status: OK"
2.3 Execute mode:
Do not run this script
3. Create all scripts in Filer with names mentioned in AfterFilterChange Shellcmd script (tune it to your needs):/root/shellcmd_ddns_sub1.example.com
3.1. Permissions700
and DescriptionCreate DDNS sub1.example.com script for Shellcmd
3.2. File Contents: (do not forget adjust your RECORD, ZONE and TOKEN. This sample for ipv4. To change it to ipv6 aaaa record you need change curl -4 to -6 and type a to type aaaa)#!/bin/sh RECORD="sub1.example.com" ZONE="example.com" TOKEN="change-me" TTL="120" PROXIED="false" CHECK_IP_SERVICE="ifconfig.co" ZONES=`curl -X GET "https://api.cloudflare.com/client/v4/zones?name=$ZONE&status=active&match=all" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"` ZONES_SUCCESS=`echo $ZONES | /usr/local/bin/jq -r ".success"` if [ "$ZONES_SUCCESS" = "true" ]; then ZONE_ID=`echo $ZONES | /usr/local/bin/jq -r ".result | .[0].id"` DNS_RECORDS=`curl -X GET "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records?type=A&name=$RECORD&match=all" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json"` DNS_RECORDS_SUCCESS=`echo $DNS_RECORDS | /usr/local/bin/jq -r ".success"` if [ "$DNS_RECORDS_SUCCESS" = "true" ]; then RECORD_ID=`echo $DNS_RECORDS | /usr/local/bin/jq -r ".result | .[0].id"` IP=`curl -4 $CHECK_IP_SERVICE` UPDDATE_DNS_RECORD=`curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/dns_records/$RECORD_ID" -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --data "{\"type\":\"A\",\"name\":\"$RECORD\",\"content\":\"$IP\",\"ttl\":$TTL,\"proxied\":$PROXIED}"` UPDDATE_DNS_RECORD_SUCCESS=`echo $UPDDATE_DNS_RECORD | /usr/local/bin/jq -r ".success"` if [ "$UPDDATE_DNS_RECORD_SUCCESS" = "true" ]; then echo "DynDNS updated: $RECORD to $IP" else echo "DynDNS update failed: $RECORD to $IP" exit 1 fi else echo "Error while tried to get DNS records of Zone: $ZONE_ID" exit 1 fi else echo "Error while tried to get Zones" fi echo "DDNS sub1.example.com exited with status: OK"
3.3 Execute mode:
Do not run this script
4. In ShellCmd if you created previously other scripts by my how-to - remove them and leave only:/bin/sh /root/shellcmd_after_filter_changes.sh
with typeafterfilterchangeshellcmd
and DescriptionRun shellcmd_after_filter_changes.sh