-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updating to support getting DNS IP automatically (non-proxied record …
…no longer needed)
- Loading branch information
1 parent
486faaf
commit 7e13512
Showing
3 changed files
with
151 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,7 @@ | |
This was a project I began working on when I founded <a href="https://www.machineitservices.com/" target="_blank">Machine IT Services</a>, a web hosting, web development, and IT company based in Louisville, KY. | ||
This script has the potential to update the DNS Records (A and AAAA) of a multitude of domains/zones on Cloudflare, while also providing flexibility by allowing the update of specific subdomains/records for each domain specified in the config file, compatible with both IPv4 and IPv6 addresses. | ||
You may refer to included config-example.sh for config file format. In order to run the script, just execute it with either the config file name (if in the same directory, i.e. config.sh) or the config file location (i.e. /your/config/directory/config.sh) as your first argument. You can specify numerous custom record sections, with each containing unique or different sets of subdomains/records for each zone specified. You can list the same zone more than once in separate records groups, setting the proxy option for each group as needed. | ||
It will also accept a second argument. This is to specify an additional script to run. Any additional arguments will be passed to the additional script. This is helpful in the situation that your server is also a DNS server or needs the IP address updated somewhere in it's own files or databases as it will include the $oldip4/6 and $newip4/6 variables, as well as the $updatedir/cloudflare-ddns-update.sh script location.. | ||
It will also accept a second argument. This is to specify an additional script to run. Any additional arguments will be passed to the additional script. This is helpful in the situation that your server is also a DNS server or needs the IP address updated somewhere in it's own files or databases as it will include the $oldip4/6 and $newip4/6 variables, as well as the $updatedir/cloudflare-ddns-update.sh script location. | ||
This is the perfect script if you're managing multiple sites on your dynamic server, and want to update several individual zones for separate Cloudflare accounts in one script. This script will allow you to specify your accounts, zones, records, and whether or not to use the Cloudflare proxy. | ||
|
||
## Usage | ||
|
@@ -24,11 +24,6 @@ This is the perfect script if you're managing multiple sites on your dynamic ser | |
|
||
Of course, I'd recommend using a cronjob to run this script automatically at set intervals; Once every minute should be fine. | ||
|
||
Please set the `hostnameaddr` variable in your config file to a record that is NOT proxied, and INCLUDE it in your list of records to update. | ||
Otherwise it will always run, as it is the address checked against your current server address. This is IMPORTANT! | ||
|
||
NOTE: In the future, I may just use the API to retrieve each record's currently set address in Cloudflare to do away with this "non-proxied" record requirement. | ||
|
||
## Contact | ||
|
||
For assistance with the use or operation of this utility, feel free to <a href="mailto:[email protected]">email me</a>. Please no spam or solicitation. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,172 +1,170 @@ | ||
#!/bin/bash | ||
|
||
|
||
updatedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" | ||
|
||
if [ "${1}" != "" ]; then | ||
if [ -e "${1}" ]; then | ||
source "${1}" | ||
elif [ -e "${updatedir}/${1}" ]; then | ||
source "${updatedir}/${1}" | ||
else | ||
echo Config File Not Found... Exiting... | ||
if [ -e "${1}" ]; then | ||
source "${1}" | ||
elif [ -e "${updatedir}/${1}" ]; then | ||
source "${updatedir}/${1}" | ||
else | ||
echo Config File Not Found... Exiting... | ||
exit | ||
fi | ||
fi | ||
shift | ||
else | ||
echo Config File Not Specified... Exiting... | ||
exit | ||
echo Config File Not Specified... Exiting... | ||
exit | ||
fi | ||
|
||
if [ "${ids_dir}" != "" ]; then | ||
if [ ! -d "${ids_dir}" ]; then | ||
if [ -d "${updatedir}/${ids_dir}" ]; then | ||
if [ ! -d "${ids_dir}" ]; then | ||
if [ -d "${updatedir}/${ids_dir}" ]; then | ||
ids_dir="${updatedir}/${ids_dir}" | ||
else | ||
mkdir -p "${updatedir}/${ids_dir}" | ||
ids_dir="${updatedir}/${ids_dir}" | ||
fi | ||
fi | ||
fi | ||
else | ||
echo IDS Storage Location Not Specified in Config File... | ||
echo Using Script Location Instead... | ||
echo IDS Storage Location Not Specified in Config File... | ||
echo Using Script Location Instead... | ||
ids_dir="${updatedir}" | ||
fi | ||
|
||
if [ "${force}" == "on" ]; then | ||
setip4=0.0.0.0 | ||
setip6=:: | ||
else | ||
setip4=$(dig +short a ${hostnameaddr}) | ||
setip6=$(dig +short aaaa ${hostnameaddr}) | ||
fi | ||
|
||
pushd "${updatedir}" > /dev/null 2>&1 | ||
|
||
export newip4=$(curl -4 -s myipv4.machineitservices.com) | ||
export newip6=$(curl -6 -s myipv6.machineitservices.com) | ||
|
||
if $([[ "${setip4}" == *"connection timed out"* ]] || [ "${newip4}" == "" ] || [ "${setip4}" == "" ] || $(unset newip4 && echo false)) && \ | ||
$([[ "${setip6}" == *"connection timed out"* ]] || [ "${newip6}" == "" ] || [ "${setip6}" == "" ] || $(unset newip6 && echo false)); then | ||
echo Obtaining Addresses Failed. Now Exiting... | ||
exit | ||
else | ||
|
||
new_ips="ip4 ip6" | ||
for i in ${new_ips[@]}; do | ||
|
||
setip="$(set_ip="set${i}"; setip=$(eval echo '${'${set_ip}'}'); echo ${setip};)" | ||
newip="$(new_ip="new${i}"; newip=$(eval echo '${'${new_ip}'}'); echo ${newip};)" | ||
|
||
if [ "${newip}" != "" ] && [ "${setip}" != "${newip}" ]; then | ||
if [ "${i}" == "ip4" ]; then | ||
echo -e "\nChecking IPv4 Address\n" | ||
rec_type="A" | ||
elif [ "${i}" == "ip6" ]; then | ||
echo -e "\nChecking IPv6 Address\n" | ||
rec_type="AAAA" | ||
fi | ||
|
||
if [ -f "${updatedir}/new_${i}.txt" ]; then | ||
mv "${updatedir}/new_${i}.txt" "${updatedir}/old_${i}.txt" | ||
elif [ "${setip}" != "" ]; then | ||
echo "${setip}"> "${updatedir}/old_${i}.txt" | ||
else | ||
echo ERROR! Unable To Obtain Old Hostname IP Address | ||
fi | ||
|
||
ip_file="${updatedir}/old_${i}.txt" | ||
if [ -f "${ip_file}" ]; then export oldip="$(cat "${updatedir}/old_${i}.txt")"; fi | ||
echo "${newip}"> "${updatedir}/new_${i}.txt" | ||
|
||
echo IP Discrepancy Detected | ||
echo Saved IP: ${oldip} | ||
echo Live IP: ${setip} | ||
echo Current IP: ${newip} | ||
echo DNS ${rec_type} Record Updates Required | ||
echo Updating Cloudflare DNS Records | ||
a=1 | ||
while [ ${a} -le ${custom_records_num} ]; do | ||
echo -e "\nLoading Custom ${a}" | ||
load_zone="custom${a}_zones[@]" | ||
cur_zone="(${!load_zone})" | ||
for b in $(eval echo '${!'${load_zone}'}'); do | ||
load_zone="custom${a}_zones[${b}]" | ||
g="${!load_zone}" | ||
if [ "$g" != "" ]; then | ||
load_record="custom${a}_records[@]" | ||
cur_record="(${!load_record})" | ||
for c in $(eval echo '${!'$load_record'}'); do | ||
load_record="custom${a}_records[${c}]" | ||
h="${!load_record}" | ||
if [ "$h" != "" ]; then q="."; else q=""; fi | ||
declare ${zones[${g}]//.}_file[${c}]=${ids_dir}/cf-${i}-${h}${q}${zones[${g}]}.ids | ||
id_file=$(eval "echo \"\${zones[${g}]//.}_file[${c}]\"") | ||
echo -e "\nUpdating Record for ${h}${q}${zones[${g}]}" | ||
s=1 | ||
while [ ${s} -le ${user_creds_num} ]; do | ||
load_creds="user${s}_credzone[@]" | ||
for t in $(eval echo '${!'${load_creds}'}'); do | ||
load_creds="user${s}_credzone[${t}]" | ||
p="${!load_creds}" | ||
if [ "${p}" == "${g}" ]; then | ||
u="user${s}_creds[0]" | ||
p="user${s}_creds[1]" | ||
if [ -f ${!id_file} ] && [ $(wc -l ${!id_file} | cut -d " " -f 1) == 2 ]; then | ||
echo Reading Identifiers from Saved File: cf-${i}-${h}${q}${zones[${g}]}.ids | ||
zone_identifier=$(head -1 ${!id_file}) | ||
record_identifier=$(tail -1 ${!id_file}) | ||
else | ||
echo Using API to GET Identifiers | ||
zone_identifier="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${zones[${g}]}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )" | ||
record_identifier="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records?name=${h}${q}${zones[${g}]}&type=${rec_type}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )" | ||
echo Writing Identifiers to Save File: cf-${h}${q}${zones[${g}]}.ids | ||
echo "${zone_identifier}" > "${!id_file}" | ||
echo "${record_identifier}" >> "${!id_file}" | ||
fi | ||
|
||
proxy_check="custom${a}_proxied" | ||
proxied=${!proxy_check} | ||
if [ "${proxied}" == "no" ] || [ "${proxied}" == "0" ]; then | ||
update="$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\",\"proxied\":false}")" | ||
new_ips="ip4 ip6" | ||
for i in ${new_ips[@]}; do | ||
newip="$(new_ip="new${i}"; newip=$(eval echo '${'${new_ip}'}'); echo ${newip};)" | ||
|
||
if [ "${newip}" != "" ]; then | ||
if [ "${i}" == "ip4" ]; then | ||
echo -e "\nChecking IPv4 Address\n" | ||
rec_type="A" | ||
elif [ "${i}" == "ip6" ]; then | ||
echo -e "\nChecking IPv6 Address\n" | ||
rec_type="AAAA" | ||
fi | ||
|
||
elif [ "${proxied}" == "yes" ] || [ "${proxied}" == "1" ]; then | ||
update="$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\",\"proxied\":true}")" | ||
else echo Proxy Value Not Defined in Custom $a; echo Attempting to Update Record Without Proxy Definition in Request | ||
update=$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\"}") | ||
fi | ||
if [[ ${update} == *"\"success\":false"* ]]; then | ||
message="API UPDATE FAILED FOR: \"${h}${q}${zones[${g}]}\" DUMPING RESULTS:\n${update}" | ||
echo -e "${message}" | ||
else | ||
message="IP changed to: ${newip}\nProxied: $(echo "${update}" | grep -Po '(?<="proxied":)[^,]*' | head -1)" | ||
echo -e "${message}" | ||
fi | ||
break | ||
fi | ||
ip_file="${updatedir}/old_${i}.txt" | ||
|
||
a=1 | ||
while [ ${a} -le ${custom_records_num} ]; do | ||
echo -e "\nLoading Custom ${a}" | ||
load_zone="custom${a}_zones[@]" | ||
cur_zone="(${!load_zone})" | ||
for b in $(eval echo '${!'${load_zone}'}'); do | ||
load_zone="custom${a}_zones[${b}]" | ||
g="${!load_zone}" | ||
if [ "$g" != "" ]; then | ||
load_record="custom${a}_records[@]" | ||
cur_record="(${!load_record})" | ||
for c in $(eval echo '${!'$load_record'}'); do | ||
load_record="custom${a}_records[${c}]" | ||
h="${!load_record}" | ||
if [ "$h" != "" ]; then q="."; else q=""; fi | ||
declare ${zones[${g}]//.}_file[${c}]=${ids_dir}/cf-${i}-${h}${q}${zones[${g}]}.ids | ||
id_file=$(eval "echo \"\${zones[${g}]//.}_file[${c}]\"") | ||
echo -e "\nUpdating Record for ${h}${q}${zones[${g}]}" | ||
s=1 | ||
while [ ${s} -le ${user_creds_num} ]; do | ||
load_creds="user${s}_credzone[@]" | ||
for t in $(eval echo '${!'${load_creds}'}'); do | ||
load_creds="user${s}_credzone[${t}]" | ||
p="${!load_creds}" | ||
if [ "${p}" == "${g}" ]; then | ||
u="user${s}_creds[0]" | ||
p="user${s}_creds[1]" | ||
unset zone_identifier | ||
unset record_identifier | ||
unset current_ip | ||
if [ -f ${!id_file} ] && [ $(wc -l ${!id_file} | cut -d " " -f 1) == 2 ]; then | ||
echo Reading Identifiers from Saved File: cf-${i}-${h}${q}${zones[${g}]}.ids | ||
zone_identifier=$(head -1 ${!id_file}) | ||
record_identifier=$(tail -1 ${!id_file}) | ||
fi | ||
|
||
if [ "${zone_identifier}" != "" ] && [ "${record_identifier}" != "" ]; then | ||
current_ip="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="content":")[^"]*' | head -1 )" | ||
fi | ||
|
||
if [ "${current_ip}" == "" ]; then | ||
echo Using API to GET Identifiers | ||
zone_identifier="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${zones[${g}]}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )" | ||
if [ "${zone_identifier}" != "" ]; then | ||
record_identifier="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records?name=${h}${q}${zones[${g}]}&type=${rec_type}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="id":")[^"]*' | head -1 )" | ||
if [ "${record_identifier}" != "" ]; then | ||
echo Writing Identifiers to Save File: cf-${i}-${h}${q}${zones[${g}]}.ids | ||
echo "${zone_identifier}" > "${!id_file}" | ||
echo "${record_identifier}" >> "${!id_file}" | ||
current_ip="$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier}" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" | grep -Po '(?<="content":")[^"]*' | head -1 )" | ||
else | ||
echo DNS Record not found. Attempting to create new $rec_type record for ${h}${q}${zones[${g}]} | ||
proxy_check="custom${a}_proxied" | ||
proxied=${!proxy_check} | ||
if [ "${proxied}" == "no" ] || [ "${proxied}" == "0" ]; then | ||
proxied_bool="false" | ||
else | ||
proxied_bool="true" | ||
fi | ||
record_identifier="$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records" -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\",\"proxied\":${proxied_bool}}" | grep -Po '(?<="id":")[^"]*' | head -1 )" | ||
if [ "${record_identifier}" != "" ]; then | ||
echo Writing Identifiers to Save File: cf-${i}-${h}${q}${zones[${g}]}.ids | ||
echo "${zone_identifier}" > "${!id_file}" | ||
echo "${record_identifier}" >> "${!id_file}" | ||
current_ip="${newip}" | ||
else | ||
echo Unable to retrieve DNS Record Identifier. DNS Record may or may not have been created. | ||
echo Please try running again. | ||
fi | ||
fi | ||
else | ||
echo DNS Zone not found... Continuing... | ||
fi | ||
fi | ||
|
||
if [ "${zone_identifier}" != "" ] && [ "${record_identifier}" != "" ]; then | ||
echo "Current IP for ${h}${q}${zones[${g}]} is ${current_ip}" | ||
if [ "${newip}" != "${current_ip}" ]; then | ||
proxy_check="custom${a}_proxied" | ||
proxied=${!proxy_check} | ||
if [ "${proxied}" == "no" ] || [ "${proxied}" == "0" ]; then | ||
update="$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\",\"proxied\":false}")" | ||
elif [ "${proxied}" == "yes" ] || [ "${proxied}" == "1" ]; then | ||
update="$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\",\"proxied\":true}")" | ||
else | ||
echo Proxy Value Not Defined in Custom $a; echo Attempting to Update Record Without Proxy Definition in Request | ||
update=$(curl -s -X PUT https://api.cloudflare.com/client/v4/zones/${zone_identifier}/dns_records/${record_identifier} -H "X-Auth-Email: ${!u}" -H "X-Auth-Key: ${!p}" -H "Content-Type: application/json" --data "{\"type\":\"${rec_type}\",\"name\":\"${h}${q}${zones[${g}]}\",\"content\":\"${newip}\"}") | ||
fi | ||
|
||
if [[ ${update} == *"\"success\":false"* ]]; then | ||
message="API UPDATE FAILED FOR: \"${h}${q}${zones[${g}]}\" DUMPING RESULTS:\n${update}" | ||
echo -e "${message}" | ||
else | ||
message="IP changed to: ${newip}\nProxied: $(echo "${update}" | grep -Po '(?<="proxied":)[^,]*' | head -1)" | ||
echo -e "${message}" | ||
fi | ||
else | ||
echo "No IP change detected for ${h}${q}${zones[${g}]}. No update required." | ||
fi | ||
break | ||
else | ||
echo DNS Zone or Record not found... Continuing... | ||
fi | ||
fi | ||
done | ||
((s++)) | ||
done | ||
done | ||
((s++)) | ||
done | ||
else | ||
echo No Zones Listed... Continuing... | ||
fi | ||
done | ||
else echo No Zones Listed... Continuing... | ||
fi | ||
done | ||
((a++)) | ||
done | ||
|
||
echo "${newip}" > ${ip_file} | ||
|
||
if [ "${1}" != "" ]; then | ||
call_script="${1}" | ||
shift | ||
if [ -e "${call_script}" ]; then | ||
source "${call_script}" "${@}" | ||
elif [ -e "${updatedir}/${call_script}" ]; then | ||
source "${updatedir}/${call_script}" "${@}" | ||
else | ||
echo Secondary Script Specified But File Not Found... Continuing... | ||
fi | ||
fi | ||
((a++)) | ||
done | ||
fi | ||
done | ||
fi |
Oops, something went wrong.