Skip to content

Instantly share code, notes, and snippets.

@zsimic
Last active November 20, 2023 02:39
Show Gist options
  • Save zsimic/c39dd9686c6d6b0d149a67ff23286b99 to your computer and use it in GitHub Desktop.
Save zsimic/c39dd9686c6d6b0d149a67ff23286b99 to your computer and use it in GitHub Desktop.
Linode dynamic dns on ubiquiti edge router
#!/bin/bash
# See https://gist.github.com/zsimic/c39dd9686c6d6b0d149a67ff23286b99 for docs on how to use
# Note: you can invoke with LOGFILE= for troubleshooting
[ -z "$LOGFILE" ] && LOGFILE=/var/log/messages
if [ -z "$1" -a -f $LOGFILE ]; then # Pass any command line arg to avoid the logging redirect
exec $0 run 1>> $LOGFILE 2>&1
fi
function do_log {
echo "$(date +'%h %e %T') $(hostname) linode-ddns: $@"
}
function usage {
do_log "Usage error: $@"
exit 1
}
# Note: you can invoke with CFGFILE= for troubleshooting
[ -z "$CFGFILE" ] && CFGFILE=~/.ssh/linode-ddns-cfg.sh
CFGFOLDER=$(dirname $CFGFILE)
IPFILE="$CFGFOLDER/.last-ip" # Allows to do nothing when IP didn't change, remove file to force re-run
[ ! -f $CFGFILE ] && usage "Config file $CFGFILE does not exist"
source $CFGFILE
[ -z "$TOKEN" ] && usage "TOKEN not defined in $CFGFILE"
[ -z "$RECORDS" ] && usage "RECORDS not defined in $CFGFILE"
URL="https://api.linode.com/v4"
H1="Content-type: application/json"
H2="Authorization: Bearer $TOKEN"
CURRENT_IP=$(ip address show eth0 | grep -Eo 'inet [0-9\.]+' | cut -d " " -f2)
LAST_IP=$([ -f $IPFILE ] && head -1 $IPFILE)
[[ $LAST_IP == $CURRENT_IP ]] && exit 0
DBG=""
[ ! -d /config/scripts ] && DBG="echo" # Useful to debug, allows to perform actual REST call only on router
for record in $RECORDS; do
OUTPUT=$($DBG curl -s -H"$H1" -H"$H2" "$@" -XPUT $URL/domains/$record -d "{\"target\": \"$CURRENT_IP\"}")
if [ $? -ne 0 ]; then
do_log "Updating record $record failed: $OUTPUT"
exit 1
fi
done
do_log "Home IP updated to $CURRENT_IP"
[ ! -f $IPFILE ] && touch $IPFILE && chmod 0600 $IPFILE # chmod just because domainId is logged there...
echo $CURRENT_IP > $IPFILE
echo "# Updated on $(date) for $RECORDS" >> $IPFILE
@dgaidula
Copy link

This is awesome, thanks! I just added ipv6 support to this bc comcast SLAAC can supposedly change.


# See https://gist.github.com/zsimic/c39dd9686c6d6b0d149a67ff23286b99 for docs on how to use

# Note: you can invoke with LOGFILE= for troubleshooting
[ -z "$LOGFILE" ] && LOGFILE=/var/log/messages
if [ -z "$1" -a -f $LOGFILE ]; then  # Pass any command line arg to avoid the logging redirect
    exec $0 run 1>> $LOGFILE 2>&1
fi

function do_log {
    echo "$(date +'%h %e %T') $(hostname) linode-ddns: $@"
}

function usage {
    do_log "Usage error: $@"
    exit 1
}

# Note: you can invoke with CFGFILE= for troubleshooting
[ -z "$CFGFILE" ] && CFGFILE=~/.ssh/linode-ddns-cfg.sh
CFGFOLDER=$(dirname $CFGFILE)
IPFILE="$CFGFOLDER/.last-ip"  # Allows to do nothing when IP didn't change, remove file to force re-run
IPFILE6="$CFGFOLDER/.last-ip6"  # Allows to do nothing when IP didn't change, remove file to force re-run

[ ! -f $CFGFILE ] && usage "Config file $CFGFILE does not exist"
source $CFGFILE
[ -z "$TOKEN" ] && usage "TOKEN not defined in $CFGFILE"
[ -z "$RECORDS" ] && usage "RECORDS not defined in $CFGFILE"
[ -z "$RECORDS6" ] && usage "RECORDS6 not defined in $CFGFILE"

URL="https://api.linode.com/v4"
H1="Content-type: application/json"
H2="Authorization: Bearer $TOKEN"
CURRENT_IP=$(ip address show eth0 | grep -Eo 'inet [0-9\.]+' | cut -d " " -f2)
CURRENT_IP6=$(ip address show eth0 | grep -Eo 'inet6 [0-9a-f\:]+' | cut -d " " -f2 | head -1)

LAST_IP=$([ -f $IPFILE ] && head -1 $IPFILE)
LAST_IP6=$([ -f $IPFILE6 ] && head -1 $IPFILE6)

[[ $LAST_IP == $CURRENT_IP && $LAST_IP6 == $CURRENT_IP6 ]] && exit 0

DBG=""
[ ! -d /config/scripts ] && DBG="echo"  # Useful to debug, allows to perform actual REST call only on router
if [[ $LAST_IP != $CURRENT_IP ]]; then
	for record in $RECORDS; do
		OUTPUT=$($DBG curl -s -H"$H1" -H"$H2" "$@" -XPUT $URL/domains/$record -d "{\"target\": \"$CURRENT_IP\"}")
		if [ $? -ne 0 ]; then
			do_log "Updating record $record failed: $OUTPUT"
			exit 1
		fi
	done
fi

if [[ $LAST_IP6 != $CURRENT_IP6 ]]; then
	for record in $RECORDS6; do
		OUTPUT=$($DBG curl -s -H"$H1" -H"$H2" "$@" -XPUT $URL/domains/$record -d "{\"target\": \"$CURRENT_IP6\"}")
		if [ $? -ne 0 ]; then
			do_log "Updating record $record failed: $OUTPUT"
			exit 1
		fi
	done
fi


do_log "Home IP updated to $CURRENT_IP $CURRENT_IP6"
[ ! -f $IPFILE ] && touch $IPFILE && chmod 0600 $IPFILE  # chmod just because domainId is logged there...
echo $CURRENT_IP > $IPFILE
echo "# Updated on $(date) for $RECORDS" >> $IPFILE

#IP6 Version
[ ! -f $IPFILE6 ] && touch $IPFILE6 && chmod 0600 $IPFILE6  # chmod just because domainId is logged there...
echo $CURRENT_IP6 > $IPFILE6
echo "# Updated on $(date) for $RECORDS6" >> $IPFILE6

@zsimic
Copy link
Author

zsimic commented Nov 20, 2023

Awesome! Thank you :)
I'm not super familiar with ipv6 yet, I thought this wasn't needed with ipv6 :)
Ie, addresses are so plentiful that they can be trivially static...

Routers may be intentionally configured to change their ipv6 every now and then, but that's more to avoid tracking (ie: for privacy reasons), so this addition could play well into that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment