|
#!/bin/bash |
|
|
|
# Initial fork from benkulbertis/cloudflare-update-record.sh by lifehome |
|
# Forked from lifehome/cfupdater |
|
# CHANGE THESE |
|
# $Domains array should have at least two elements : ("Which record you want to be synced" "4 for IPv4 or 6 for IPv6") |
|
declare -a Domains=("sub_or_owned.domain" "4" "sub_or_owned.domain" "6"); |
|
auth_email="[email protected]" # The email used to login 'https://dash.cloudflare.com' |
|
auth_key="fffffffffffffffffffffffffffffffffffff" # Top right corner, "My profile" > "Global API Key" |
|
zone_identifier="ffffffffffffffffffffffffffffffff" # Can be found in the "Overview" tab of your domain |
|
# Configure output interface if your ISP alternates between dual stack and IPv4 only |
|
# If not configured, when getting at ipv6=$(curl -6 -s https://ipv6.detector), the script will hang (not getting any IPv6) |
|
outputif="ppp0" # Output interface (also used for warn_v4) |
|
# Optional |
|
# Leave as is if not necessary |
|
warn_v4=false # Warn if IPv4 is routed by your ISP |
|
|
|
# DO NOT CHANGE LINES BELOW |
|
# SCRIPT START |
|
main() { |
|
echo "[Cloudflare DDNS] Check Initiated" | systemd-cat |
|
|
|
# Let's check connection to the Internet (Google is always online) |
|
while :; do |
|
check_connect=$(ping -q -w1 -c1 google.com &>/dev/null && echo online || echo offline) |
|
if [ "$check_connect" == "online" ]; then |
|
break |
|
else |
|
echo "[Cloudflare DDNS] Waiting for Internet connection" | systemd-cat |
|
sleep 30 |
|
fi |
|
done |
|
|
|
#ipv4=$(curl -4 -s https://icanhazip.com/) |
|
#ipv4=$(curl -4 -s http://plain-text-ip.com/) |
|
#ipv4=$(curl -4 -s https://ip.seeip.org) |
|
#ipv4=$(curl -4 -s https://ident.me/) |
|
ipv4=$(curl -4 -s https://wtfismyip.com/text) |
|
|
|
# Checking IPv6 on output interface (if global IPv6 present) |
|
if [ "$(ifconfig $outputif | grep global)" == "" ]; then |
|
ipv6="noipv6" |
|
else |
|
#ipv6=$(curl -6 -s https://icanhazip.com/) |
|
#ipv6=$(curl -6 -s http://plain-text-ip.com/) |
|
#ipv6=$(curl -6 -s https://ip.seeip.org) |
|
#ipv6=$(curl -6 -s https://ident.me/) |
|
ipv6=$(curl -6 -s https://wtfismyip.com/text) |
|
fi |
|
|
|
len=${#Domains[@]} |
|
if [ "$len" -lt 2 ]; then |
|
echo -e "[Cloudflare DDNS] Not enough elements in Domains array" | systemd-cat -p err |
|
exit 1 |
|
fi |
|
if [ $(( $len % 2)) -ne 0 ]; then |
|
echo -e "[Cloudflare DDNS] Domains array is defined with an odd number of elements" | systemd-cat -p err |
|
exit 1 |
|
fi |
|
ver_err=0 |
|
for (( i=0; i < $len; i++ )) |
|
do |
|
record_name=${Domains[$i]} |
|
i=$(( $i + 1 )) |
|
ip_type=${Domains[$i]} |
|
select_type $ip_type $record_name |
|
if [[ "$?" -eq 1 ]]; then |
|
ver_err=$(( $ver_err + 1 )) |
|
fi |
|
done |
|
if [ "$ver_err" -gt 0 ]; then |
|
echo -e "[Cloudflare DDNS] Errors were encountered when parsing array" | systemd-cat -p err |
|
exit 1 |
|
fi |
|
echo "[Cloudflare DDNS] Check Finished successfully" | systemd-cat |
|
exit 0 |
|
} |
|
|
|
select_type() { |
|
# Check selected ip_type that needs to be updated |
|
local ip="" |
|
local record_type="" |
|
if [ "$1" == "4" ]; then |
|
ip=$ipv4 |
|
if [ $warn_v4 ]; then |
|
local ipv4_local=$(ifconfig $outputif | grep -Po '(?<=inet)[^"]*(?=netmask)') |
|
if [ $ip != $ipv4_local ]; then |
|
echo "[Cloudflare DDNS] Warning! IPv4 is routed by the ISP" | systemd-cat -p notice |
|
fi |
|
fi |
|
record_type="A" |
|
else |
|
ip=$ipv6 |
|
if [ "$ip" == "noipv6" ]; then |
|
echo "[Cloudflare DDNS] Warning! No IPv6 detected on $outputif interface" | systemd-cat -p notice |
|
return 0 |
|
fi |
|
record_type="AAAA" |
|
fi |
|
|
|
# Seek for the record |
|
local record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$2" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json") |
|
|
|
# Wrong login email or API key |
|
if [[ $record == *"\"code\":9103"* ]]; then |
|
echo -e "[Cloudflare DDNS] Unknown X-Auth-Key or X-Auth-Email!" | systemd-cat -p crit |
|
exit 1 |
|
fi |
|
|
|
# Wrong zone identifier |
|
if [[ $record == *"\"code\":7003"* ]]; then |
|
echo -e "[Cloudflare DDNS] Object (zone) identifier is invalid!" | systemd-cat -p crit |
|
exit 1 |
|
fi |
|
|
|
# Can't do anything without the record |
|
if [[ $record == *"\"count\":0"* ]]; then |
|
echo -e "[Cloudflare DDNS] Record $2 does not exist, perhaps create one first?" | systemd-cat -p crit |
|
return 1 |
|
fi |
|
|
|
# Set existing IP address from the fetched record |
|
local oldip=$(echo "$record" | grep -Po '(?<="type":"'$record_type'","name":"'$2'","content":")[^"]*' | head -1) |
|
|
|
# Compare if they're the same |
|
if [ "$ip" == "$oldip" ]; then |
|
echo "[Cloudflare DDNS] IP($oldip) for record $2 has not changed." | systemd-cat -p notice |
|
return 0 |
|
fi |
|
|
|
# The execution of update for the IP |
|
local id_ip=$(echo "$record" | grep -Po '([^"]*)[^"]*(?=","type":"'$record_type'","name":"'$2'","content":")' | head -1) |
|
local oldproxiable=$(echo "$record" | grep -Po '(?<="type":"'$record_type'","name":"'$2'","content":"'$oldip'","proxiable":)[^,]*' | head -1) |
|
local oldproxied=$(echo "$record" | grep -Po '(?<="type":"'$record_type'","name":"'$2'","content":"'$oldip'","proxiable":'$oldproxiable',"proxied":)[^,]*' | head -1) |
|
local oldttl=$(echo "$record" | grep -Po '(?<="type":"'$record_type'","name":"'$2'","content":"'$oldip'","proxiable":'$oldproxiable',"proxied":'$oldproxied',"ttl":)[^,]*' | head -1) |
|
local update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$id_ip" -H "X-Auth-Email: $auth_email" -H "X-Auth-Key: $auth_key" -H "Content-Type: application/json" --data "{\"id\":\"$zone_identifier\",\"type\":\"$record_type\",\"name\":\"$2\",\"content\":\"$ip\",\"ttl\":$oldttl,\"proxied\":$oldproxied}") |
|
# The moment of truth |
|
case "$update" in |
|
*"\"success\":false"*) |
|
echo -e "[Cloudflare DDNS] Update failed for $id_ip. DUMPING RESULTS:\n$update" | systemd-cat -p err |
|
return 1;; |
|
*) |
|
echo "[Cloudflare DDNS] IP($1) for record $2 synced to: $ip" | systemd-cat -p notice |
|
return 0;; |
|
esac |
|
} |
|
|
|
main "$@" |