fix for broken ipv6
[distro-setup] / dynamic-ip-update
1 #!/bin/bash
2
3 set -e; . /usr/local/lib/bash-bear; set +e
4 [[ $EUID == 0 ]] || exec sudo -E "${BASH_SOURCE[0]}" "$@"
5
6 this_file="$(readlink -f -- "${BASH_SOURCE[0]}")"
7 readonly this_file
8 this_dir="${this_file%/*}"
9 readonly this_dir
10 cd "$this_dir"
11
12 usage() {
13 cat <<EOF
14 Usage: ${0##*/} [-f]
15 Update ip in remote nameserver.
16
17 -f Force update even if ip hasn't changed.
18 -h|--help Print help and exit.
19
20 Note: Uses util-linux getopt option parsing: spaces between args and
21 options, short options can be combined, options before args.
22 EOF
23 exit $1
24 }
25
26 ##### begin command line parsing ########
27
28 # ensure we can handle args with spaces or empty.
29 ret=0; getopt -T || ret=$?
30 [[ $ret == 4 ]] || { echo "Install util-linux for enhanced getopt" >&2; exit 1; }
31
32 force=false # default
33 temp=$(getopt -l help hf "$@") || usage 1
34 eval set -- "$temp"
35 while true; do
36 case $1 in
37 -f) force=true ;;
38 --) shift; break ;;
39 *) echo "$0: unexpected args: $*" >&2 ; usage 1 ;;
40 esac
41 shift
42 done
43
44 ##### end command line parsing ########
45
46 main() {
47
48 fqdn=$(hostname -f)
49 domaintmp=${fqdn#*.}
50 hostnametmp=${fqdn%%.*}
51 # i for internet
52 fqdn=${hostnametmp}i.${domaintmp}
53
54 up4=false
55
56 if ! tmp=$(ip -4 route get 85.119.83.50 2>/dev/null); then
57 # our internet is down
58 if [[ $INVOCATION_ID ]]; then
59 return 0
60 else
61 echo $0: failed to get route, giving up
62 exit 0
63 fi
64 fi
65 read -r _ _ gateway _ ifdev _ <<<"$tmp"
66
67 case $gateway in
68 10.2.0.1)
69 dyndomain=b8.nz
70 dynhost=i.b8.nz
71 ;;
72 *)
73 return 0
74 ;;
75 esac
76
77 # We check if we are at home by testing gateway ssh
78 # fingerprint. However, if we found in the past that we are, I dont
79 # like to spam its logs with ssh login attempts, so just check if our
80 # gateway interface has an increasing amount of packets sent +
81 # received from last time.
82 athome=false
83 if [[ -s /dev/shm/dynamic-ip-update-state ]]; then
84 oldbytes=$(cat /dev/shm/dynamic-ip-update-state)
85 newbytes=$(awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev)
86 if [[ $oldbytes == [1-9]* ]] && (( newbytes >= oldbytes )); then
87 athome=true
88 printf "%s\n" "$newbytes" >/dev/shm/dynamic-ip-update-state
89 fi
90 fi
91 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
92 athome=true
93 awk '$1 == "'$ifdev':" {print $2 + $10}' /proc/net/dev > /dev/shm/dynamic-ip-update-state
94 fi
95
96
97 if $athome; then
98 if ! cur4="$(dig +short $dynhost @iankelling.org | tail -1)"; then
99 if [[ ! $INVOCATION_ID ]]; then
100 echo "$0: dig failed. internet looks down. giving up"
101 fi
102 return 0
103 fi
104 if ip4=$(curl --connect-timeout 10 -s4 https://iankelling.org/cgi/pubip); then
105 if $force || [[ $cur4 && $ip4 && $cur4 != $ip4 ]]; then
106 up4=true # update ipv4
107 fi
108 fi
109 fi
110
111 # may not be set yet so allow fail
112 cur6="$(host -4 -t aaaa $fqdn iankelling.org | sed -rn 's/.*has IPv6 address (.*)/\1/p;T;q')" ||:
113
114 up6=false
115
116 out6=$(curl --connect-timeout 10 -s6 https://iankelling.org/cgi/pubip) ||: # failure allowed if we have no ipv6
117
118 if [[ $out6 ]]; then
119 dev=$(ip -o a show to $out6 | awk '{print $2}')
120 # we use slaac with privacy extension, so get our less private more permanent address
121 mac=$(cat /sys/class/net/$dev/address)
122
123 IFS=: read -a f <<<$mac; set -- ${f[@]}
124 ip6=${out6%:*:*:*:*}:$(printf %x $((0x$1 + 2)))$2:$3'ff:fe'$4:$5$6
125 # in case we aren't using slaac
126 if ! ip a | grep "^ *inet6 $ip6/" &>/dev/null; then
127 ip6=$out6
128 fi
129 fi
130
131 if $force || [[ $cur6 != $ip6 ]]; then
132 up6=true
133 fi
134
135 # if we failed to get our ipv6 addr, we probably have ipv6
136 # connectivity problem.
137 if [[ ! $ip6 ]]; then
138 ip_arg=-4
139 fi
140
141 if ! $up4 && ! $up6; then
142 return 0
143 fi
144
145 # note, a simpler way to do this would be to ssh and use
146 # "${SSH_CLIENT%% *}
147 # to update bind if needed.
148
149 f=$(mktemp)
150 cat >>$f <<EOF
151 server iankelling.org
152 zone b8.nz
153 EOF
154
155 if $up4; then
156 cat >>$f <<EOF
157 update delete $dynhost. A
158 update add $dynhost. 300 A $ip4
159 update delete $dyndomain. A
160 update add $dyndomain. 300 A $ip4
161 EOF
162 fi
163
164 if $up6; then
165 if [[ $ip6 ]]; then
166 cat >>$f <<EOF
167 update delete $fqdn. AAAA
168 update add $fqdn. 60 AAAA $ip6
169 EOF
170 else
171 cat >>$f <<EOF
172 update delete $fqdn. AAAA
173 EOF
174 fi
175 fi
176
177 cat >>$f <<EOF
178 show
179 send
180 answer
181 quit
182 EOF
183
184 chronic nsupdate $ip_arg -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f || nsupdate_fails=$((nsupdate_fails + 1))
185 sed -i 's/^server .*/server bk.b8.nz/' $f
186 chronic nsupdate $ip_arg -k /p/c/machine_specific/vps/filesystem/etc/bind/Kb8.nz.*.private <$f || nsupdate_fails=$((nsupdate_fails + 1))
187 if (( nsupdate_fails > nsupdate_fail_limit )); then
188 echo error: nsupdate is persistently failing >&2
189 exit 1
190 fi
191 }
192
193 loop-main() {
194 while true; do
195 main
196 sleep 30
197 done
198 }
199
200 nsupdate_fails=0
201 if [[ $INVOCATION_ID ]]; then
202 nsupdate_fail_limit=10
203 loop-main
204 else
205 nsupdate_fail_limit=0
206 main
207 fi
208
209 exit 0
210
211
212 # # # persistent initial setup for this:
213 # # # create files in /a/c/machine_specific/vps/filesystem/etc/bind
214 # # # note, conflink also does some group ownership stuff.
215 # mkc /p/c/machine_specific/vps/filesystem/etc/bind
216 # sudo dnssec-keygen -a HMAC-SHA512 -b 512 -n HOST b8.nz
217 # user=$(id -un)
218 # sudo chown $user:$user *
219
220
221 # f=key.b8.nz
222 # cat >$f <<EOF
223 # key b8.nz. {
224 # algorithm HMAC-SHA512;
225 # secret "$(awk '$1 == "Key:" {print $2}' Kb8.nz.*.private)";
226 # };
227 # EOF
228
229 # chmod 640 [kK]*
230
231 # # push here?
232 # #myunison -ob li
233 # #ssh li conflink
234 # ssh li.b8.nz systemctl reload named
235
236
237 # # b8.nz has address 65.96.178.16
238 # # b8.nz has IPv6 address 2601:197:600:6efb:82fa:5bff:fe1c:6ecf