234 lines
4.1 KiB
Text
234 lines
4.1 KiB
Text
|
#!/usr/bin/env bash
|
||
|
|
||
|
quiet=0 # should i shut up?!?!? :<
|
||
|
|
||
|
token="" # the api token
|
||
|
domain="" # the domain to update
|
||
|
|
||
|
record="A" # the record type
|
||
|
ttl="60" # the new time to live
|
||
|
content="" # the new record content
|
||
|
|
||
|
usage() {
|
||
|
printf "usage: cfdns [-hq] [-d DOMAIN] [-t TOKEN] [-r RECORD] [-l TTL] [-cC CONTENT]\n\n"
|
||
|
printf "\t-h\t\tshow the help message\n"
|
||
|
printf "\t-q\t\tquiet output\n"
|
||
|
printf "\t-d DOMAIN\tthe domain name to update\n"
|
||
|
printf "\t-t TOKEN\tthe api token\n"
|
||
|
printf "\t-r RECORD\tthe new record type\n"
|
||
|
printf "\t-l TTL\t\tthe new time to live\n"
|
||
|
printf "\t-c CONTENT\tthe new contents of the record\n"
|
||
|
printf "\t-C RAW CONTENT\tthe new conents of the record (as raw json)\n"
|
||
|
}
|
||
|
|
||
|
chk_command() {
|
||
|
if ! command -v "$1" > /dev/null; then
|
||
|
>&2 echo "error: command '$1' could not be found"
|
||
|
exit 1
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
chk_command "getopts"
|
||
|
chk_command "curl"
|
||
|
chk_command "jq"
|
||
|
|
||
|
while getopts "hqd:t:r:l:c:C:" arg > /dev/null; do
|
||
|
case $arg in
|
||
|
h)
|
||
|
usage
|
||
|
exit 0
|
||
|
;;
|
||
|
q)
|
||
|
quiet=1
|
||
|
;;
|
||
|
d)
|
||
|
domain="${OPTARG}"
|
||
|
;;
|
||
|
t)
|
||
|
token="${OPTARG}"
|
||
|
;;
|
||
|
r)
|
||
|
record="${OPTARG}"
|
||
|
;;
|
||
|
l)
|
||
|
ttl="${OPTARG}"
|
||
|
;;
|
||
|
c)
|
||
|
content="\"content\": \"${OPTARG}\""
|
||
|
;;
|
||
|
C)
|
||
|
content="${OPTARG}"
|
||
|
;;
|
||
|
?)
|
||
|
exit 1
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
|
||
|
if [ ! "$cert" = "cert.pem" ] && [ "$key" = "cert.key" ]; then
|
||
|
name=${cert%.*}
|
||
|
key="$name.key"
|
||
|
fi
|
||
|
|
||
|
log() {
|
||
|
if [ $quiet = 0 ]; then
|
||
|
printf "$*\n" 1>&2
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
step() {
|
||
|
if [ $quiet = 0 ]; then
|
||
|
printf "\033[32m>>> \033[0m$*\n" 1>&2
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
error() {
|
||
|
printf "\033[31merror: \033[0m$*\n" > /dev/stderr
|
||
|
}
|
||
|
|
||
|
die() {
|
||
|
kill $$
|
||
|
}
|
||
|
|
||
|
handle_error() {
|
||
|
errs="$1"
|
||
|
count="$(echo $errs | jq -r ". | length")"
|
||
|
for i in $(seq 0 $(($count - 1))); do
|
||
|
err="$(echo $errs | jq -r ".[$i]")"
|
||
|
error "$(echo $err | jq -r '.message')"
|
||
|
chain="$(echo $err | jq -r '.error_chain')"
|
||
|
if ! [ "$chain" = "null" ]; then
|
||
|
count="$(echo $chain | jq -r ". | length")"
|
||
|
for j in $(seq 0 $(($count - 1))); do
|
||
|
error "$(echo $chain | jq -r ".[$j].message")"
|
||
|
done
|
||
|
fi
|
||
|
done
|
||
|
}
|
||
|
|
||
|
_curl() {
|
||
|
RESPONSE=$(curl --silent --request $1 \
|
||
|
--url "https://api.cloudflare.com/client/v4$2" \
|
||
|
--header "Content-Type: application/json" \
|
||
|
--header "Authorization: Bearer $token" \
|
||
|
--data "$3")
|
||
|
SUCCESS=$(echo $RESPONSE | jq -r ".success")
|
||
|
if [ "$SUCCESS" != "true" ]; then
|
||
|
errs="$(echo $RESPONSE | jq -r .errors)"
|
||
|
handle_error "$errs"
|
||
|
die
|
||
|
fi
|
||
|
|
||
|
echo $RESPONSE | jq ".result"
|
||
|
}
|
||
|
|
||
|
patch() {
|
||
|
_curl "PATCH" "$1" "$2"
|
||
|
}
|
||
|
|
||
|
post() {
|
||
|
_curl "POST" "$1" "$2"
|
||
|
}
|
||
|
|
||
|
get() {
|
||
|
_curl "GET" "$1" ""
|
||
|
}
|
||
|
|
||
|
# Step 1: get the zone the domain is in
|
||
|
zone=$(echo "$domain" | awk -F'.' '{print $(NF-1)"."$(NF);}' 2>/dev/null)
|
||
|
|
||
|
if [ "$zone" = "" ]; then
|
||
|
error "invalid domain: '$domain'"
|
||
|
die
|
||
|
fi
|
||
|
|
||
|
step "fetching zones..."
|
||
|
zones=$(get "/zones")
|
||
|
zone_id="null"
|
||
|
|
||
|
i=0
|
||
|
while true; do
|
||
|
json="$(echo "$zones" | jq ".[$i]")"
|
||
|
|
||
|
if [ "$json" == "null" ]; then
|
||
|
break
|
||
|
fi
|
||
|
|
||
|
name="$(echo "$json" | jq -r ".name")"
|
||
|
id="$(echo "$json" | jq -r ".id")"
|
||
|
|
||
|
log "found zone: $name ($id)"
|
||
|
|
||
|
if [ "$name" == "$zone" ]; then
|
||
|
zone_id="$id"
|
||
|
break
|
||
|
fi
|
||
|
|
||
|
((i=i+1))
|
||
|
done
|
||
|
|
||
|
if [ "$zone_id" == "null" ]; then
|
||
|
error "could not find zone: $zone"
|
||
|
die
|
||
|
fi
|
||
|
|
||
|
# Step 2: get the current record id if it exists
|
||
|
step "fetching records..."
|
||
|
|
||
|
records="$(get "/zones/$zone_id/dns_records")"
|
||
|
current="null"
|
||
|
|
||
|
i=0
|
||
|
while true; do
|
||
|
|
||
|
_record="$(echo "$records" | jq ".[$i]")"
|
||
|
|
||
|
if [ "$_record" == "null" ]; then
|
||
|
break
|
||
|
fi
|
||
|
|
||
|
name="$(echo "$_record" | jq -r ".name")"
|
||
|
type="$(echo "$_record" | jq -r ".type")"
|
||
|
_content="$(echo "$_record" | jq -r ".name")"
|
||
|
id="$(echo "$_record" | jq -r ".id")"
|
||
|
|
||
|
log "found record: $name $type \"$_content\" ($id)"
|
||
|
|
||
|
if [ "$name" == "$domain" ] && [ "$record" = "$type" ]; then
|
||
|
current="$id"
|
||
|
break
|
||
|
fi
|
||
|
|
||
|
((i=i+1))
|
||
|
done
|
||
|
|
||
|
# Step 3: update record
|
||
|
step "updating record"
|
||
|
|
||
|
update() {
|
||
|
patch "/zones/$zone_id/dns_records/$1" "$2"
|
||
|
}
|
||
|
|
||
|
create() {
|
||
|
post "/zones/$zone_id/dns_records" "$1"
|
||
|
}
|
||
|
|
||
|
json="{
|
||
|
\"name\": \"$domain\",
|
||
|
\"proxied\": false,
|
||
|
\"type\": \"$record\",
|
||
|
$content
|
||
|
}"
|
||
|
|
||
|
log $(echo "$json" | jq -C)
|
||
|
|
||
|
if [ "$current" == "null" ]; then
|
||
|
log "no record found... creating new one"
|
||
|
create "$json"
|
||
|
else
|
||
|
log "record found... updating"
|
||
|
update "$current" "$json"
|
||
|
fi
|
||
|
|
||
|
step "successfully updated record"
|