From d62a63c3841d3ef005bbf1494c7cdbfa7c25863f Mon Sep 17 00:00:00 2001 From: David Vazgenovich Shakaryan Date: Tue, 14 Mar 2023 01:23:11 -0700 Subject: update for Hetzner instead of Linode --- hetzner-ddns.sh | 59 ++++++++++++++++++++++ linode-ddns.sh | 56 -------------------- systemd/hetzner-ddns@.service | 6 +++ systemd/hetzner-ddns@.timer | 9 ++++ .../opts.conf | 2 + systemd/linode-ddns@.service | 6 --- systemd/linode-ddns@.timer | 9 ---- .../opts.conf | 2 - 8 files changed, 76 insertions(+), 73 deletions(-) create mode 100755 hetzner-ddns.sh delete mode 100755 linode-ddns.sh create mode 100644 systemd/hetzner-ddns@.service create mode 100644 systemd/hetzner-ddns@.timer create mode 100644 systemd/hetzner-ddns@home.example.org.service.d/opts.conf delete mode 100644 systemd/linode-ddns@.service delete mode 100644 systemd/linode-ddns@.timer delete mode 100644 systemd/linode-ddns@home.example.org.service.d/opts.conf diff --git a/hetzner-ddns.sh b/hetzner-ddns.sh new file mode 100755 index 0000000..7ad8e28 --- /dev/null +++ b/hetzner-ddns.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# +# Copyright 2022 David Vazgenovich Shakaryan +# +# HETZNER_TOKEN= hetzner-ddns.sh + +IP_RESOLVER='https://ifconfig.co' +TARGET="${1}" + +shopt -s extglob + +die() { + [[ -n "${@}" ]] && echo "${@}" >&2 + exit 1 +} + +hetzcurl() { + curl -sfH "Auth-API-Token: ${HETZNER_TOKEN}" \ + "https://dns.hetzner.com/api/v1/${1}" \ + "${@:2}" +} + +ip="$(curl -sf4 "${IP_RESOLVER}")" || die 'IP lookup failed' + +zone_re="${TARGET}" +while [[ "${zone_re}" =~ ^([^\\]*)\.(.*)$ ]]; do + zone_re="(${BASH_REMATCH[1]}\\.)?${BASH_REMATCH[2]}" +done + +res="$(hetzcurl "zones")" || die 'Zones lookup failed' +IFS='|' read zone_id zone_name < <(jq -er --arg re "${zone_re}" \ + '[.zones[] | select(.name | test("\\A" + $re + "\\z"))] | + if . == [] then (null | halt_error) else . end | + max_by(.name | length) | [.id, .name] | join("|")' \ + <<< "${res}") || die 'Zone not found' +rec_name="${TARGET%%?(.)${zone_name}}" +rec_name="${rec_name:-@}" + +res="$(hetzcurl "records?zone_id=${zone_id}")" || die 'Records lookup failed' +rec_id="$(jq -er --arg name "${rec_name}" \ + 'first(.records[] | select(.type == "A" and .name == $name)) | .id' \ + <<< "${res}")" || die 'Record not found' + +res="$(hetzcurl "records/${rec_id}")" || die 'Record lookup failed' +old_ip="$(jq -r '.record.value' <<< "${res}")" + +if [[ "${old_ip}" == "${ip}" ]]; then + echo "IP unchanged from ${ip}" + exit +fi + +data="$(jq -c --arg ip "${ip}" \ + '.record | {zone_id, type, name, value: $ip }' <<< "${res}")" +res="$(hetzcurl "records/${rec_id}" \ + -H 'Content-Type: application/json' \ + -X PUT -d "${data}")" || die 'Record update failed' +new_ip="$(jq -r '.record.value' <<< "${res}")" + +echo "IP changed from ${old_ip} to ${new_ip}" diff --git a/linode-ddns.sh b/linode-ddns.sh deleted file mode 100755 index cd0cd76..0000000 --- a/linode-ddns.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -# -# Copyright 2022 David Vazgenovich Shakaryan -# -# LINODE_TOKEN= linode-ddns.sh - -IP_RESOLVER='https://ifconfig.co' -TARGET="${1}" - -shopt -s extglob - -die() { - [[ -n "${@}" ]] && echo "${@}" >&2 - exit 1 -} - -lincurl() { - curl -sfH "Authorization: Bearer ${LINODE_TOKEN}" \ - "https://api.linode.com/v4/domains/${1}" \ - "${@:2}" -} - -ip="$(curl -sf4 "${IP_RESOLVER}")" || die 'IP lookup failed' - -dom_re="${TARGET}" -while [[ "${dom_re}" =~ ^([^\\]*)\.(.*)$ ]]; do - dom_re="(${BASH_REMATCH[1]}\\.)?${BASH_REMATCH[2]}" -done - -res="$(lincurl)" || die 'Domains lookup failed' -IFS='|' read dom_id dom_name < <(jq -er --arg re "${dom_re}" \ - '[.data[] | select(.domain | test("\\A" + $re + "\\z"))] | - if . == [] then (null | halt_error) else . end | - max_by(.domain | length) | [.id, .domain] | join("|")' \ - <<< "${res}") || die 'Domain not found' -rec_name="${TARGET%%?(.)${dom_name}}" - -res=$(lincurl "${dom_id}/records") || die 'Records lookup failed' -rec_id="$(jq -er --arg name "${rec_name}" \ - 'first(.data[] | select(.type == "A" and .name == $name)) | .id' \ - <<< "${res}")" || die 'Record not found' - -res="$(lincurl "${dom_id}/records/${rec_id}")" || die 'Record lookup failed' -old_ip="$(jq -r '.target' <<< "${res}")" - -if [[ "${old_ip}" == "${ip}" ]]; then - echo "IP unchanged from ${ip}" - exit -fi - -res="$(lincurl "${dom_id}/records/${rec_id}" \ - -H 'Content-Type: application/json' \ - -X PUT -d "{\"target\":\"${ip}\"}")" || die 'Record update failed' -new_ip="$(jq -r '.target' <<< "${res}")" - -echo "IP changed from ${old_ip} to ${new_ip}" diff --git a/systemd/hetzner-ddns@.service b/systemd/hetzner-ddns@.service new file mode 100644 index 0000000..040fb5d --- /dev/null +++ b/systemd/hetzner-ddns@.service @@ -0,0 +1,6 @@ +[Unit] +Description=Hetzner DDNS updater + +[Service] +Type=oneshot +ExecStart=hetzner-ddns.sh %i diff --git a/systemd/hetzner-ddns@.timer b/systemd/hetzner-ddns@.timer new file mode 100644 index 0000000..56b87ea --- /dev/null +++ b/systemd/hetzner-ddns@.timer @@ -0,0 +1,9 @@ +[Unit] +Description=Regular updates of Hetzner DDNS + +[Timer] +OnBootSec=2m +OnUnitActiveSec=30m + +[Install] +WantedBy=timers.target diff --git a/systemd/hetzner-ddns@home.example.org.service.d/opts.conf b/systemd/hetzner-ddns@home.example.org.service.d/opts.conf new file mode 100644 index 0000000..1e62794 --- /dev/null +++ b/systemd/hetzner-ddns@home.example.org.service.d/opts.conf @@ -0,0 +1,2 @@ +[Service] +Environment="HETZNER_TOKEN=access_token" diff --git a/systemd/linode-ddns@.service b/systemd/linode-ddns@.service deleted file mode 100644 index cc445cb..0000000 --- a/systemd/linode-ddns@.service +++ /dev/null @@ -1,6 +0,0 @@ -[Unit] -Description=Linode DDNS updater - -[Service] -Type=oneshot -ExecStart=linode-ddns.sh %i diff --git a/systemd/linode-ddns@.timer b/systemd/linode-ddns@.timer deleted file mode 100644 index d87ed06..0000000 --- a/systemd/linode-ddns@.timer +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Regular updates of Linode DDNS - -[Timer] -OnBootSec=2m -OnUnitActiveSec=30m - -[Install] -WantedBy=timers.target diff --git a/systemd/linode-ddns@home.example.org.service.d/opts.conf b/systemd/linode-ddns@home.example.org.service.d/opts.conf deleted file mode 100644 index cbd2bea..0000000 --- a/systemd/linode-ddns@home.example.org.service.d/opts.conf +++ /dev/null @@ -1,2 +0,0 @@ -[Service] -Environment="LINODE_TOKEN=access_token" -- cgit v1.2.3-70-g09d2