Compare commits

..

3 Commits

Author SHA1 Message Date
Jason K 4ba3e79ce3
Merge pull request #5 from paul-nelson-baker/main
Environment Input Variables with Validation
2021-08-08 18:47:15 +08:00
Paul FREAKN Baker a0362bacba Reading from enviroment variables with validation
This change allows one to set a environment variables prior to executing
the script. This enables end-users to avoid editing the script itself,
which in turns makes it functionally easier. This also enables end-users
to potentially just drop this script into arbitrary environments without
changing the contents (EG: Docker containers or VMs under configuration
management)
2021-07-20 11:43:06 -06:00
Paul FREAKN Baker 77613a34a4 Fixing potential globbing matching in condition
https://github.com/koalaman/shellcheck/wiki/SC2053
2021-07-20 11:28:15 -06:00
2 changed files with 77 additions and 63 deletions

View File

@ -1,4 +1,34 @@
# Cloudflare Dynamic DNS IP Updater # Cloudflare Dynamic DNS IP Updater
<img alt="GitHub" src="https://img.shields.io/github/license/K0p1-Git/cloudflare-ddns-updater?color=black"> <img alt="GitHub last commit (branch)" src="https://img.shields.io/github/last-commit/K0p1-Git/cloudflare-ddns-updater/main"> <img alt="GitHub contributors" src="https://img.shields.io/github/contributors/K0p1-Git/cloudflare-ddns-updater">
This script is used to update dynamic DNS entries for accounts on Cloudflare.
This script is used to update Dynamic DNS (DDNS) service based on Cloudflare! Access your home network remotely via a custom domain name without a static IP! Written in pure BASH. ## Installation
```bash
git clone https://github.com/K0p1-Git/cloudflare-ddns-updater.git
```
## Usage
This script is used with crontab. Specify the frequency of execution through crontab.
```bash
# ┌───────────── minute (0 - 59)
# │ ┌───────────── hour (0 - 23)
# │ │ ┌───────────── day of the month (1 - 31)
# │ │ │ ┌───────────── month (1 - 12)
# │ │ │ │ ┌───────────── day of the week (0 - 6) (Sunday to Saturday 7 is also Sunday on some systems)
# │ │ │ │ │ ┌───────────── command to issue
# │ │ │ │ │ │
# │ │ │ │ │ │
# * * * * * /bin/bash {Location of the script}
```
## Contributing
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.
## Reference
This script was made with reference from [Keld Norman](https://www.youtube.com/watch?v=vSIBkH7sxos) video.
## License
[MIT](https://github.com/K0p1-Git/cloudflare-ddns-updater/blob/main/LICENSE)

View File

@ -1,42 +1,55 @@
#!/bin/bash #!/bin/bash
## change to "bin/sh" when necessary set -u
auth_email="" # The email used to login 'https://dash.cloudflare.com' auth_email="${DDNS_AUTH_EMAIL:-}" # The email used to login 'https://dash.cloudflare.com'
auth_method="token" # Set to "global" for Global API Key or "token" for Scoped API Token auth_method="${DDNS_AUTH_METHOD:-token}" # Set to "global" for Global API Key or "token" for Scoped API Token
auth_key="" # Your API Token or Global API Key auth_key="${DDNS_AUTH_KEY:-}" # Your API Token or Global API Key
zone_identifier="" # Can be found in the "Overview" tab of your domain zone_identifier="${DDNS_ZONE_IDENTIFIER:-}" # Can be found in the "Overview" tab of your domain
record_name="" # Which record you want to be synced record_name="${DDNS_RECORD_NAME:-}" # Which record you want to be synced
ttl="3600" # Set the DNS TTL (seconds) proxy="${DDNS_PROXY:-false}" # Set the proxy to true or false
proxy="false" # Set the proxy to true or false
sitename="" # Title of site "Example Site"
slackchannel="" # Slack Channel #example
slackuri="" # URI for Slack WebHook "https://hooks.slack.com/services/xxxxx"
discorduri="" # URI for Discord WebHook "https://discordapp.com/api/webhooks/xxxxx"
###########################################
## Validate variables have been set
###########################################
if [ -z "${auth_email}" ]; then
logger "DDNS Updater: DDNS_AUTH_EMAIL was unset"
exit 1
fi
if [ -z "${auth_method}" ]; then
logger "DDNS Updater: DDNS_AUTH_METHOD was unset"
exit 1
fi
if [ -z "${auth_key}" ]; then
logger "DDNS Updater: DDNS_AUTH_KEY was unset"
exit 1
fi
if [ -z "${zone_identifier}" ]; then
logger "DDNS Updater: DDNS_ZONE_IDENTIFIER was unset"
exit 1
fi
if [ -z "${record_name}" ]; then
logger "DDNS Updater: DDNS_RECORD_NAME was unset"
exit 1
fi
if [ -z "${proxy}" ]; then
logger "DDNS Updater: DDNS_PROXY was unset"
exit 1
fi
########################################### ###########################################
## Check if we have a public IP ## Check if we have a public IP
########################################### ###########################################
ipv4_regex='([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])' ip=$(curl -s https://api.ipify.org || curl -s https://ipv4.icanhazip.com/)
ip=$(curl -s -4 https://cloudflare.com/cdn-cgi/trace | grep -E '^ip'); ret=$?
if [[ ! $ret == 0 ]]; then # In the case that cloudflare failed to return an ip.
# Attempt to get the ip from other websites.
ip=$(curl -s https://api.ipify.org || curl -s https://ipv4.icanhazip.com)
else
# Extract just the ip from the ip line from cloudflare.
ip=$(echo $ip | sed -E "s/^ip=($ipv4_regex)$/\1/")
fi
# Use regex to check for proper IPv4 format. if [ "${ip}" == "" ]; then
if [[ ! $ip =~ ^$ipv4_regex$ ]]; then logger -s "DDNS Updater: No public IP found"
logger -s "DDNS Updater: Failed to find a valid IP." exit 1
exit 2
fi fi
########################################### ###########################################
## Check and set the proper auth header ## Check and set the proper auth header
########################################### ###########################################
if [[ "${auth_method}" == "global" ]]; then if [ "${auth_method}" == "global" ]; then
auth_header="X-Auth-Key:" auth_header="X-Auth-Key:"
else else
auth_header="Authorization: Bearer" auth_header="Authorization: Bearer"
@ -47,10 +60,7 @@ fi
########################################### ###########################################
logger "DDNS Updater: Check Initiated" logger "DDNS Updater: Check Initiated"
record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?type=A&name=$record_name" \ record=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records?name=$record_name" -H "X-Auth-Email: $auth_email" -H "$auth_header $auth_key" -H "Content-Type: application/json")
-H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \
-H "Content-Type: application/json")
########################################### ###########################################
## Check if the domain has an A record ## Check if the domain has an A record
@ -63,9 +73,9 @@ fi
########################################### ###########################################
## Get existing IP ## Get existing IP
########################################### ###########################################
old_ip=$(echo "$record" | sed -E 's/.*"content":"(([0-9]{1,3}\.){3}[0-9]{1,3})".*/\1/') old_ip=$(echo "$record" | grep -Po '(?<="content":")[^"]*' | head -1)
# Compare if they're the same # Compare if they're the same
if [[ $ip == $old_ip ]]; then if [[ $ip == "${old_ip}" ]]; then
logger "DDNS Updater: IP ($ip) for ${record_name} has not changed." logger "DDNS Updater: IP ($ip) for ${record_name} has not changed."
exit 0 exit 0
fi fi
@ -73,51 +83,25 @@ fi
########################################### ###########################################
## Set the record identifier from result ## Set the record identifier from result
########################################### ###########################################
record_identifier=$(echo "$record" | sed -E 's/.*"id":"(\w+)".*/\1/') record_identifier=$(echo "$record" | grep -Po '(?<="id":")[^"]*' | head -1)
########################################### ###########################################
## Change the IP@Cloudflare using the API ## Change the IP@Cloudflare using the API
########################################### ###########################################
update=$(curl -s -X PATCH "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" \ update=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$zone_identifier/dns_records/$record_identifier" \
-H "X-Auth-Email: $auth_email" \ -H "X-Auth-Email: $auth_email" \
-H "$auth_header $auth_key" \ -H "$auth_header $auth_key" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
--data "{\"type\":\"A\",\"name\":\"$record_name\",\"content\":\"$ip\",\"ttl\":\"$ttl\",\"proxied\":${proxy}}") --data "{\"id\":\"$zone_identifier\",\"type\":\"A\",\"proxied\":${proxy},\"name\":\"$record_name\",\"content\":\"$ip\"}")
########################################### ###########################################
## Report the status ## Report the status
########################################### ###########################################
case "$update" in case "$update" in
*"\"success\":false"*) *"\"success\":false"*)
echo -e "DDNS Updater: $ip $record_name DDNS failed for $record_identifier ($ip). DUMPING RESULTS:\n$update" | logger -s logger -s "DDNS Updater: $ip $record_name DDNS failed for $record_identifier ($ip). DUMPING RESULTS:\n$update"
if [[ $slackuri != "" ]]; then
curl -L -X POST $slackuri \
--data-raw '{
"channel": "'$slackchannel'",
"text" : "'"$sitename"' DDNS Update Failed: '$record_name': '$record_identifier' ('$ip')."
}'
fi
if [[ $discorduri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$sitename"' DDNS Update Failed: '$record_name': '$record_identifier' ('$ip')."
}' $discorduri
fi
exit 1;; exit 1;;
*) *)
logger "DDNS Updater: $ip $record_name DDNS updated." logger "DDNS Updater: $ip $record_name DDNS updated."
if [[ $slackuri != "" ]]; then
curl -L -X POST $slackuri \
--data-raw '{
"channel": "'$slackchannel'",
"text" : "'"$sitename"' Updated: '$record_name''"'"'s'""' new IP Address is '$ip'"
}'
fi
if [[ $discorduri != "" ]]; then
curl -i -H "Accept: application/json" -H "Content-Type:application/json" -X POST \
--data-raw '{
"content" : "'"$sitename"' Updated: '$record_name''"'"'s'""' new IP Address is '$ip'"
}' $discorduri
fi
exit 0;; exit 0;;
esac esac