-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathupdate-client
executable file
·158 lines (125 loc) · 4.29 KB
/
update-client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#!/bin/bash
#
# update-client - update generated zone file with a given IP address
# Copyright (C) 2014,2019 Christian Garbs <[email protected]>
# Licensed under GNU GPL v3 (or later)
#
# This file is part of:
# dns-update - small dynamic DNS suite using SSH
# https://github.com/mmitch/dns-update
#
#
# set this script in your ~/.ssh/authorized_keys as
# command="/path/to/update-client <HOSTNAME>" <KEY>
# to only allow calls to this script for that key
#
# where are we?
BASEDIR=/home/dns-update
# zonefile basic configuration
ZONEFILE_INPUT="${BASEDIR}"/config/zonefile.input
# where to put the new zone file
ZONEFILE_OUTPUT="${BASEDIR}"/zones/dynip.example.com.zone
# where to put the source snippets
HOSTS_DIR="${BASEDIR}"/hosts
# combined host entry files
HOSTS_CUR="${HOSTS_DIR}"/allhosts.cur
HOSTS_NEW="${HOSTS_DIR}"/allhosts.new
# lockfile
LOCKFILE="${HOSTS_DIR}"/.flock
# currently, the hostname is tied to the SSH key via authorized_keys
# TODO: this could also be a parameter from the client to support multiple hosts per key
HOSTNAME="${1}"
# get parameters from client
# shellcheck disable=SC2086
set -- ${SSH_ORIGINAL_COMMAND}
# check for the first argument to be something like update-client, with or without path
case "${1}" in
*update-client)
;;
*)
echo "need 'update-client' as first parameter"
exit 1
;;
esac
# the second parameter is the new IP ADDRESS
# (simple) validation is done later by the zone generator
IPADDRESS="${2}"
# automatic IP ADDRESS detection:
# use connection source ip
if [ "${IPADDRESS}" = 'auto' ] ; then
# shellcheck disable=SC2086
set -- ${SSH_CONNECTION}
IPADDRESS=${1}
# print current IP as the client obviously does not know it
echo "${IPADDRESS}"
fi
# some simple sanity checks
if [ -z "${HOSTNAME}" ] ; then
echo "no hostname given"
exit 1
fi
if [ -z "${IPADDRESS}" ] ; then
echo "no IP address given"
exit 1
fi
# write client IP to snippet file
SNIPPETFILE="${HOSTS_DIR}/${HOSTNAME}"
if [[ "${IPADDRESS}" =~ : ]]; then
# append _6 to filename for addresses that look like IPv6
# this allows two addresses per hostname (IPv4 and IPv6)
SNIPPETFILE="${SNIPPETFILE}_6"
fi
echo "${IPADDRESS}" > "${SNIPPETFILE}"
(
# use fd 9 as lockfile
flock -w 60 9
# combine snippet files:
# find nicely formatted IPv4 host snippet files and collect them
# (please: no line breaks in file names - DNS does not support this anyway)
# TODO: simple check for valid hostnames
# TODO: more complete check for IP addresses, this currently allows "999.555.333.111" like seen on TV
grep -HE '^[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}$' "${HOSTS_DIR}"/* \
| sort \
| sed 's/:/ /' \
> "${HOSTS_NEW}"
# find IPv6 host snippet files and append them
# (please: no line breaks in file names - DNS does not support this anyway)
# TODO: simple check for valid hostnames
# TODO: more complete check for IP addresses, this is currently totally basic
grep -HE '^[0-9a-fA-F.:]+:[0-9a-fA-F.:]+$' "${HOSTS_DIR}"/* \
| sort \
| sed 's/_6:/ /' \
>> "${HOSTS_NEW}"
# create current combined file if absent, otherwise mark as updated
touch "${HOSTS_CUR}"
# check for changes to process
if cmp -s "${HOSTS_NEW}" "${HOSTS_CUR}" ; then
# new file is uneccessary
rm "${HOSTS_NEW}"
else
# declare new file as current file
mv "${HOSTS_NEW}" "${HOSTS_CUR}"
# back up zone file if current file exists and has contents
if [ -f "${ZONEFILE_OUTPUT}" ] && [ -s "${ZONEFILE_OUTPUT}" ] ; then
mv "${ZONEFILE_OUTPUT}" "${ZONEFILE_OUTPUT}.bak"
fi
# serial has 1 second resolution, so wait one second to not accidentially
# generate the same serial twice (yeah, cheap lame hack, but come on...)
sleep 1
# generate serial
SERIAL=$(date +%m%d%H%M%S)
# generate new zone file
sed "s/§SERIAL§/${SERIAL}/" < "${ZONEFILE_INPUT}" > "${ZONEFILE_OUTPUT}"
# read hostnames and append to zonefile
while read -r FILENAME IPADDRESS; do
HOSTNAME="$(basename "${FILENAME}")"
TYPE=A
if [[ "${IPADDRESS}" =~ : ]]; then
TYPE=AAAA
fi
printf '%-32s %s %-15s ;\n' "${HOSTNAME}" "${TYPE}" "${IPADDRESS}"
done < "${HOSTS_CUR}" >> "${ZONEFILE_OUTPUT}"
# reload the nameserver
sudo /bin/systemctl reload nsd
fi
) 9>"${LOCKFILE}"