-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdnsupdate-install-hooks.in
executable file
·449 lines (389 loc) · 12 KB
/
dnsupdate-install-hooks.in
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
#!/bin/sh
# Script to install the required DHCP hook for various known platforms.
# Copyright 2006 Quest Software, see the COPYING file for licencing
# Authors: Ted Percival <ted.percival@quest.com>
#
# (c) 2006 Quest Software, Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of Quest Software, Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
set -e
TMPSUFFIX='.quest-dhclient.tmp'
umask 022
#-- Display the program usage
usage () {
echo "usage: $0 [-hiqrt] [platform]" >&2
cat <<-. >&2
-h Help (display this information)
-i Installs a DHCP client hook to run dnsupdate on address changes.
-q Quiet, no informational messages.
-r Removes the last installed hook.
-t Test if it looks like a hook is already installed
platform DHCP client type to install hook. Auto-detected if missing.
One of:
aix hpux solaris macos
linux dhclient dhcpcd odhcpcd
(Note: 'linux' auto-detects dhclient, dhcpcd or odhcpcd.)
Warning: Running this hook installation script more than once
may insert multiple dnsupdate hooks, which is probably not
what you want.
.
}
#-- Write a verbose, error message to stderr and exit
die () {
echo "$0: error $*" >&2
exit 1
}
#-- Write a verbose, informational message to stderr unless QUIET is true
verbose () {
$QUIET || echo "quest-dnsupdate: $*" >&2
}
#-- Clean up temporary files on exit
cleanup () {
if test -n "$TMPHOOKFILE"; then
rm -f "$TMPHOOKFILE"
rm -f "$TMPHOOKFILE.2"
fi
return 0
}
trap cleanup 0 1 2
#------------------------------------------------------------
# hook-style platform helper
# These helper functions are for the common case where all we need to do
# is insert a shell fragment into a script file that is run by the DHCP
# client whenever it registers an IP address.
# Requiements for 'hookable' platform $PLAT:
# - Set the following vars
# $HOOKFILE -- script file to create or append
# script fragment to
# $TMPHOOKFILE -- temporary place for building new hookfile
# - Define a function "${PLAT}_script ()" that emits a script fragment
# The output of the ${PLAT}_script must not contain '#!'
# - Call "add_hook_platform ${PLAT}"
# hook_insert($PLAT)
# Installs the output of ${PLAT}_script into $HOOKFILE.
# $HOOKFILE is created executable with '#!/bin/sh' if it doesn't exist.
# $TMPHOOKFILE is created to store working data. It is deleted at exit.
hook_insert () {
test $# -eq 1 || die "hook_insert: missing argument"
test -n "$TMPHOOKFILE" || die "hook_insert $1: TMPHOOKFILE not set"
test -n "$HOOKFILE" || die "hook_insert $1: HOOKFILE not set"
if [ -f $HOOKFILE ]; then
hook_script $1 >> $HOOKFILE
else
{ echo '#!/bin/sh'; hook_script $1; } > $HOOKFILE
chmod 755 $HOOKFILE
fi
verbose "$1 hook installed into $HOOKFILE"
return 0
}
# hook_remove($PLAT)
# Removes previously inserted output of ${PLAT}_script from $HOOKFILE.
# That is, reverses hook_insert($PLAT)
# $HOOKFILE is deleted if the result would be that it just contains '#!/bin/sh'
# $TMPHOOKFILE is used to store working data.
hook_remove () {
test $# -eq 1 || die "hook_remove: missing argument"
test -n "$TMPHOOKFILE" || die "hook_remove $1: TMPHOOKFILE not set"
test -n "$HOOKFILE" || die "hook_remove $1: HOOKFILE not set"
test -f $HOOKFILE || return 0
if hook_test $1; then
# Make a regular expression for the tag text, which
# may include dots and slashes.
tagre=`echo "$hook_tag" | sed -e 's/[./]/[&]/g'`
sed -e "/^# $tagre BEGIN\$/,/^# $tagre END\$/d" \
< $HOOKFILE > $TMPHOOKFILE
# If only the shebang is left, then delete the hookfile
echo '#!/bin/sh' > $TMPHOOKFILE.2
if cmp $TMPHOOKFILE.2 $TMPHOOKFILE >/dev/null 2>/dev/null; then
rm -f $HOOKFILE
else
cat $TMPHOOKFILE > $HOOKFILE
fi
rm -f $TMPHOOKFILE $TMPHOOKFILE.2
verbose "hook removed from $HOOKFILE"
else
echo "$0: No hook found in $HOOKFILE" >&2
verbose "no changes made to $HOOKFILE"
verbose "manual editing of $HOOKFILE may be necessary."
fi
return 0
}
hook_tag='#quest-dnsupdate @VERSION@#'
# hook_script($PLAT)
# Writes the platforms-specific script fragment to standard output
# preceeded by a tag that hook_test will look for
hook_script () {
echo "# $hook_tag BEGIN"
${1}_script
echo "# $hook_tag END"
}
# hook_test($PLAT)
# Tests to see if the hook has already been installed.
# Relies on the tag written by hook_script.
# Exits abnormally if it hasn't.
hook_test () {
test $# -eq 1 || die "hook_test: missing argument"
test -n "$HOOKFILE" || die "hook_remove $1: HOOKFILE not set"
test -f $HOOKFILE || return 1
fgrep "# $hook_tag BEGIN" $HOOKFILE > /dev/null
}
#-- marks platform as using hook_insert/hook_remove
add_hook_platform () {
eval "${1}_insert () { hook_insert $1; }"
eval "${1}_remove () { hook_remove $1; }"
eval "${1}_test () { hook_test $1; }"
}
#------------------------------------------------------------
# AIX
aix_init () {
REALFILE=/etc/dhcpcd.ini
TMPHOOKFILE=/etc/dhcpcd.ini$TMPSUFFIX
}
aix_insert () {
sed -e '/^updateDNS/s/^/##quest-dnsupdate##/' \
< $REALFILE > $TMPHOOKFILE
echo "updateDNS \"@sbindir@/dnsupdate '%.0s%.0s%s%.0s'\"" \
>> $TMPHOOKFILE
cat < $TMPHOOKFILE > $REALFILE
verbose "Installed dnsupdate hook into $REALFILE"
return 0
}
aix_remove () {
grep -v '^updateDNS "@sbindir@/dnsupdate' < $REALFILE |
sed -e 's/^##quest-dnsupdate##//' > $TMPHOOKFILE
cat < $TMPHOOKFILE > $REALFILE
verbose "Removed dnsupdate hook from $REALFILE"
return 0
}
aix_test () {
grep '^updateDNS "@sbindir@/dnsupdate' < $REALFILE > /dev/null
}
#------------------------------------------------------------
# Solaris
add_hook_platform solaris
solaris_init () {
case `uname -r` in
5.[6789])
die "DHCP event hooks only became available in Solaris 10"
;;
esac
HOOKFILE=/etc/dhcp/eventhook
TMPHOOKFILE=${HOOKFILE}${TMPSUFFIX}
}
solaris_script () {
cat <<-'.'
# usage: eventhook <interface> <event>
case "$2" in
BOUND|EXTEND)
addr=`/sbin/dhcpinfo -i "$1" Yiaddr`
@sbindir@/dnsupdate $addr
;;
esac
.
}
#------------------------------------------------------------
# HP-UX
add_hook_platform hpux
hpux_init () {
HOOKFILE=/sbin/rc1.d/S321dnsupdate
TMPHOOKFILE=$HOOKFILE$TMPSUFFIX
}
hpux_script () {
cat <<-'.'
if test 0 -ne 0`/usr/sbin/ch_rc -l -p 'DHCP_ENABLE[0]'`
then
addr=`/usr/sbin/ch_rc -l -p 'IP_ADDRESS[0]'`
case "$addr" in
*.*.*.*) @sbindir@/dnsupdate $addr;;
esac
fi
.
}
#------------------------------------------------------------
# Linux
#-- detects the kind of DHCP client in use.
# Mostly useful for Linux distros; Standards and consistency are a good thing.
# Possible values of $dhc are: dhclient dhcpcd odhcpcd unknown
detect_linux_platform () {
if [ -x /sbin/dhclient ]; then
echo dhclient
elif [ -x /sbin/dhcpcd ]; then
if [ -d /etc/sysconfig/network/if-up.d ]; then
echo dhcpcd
else
echo odhcpcd
fi
else
echo "unknown"
return 1
fi
}
#------------------------------------------------------------
# Linux dhclient
add_hook_platform dhclient
dhclient_init () {
if [ -d /etc/dhcp3/dhclient-exit-hooks.d ]; then
HOOKFILE=/etc/dhcp3/dhclient-exit-hooks.d/dnsupdate
else
HOOKFILE=/etc/dhclient-exit-hooks
fi
TMPHOOKFILE=$HOOKFILE$TMPSUFFIX
}
# Linux dhclient hook based on dhclient-script(8) manpage
# This function being called dhclient_script is accidental coincidence
dhclient_script () {
# Hook is sourced (not executed)
# Return value is to be passed in exit_status var
cat <<-'.'
# This file is sourced by dhclient-script.
# It doesn't matter if there is a bang (#!/bin/sh) above.
case "$reason" in
BOUND|RENEW|REBIND|REBOOT)
@sbindir@/dnsupdate "$new_ip_address"
;;
esac
.
}
#------------------------------------------------------------
# Linux odhcpcd
add_hook_platform odhcpcd
odhcpcd_init () {
if [ -d /etc/sysconfig/network/scripts ]; then
HOOKFILE=/etc/sysconfig/network/scripts/dhcpcd-hook
else
HOOKFILE=/etc/dhcpc/dhcpcd.exe
fi
TMPHOOKFILE=$HOOKFILE$TMPSUFFIX
}
# Based on dhcpcd(8) manpage
odhcpcd_script () {
# TODO: The script is called with [ "$3" = '-d' ] for debug mode.
# dnsupdate should be called with '-v' if that's the case.
cat <<-'.'
. $1
case $2 in
new)
@sbindir@/dnsupdate "$IPADDR"
;;
esac
.
}
#------------------------------------------------------------
# Linux odhcpcd
add_hook_platform dhcpcd
dhcpcd_init () {
HOOKFILE=/etc/sysconfig/network/if-up.d/quest-dnsupdate
TMPHOOKFILE=$HOOKFILE$TMPSUFFIX
}
dhcpcd_script () {
cat <<'.'
test -f /etc/sysconfig/network/ifcfg-$1 &&
. /etc/sysconfig/network/ifcfg-$1
test x"$BOOTPROTO" = x"dhcp" || exit 0
. /var/lib/dhcpcd/dhcpcd-$2.info || exit
@sbindir@/dnsupdate "$IPADDR"
.
}
#------------------------------------------------------------
# Macos
macos_init () {
IPWATCH_PLIST=/Library/LaunchDaemons/com.quest.rc.ipwatchd.plist
PLIST_SRC=@datadir@/ipwatchd/com.quest.rc.ipwatchd.plist
}
macos_insert () {
test -r $IPWATCH_PLIST ||
/usr/bin/install -o root -m 644 $PLIST_SRC $IPWATCH_PLIST
/bin/launchctl load $IPWATCH_PLIST
}
macos_remove () {
/bin/launchctl unload $IPWATCH_PLIST
if cmp $IPWATCH_PLIST $PLIST_SRC >/dev/null 2>/dev/null; then
rm -f $IPWATCH_PLIST
fi
return 0
}
macos_test () {
test -r $IPWATCH_PLIST &&
/bin/launchctl list | fgrep com.quest.rc.ipwatchd > /dev/null
}
#------------------------------------------------------------
# Command line processing
QUIET=false
ERROR=false
ACTION=unset
while getopts hiqrt f; do
case "$f" in
h) ACTION=help;;
i) ACTION=insert;;
q) QUIET=true;;
r) ACTION=remove;;
t) ACTION=test;;
*) ERROR=true;;
esac
done
shift `expr $OPTIND - 1`
case $ACTION in
unset) ERROR=true;;
help) usage help; exit 0;;
esac
#-- platform is the DHCP client type.
# Most of the time, the DHCP client is directly tied to the operating
# system, so its name will match the OS name. On Linux, however,
# there are at least three DHCP client implementations.
if test $# -ge 1; then
platform="$1"
shift
else
case `uname -s` in
AIX) platform=aix;;
SunOS) platform=solaris;;
Darwin) platform=macos;;
Linux) platform=linux;;
HP-UX) platform=hpux;;
*) echo "Cannot auto-detect hook style (platform `uname -s`)" >&2
ERROR=true
;;
esac
fi
#-- Convert ambiguous platform names into specific DHCP client types
case "$platform" in
linux)
platform=`detect_linux_platform` || die "unknown Linux platform"
;;
hpux|aix|solaris|macos|dhclient|dhcpcd|odhcpcd)
: no change
;;
*)
echo "$0: Unrecognised platform '$platform'" >&2
ERROR=true
;;
esac
if $ERROR; then
usage
exit 1
fi
${platform}_init
${platform}_${ACTION}