#!/bin/bash # I, Ian Kelling, follow the GNU license recommendations at # https://www.gnu.org/licenses/license-recommendations.en.html. They # recommend that small programs, < 300 lines, be licensed under the # Apache License 2.0. This file contains or is part of one or more small # programs. If a small program grows beyond 300 lines, I plan to switch # its license to GPL. # Copyright 2024 Ian Kelling # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # http://www.apache.org/licenses/LICENSE-2.0 # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. set -e; . /usr/local/lib/bash-bear; set +e [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@" this_file="$(readlink -f -- "${BASH_SOURCE[0]}")" readonly this_file this_dir="${this_file%/*}" readonly this_dir cd "$this_dir" usage() { cat <&2; exit 1; } force=false # default temp=$(getopt -l help hf "$@") || usage 1 eval set -- "$temp" while true; do case $1 in -f) force=true ;; --) shift; break ;; *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;; esac shift done ##### end command line parsing ######## main() { fqdn=$(hostname -f) domaintmp=${fqdn#*.} hostnametmp=${fqdn%%.*} # i for internet fqdn=${hostnametmp}i.${domaintmp} up4=false if ! tmp=$(ip -4 route get 85.119.83.50 2>/dev/null); then # our internet is down if [[ $INVOCATION_ID ]]; then return 0 else echo $0: failed to get route, giving up exit 0 fi fi read -r _ _ gateway _ ifdev _ <<<"$tmp" case $gateway in 10.2.0.1) dyndomain=b8.nz ;; *) return 0 ;; esac # We check if we are at home by testing gateway ssh # fingerprint. However, if we found in the past that we are, I dont # like to spam its logs with ssh login attempts, so just check if our # gateway interface has an increasing amount of packets sent + # received from last time. athome=false if [[ -s /dev/shm/dynamic-ip-update-state ]]; then oldbytes=$(cat /dev/shm/dynamic-ip-update-state) newbytes=$(awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev) if [[ $oldbytes == [1-9]* ]] && (( newbytes >= oldbytes )); then athome=true printf "%s\n" "$newbytes" >/dev/shm/dynamic-ip-update-state fi fi if ! $athome && timeout -s 9 5 ssh-keyscan -p 2220 -t rsa $gateway 2>/dev/null | grep -qFx "[$gateway]:2220 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCH+/h1dGEfKEusBblndU2e6QT4wLCm5+yqr/sqh/0X9YfjR7BfWWm8nNmuP55cYc+Wuf5ljB1H1acXEcsl1y8e0j3agHfF0V74FE1N1zz5nn2Ep8NHnmqgEhza38ZxMPh+4p3X7zklEKU7+3SzybKBi8sg0wLzlS2LM0JaUN80zR2sK11Kye3dURUXPk78u5wodOkgcEYRwSYaDMJlUzWP+poRXIDJwFaMQnwmxbl/c84yOyaU0x/d6hFwoRscWecihX+vvBNeSyxR4xr2HDOyUWwJkctyAgt2p7w3tfkXOKcCRzTAjGVIMQLTvo0sG/yJbcyHoEFdFybCsgDvfyYn"; then athome=true awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev > /dev/shm/dynamic-ip-update-state fi if $athome; then if ! cur4="$(dig +short $dyndomain @iankelling.org | tail -1)"; then if [[ ! $INVOCATION_ID ]]; then echo "$0: dig failed. internet looks down. giving up" fi return 0 fi if ip4=$(curl --connect-timeout 10 -s4 https://iankelling.org/cgi/pubip); then if $force || [[ $cur4 && $ip4 && $cur4 != "$ip4" ]]; then up4=true # update ipv4 fi fi fi # may not be set yet so allow fail cur6="$(host -4 -t aaaa $fqdn iankelling.org | sed -rn 's/.*has IPv6 address (.*)/\1/p;T;q')" ||: up6=false out6=$(curl --connect-timeout 10 -s6 https://iankelling.org/cgi/pubip) ||: # failure allowed if we have no ipv6 if [[ $out6 ]]; then dev=$(ip -o a show to $out6 | awk '{print $2}') # we use slaac with privacy extension, so get our less private more permanent address mac=$(cat /sys/class/net/$dev/address) IFS=: read -ra f <<<$mac; set -- ${f[@]} ip6=${out6%:*:*:*:*}:$(printf %x $((0x$1 + 2)))$2:$3'ff:fe'$4:$5$6 # in case we aren't using slaac if ! ip a | grep "^ *inet6 $ip6/" &>/dev/null; then ip6=$out6 fi fi if $force || [[ $cur6 != "$ip6" ]]; then up6=true fi # if we failed to get our ipv6 addr, we probably have ipv6 # connectivity problem. if [[ ! $ip6 ]]; then ip_arg=-4 fi if ! $up4 && ! $up6; then return 0 fi # note, a simpler way to do this would be to ssh and use # "${SSH_CLIENT%% *} # to update bind if needed. tmpf=$(mktemp) cat >>$tmpf <>$tmpf <>$tmpf <>$tmpf <>$tmpf < nsupdate_fail_limit )); then echo error: nsupdate is persistently failing >&2 exit 1 fi rm -f $tmpf } loop-main() { while true; do main sleep 30 done } nsupdate_fails=0 if [[ $INVOCATION_ID ]]; then nsupdate_fail_limit=10 loop-main else nsupdate_fail_limit=0 main fi exit 0 # # # persistent initial setup for this: # # # create files in /a/c/machine_specific/vps/filesystem/etc/bind # # # note, conflink also does some group ownership stuff. # mkc /p/c/machine_specific/vps/filesystem/etc/bind # sudo dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST b8.nz # user=$(id -un) # sudo chown $user:$user * # f=key.b8.nz # cat >$tmpf <