This commit is contained in:
2025-12-15 12:03:22 +00:00
parent 5fd6d6996e
commit 6722b2b23e
3 changed files with 185 additions and 93 deletions
-93
View File
@@ -1,93 +0,0 @@
#! /bin/bash
# Work with DigitalOcean api to update "A" record for a domain.
# Store DigitalOcean API token in file : DIGITALOCEAN_TOKEN
# Store domain to be updated in file : DIGITALOCEAN_DOMAIN
SCRIPT="${BASH_SOURCE[0]}"
SCRIPT_DIR=$(builtin cd "${SCRIPT%/*}" && pwd )
SCRIPT_NAME=${SCRIPT##*/}
REPEAT_CHECK_DIR=$SCRIPT_DIR
REPEAT_CHECK=$REPEAT_CHECK_DIR/REPEAT_CHECK # file to save argument in if successful
DIGITALOCEAN_DOMAIN=`cat $SCRIPT_DIR/DIGITALOCEAN_DOMAIN`
DIGITALOCEAN_TOKEN=`cat $SCRIPT_DIR/DIGITALOCEAN_TOKEN`
# Get IP from command line if available. Otherwise use curl to get public IP.
IP=""
if [ "$#" == "1" ]; then
IP=$1
else
IP=`curl -4 icanhazip.com 2> /dev/null`
fi
# If $IP does not look like a valid address then complain and exit.
# For regular expression, thank you to : https://tecadmin.net/shell-script-validate-ipv4-addresses/
if ! [[ $IP =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
echo Invalid IP address format: $IP
exit
fi
get_a_record_ids() {
curl -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_records | map(select(.type == "A" and .name == "@")) | map(.id) | .[]'
}
add_a_record() {
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-d "{\"type\":\"A\" \
,\"name\":\"@\" \
,\"data\":\"$IP\" \
,\"priority\":null \
,\"port\":null \
,\"ttl\":1800 \
,\"weight\":null \
,\"flags\":null \
,\"tag\":null \
}" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_record.id'
}
delete_record_by_id() {
echo deleting existing A record for $DIGITALOCEAN_DOMAIN
curl -X DELETE \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records/$1" > /dev/null 2>&1
}
replace_a_record() {
for id in `get_a_record_ids`; do
delete_record_by_id $id
done
new_record_id=`add_a_record`
if [ "$new_record_id" == "null" ] ; then
echo unable to add new A record for $DIGITALOCEAN_DOMAIN with value : $1
return 1
fi
echo added new A record for $DIGITALOCEAN_DOMAIN with value : $1
}
# exit if previous successful call was with same argument
if [[ -e $REPEAT_CHECK ]]; then
PREVIOUS_IP=`cat $REPEAT_CHECK`
if [[ "$IP" == "$PREVIOUS_IP" ]]; then
echo previous update was also with argument: \"$IP\" so exiting now to avoid duplicate work.
exit
fi
fi
# attempt to replace A record and, if successful, save arguments to check against next time
if replace_a_record $IP; then
# if successful then save arguments.
echo update worked so saving arguments \"$IP\" in $REPEAT_CHECK
mkdir -p $REPEAT_CHECK_DIR
echo "$IP" > $REPEAT_CHECK
fi
Executable
+134
View File
@@ -0,0 +1,134 @@
#! /bin/sh
# Work with DigitalOcean api to update "A" and "AAAA" records for a domain.
# Store DigitalOcean API token in file : DIGITALOCEAN_TOKEN
# Store domain to be updated in file : DIGITALOCEAN_DOMAIN
ip_version="$1"
if [ -z "${ip_version:-}" ] || ([ "$ip_version" != 4 ] && [ "$ip_version" != 6 ]); then
echo "Error: no valid IP version provided" &>2
echo "Usage: dyndns.bash <4|6>" &>2
exit 1
fi
IP="$(./get_ip_addr.sh $ip_version)"
if [ -z "$IP" ]; then
echo "Error: could not find IP address" &>2
exit 1
fi
SCRIPT="$0"
SCRIPT_DIR=$(cd "${SCRIPT%/*}" && pwd )
SCRIPT_NAME=${SCRIPT##*/}
REPEAT_CHECK_DIR=$SCRIPT_DIR
REPEAT_CHECK_A=$REPEAT_CHECK_DIR/REPEAT_CHECK_A
REPEAT_CHECK_AAAA=$REPEAT_CHECK_DIR/REPEAT_CHECK_AAAA
REPEAT_CHECK="$([ $ip_version = 4 ] && echo $REPEAT_CHECK_A || echo $REPEAT_CHECK_AAAA)"
DIGITALOCEAN_DOMAIN=`cat $SCRIPT_DIR/DIGITALOCEAN_DOMAIN`
DIGITALOCEAN_TOKEN=`cat $SCRIPT_DIR/DIGITALOCEAN_TOKEN`
get_a_record_ids() {
curl -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_records | map(select(.type == "A" and .name == "@")) | map(.id) | .[]'
}
get_aaaa_record_ids() {
curl -X GET \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_records | map(select(.type == "AAAA" and .name == "@")) | map(.id) | .[]'
}
add_a_record() {
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-d "{\"type\":\"A\" \
,\"name\":\"@\" \
,\"data\":\"$IP\" \
,\"priority\":null \
,\"port\":null \
,\"ttl\":1800 \
,\"weight\":null \
,\"flags\":null \
,\"tag\":null \
}" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_record.id'
}
add_aaaa_record() {
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
-d "{\"type\":\"AAAA\" \
,\"name\":\"@\" \
,\"data\":\"$IP\" \
,\"priority\":null \
,\"port\":null \
,\"ttl\":1800 \
,\"weight\":null \
,\"flags\":null \
,\"tag\":null \
}" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records" 2> /dev/null | jq '.domain_record.id'
}
delete_record_by_id() {
echo deleting existing A/AAAA record for $DIGITALOCEAN_DOMAIN
curl -X DELETE \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $DIGITALOCEAN_TOKEN" \
"https://api.digitalocean.com/v2/domains/$DIGITALOCEAN_DOMAIN/records/$1" > /dev/null 2>&1
}
replace_a_records() {
for id in `get_a_record_ids`; do
delete_record_by_id $id
done
new_record_id=`add_a_record`
if [ "$new_record_id" = "null" ] ; then
echo unable to add new A record for $DIGITALOCEAN_DOMAIN with value: $IP
return 1
fi
echo added new A record for $DIGITALOCEAN_DOMAIN with value: $IP
}
replace_aaaa_records() {
for id in `get_aaaa_record_ids`; do
delete_record_by_id $id
done
new_record_id=`add_aaaa_record`
if [ "$new_record_id" = "null" ] ; then
echo unable to add new AAAA record for $DIGITALOCEAN_DOMAIN with value: $IP
return 1
fi
echo added new AAAA record for $DIGITALOCEAN_DOMAIN with value: $IP
}
replace_records() {
[ $ip_version = 4 ] && replace_a_records || replace_aaaa_records
}
# exit if previous successful call was with same argument
if [ -e $REPEAT_CHECK ]; then
PREVIOUS_IP=`cat $REPEAT_CHECK`
if [ "$IP" = "$PREVIOUS_IP" ]; then
echo previous update was also with argument: \"$IP\" so exiting now to avoid duplicate work.
exit
fi
fi
# attempt to replace records and, if successful, save arguments to check against next time
if replace_records $IP; then
# if successful then save arguments.
echo update worked so saving arguments \"$IP\" in $REPEAT_CHECK
mkdir -p $REPEAT_CHECK_DIR
echo "$IP" > $REPEAT_CHECK
fi
Executable
+51
View File
@@ -0,0 +1,51 @@
#!/bin/sh
ip_version="$1"
if [ -z "${ip_version:-}" ] || ([ "$ip_version" != 4 ] && [ "$ip_version" != 6 ]); then
echo "Usage: get_ip_addr <4|6>" &>2
exit 1
fi
if [ $ip_version = 4 ]; then
curl -4 http://icanhazip.com 2> /dev/null
exit 0
fi
set -eu
CONN_NAME=${CONN_NAME:-nevis}
conn_device_name="$(nmcli --fields NAME,DEVICE con show | grep ^$CONN_NAME | sed 's/\s\+/ /g' | cut -d' ' -f 2)"
if [ -z "${conn_device_name:-}" ]; then
echo "Could not find the connection device name for connection: \"$CONN_NAME\"" &>2
exit 1
fi
device_line_no="$(ip addr | grep -En ^[0-9]+:\ $conn_device_name | cut -d':' -f 1)"
if [ -z "${device_line_no:-}" ]; then
echo "Could not find device: \"$conn_device_name\" in output of ip addr" &>2
exit 1
fi
ip_addr_output_for_device="$(ip addr | tail -n +$(($device_line_no + 1)))"
device_no="$(ip addr | tail -n +$device_line_no | head -n 1 | cut -d':' -f 1)"
next_device_no=$(($device_no + 1))
next_device_line_no="$(ip addr | grep -En ^${next_device_no}:\ | cut -d':' -f 1)"
if [ -n "${next_device_line_no:-}" ]; then
len=$(($next_device_line_no - ($device_line_no + 1)))
ip_addr_output_for_device="$(echo $ip_addr_output_for_device | head -n $len)"
fi
ipv4_regex="([a-z0-9]{1,3}\.){3}[a-z0-9]{1,3}"
ipv6_regex="([a-z0-9]{1,4}:){7}[a-z0-9]{1,4}"
if [ "$ip_version" = "4" ]; then
ip_regex="$ipv4_regex"
else
ip_regex="$ipv6_regex"
fi
ip="$(echo "$ip_addr_output_for_device" | grep "scope global" | grep -oE $ip_regex | head -n 1)"
if [ -z "${ip:-}" ]; then
echo "Could not find global IP in output of ip addr under device: $conn_device_name ($CONN_NAME)"
exit 1
fi
echo "$ip"