Project

General

Profile

Download (10.5 KB) Statistics
| Branch: | Tag: | Revision:
1
#!/bin/sh
2
# $Id$
3
# $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $
4
# $FreeBSD: src/sbin/dhclient/dhclient-script,v 1.4 2005/06/10 03:41:18 brooks Exp $
5
#
6
# Copyright (c) 2003 Kenneth R Westerback <krw@openbsd.org>
7
#
8
# Permission to use, copy, modify, and distribute this software for any
9
# purpose with or without fee is hereby granted, provided that the above
10
# copyright notice and this permission notice appear in all copies.
11
#
12
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
#
20

    
21
HOSTNAME=/bin/hostname
22
ROUTE=/sbin/route
23
SED=/usr/bin/sed
24
ARP=/usr/sbin/arp
25
IFCONFIG=/sbin/ifconfig
26

    
27
LOCALHOST=127.0.0.1
28

    
29
if [ -x /usr/bin/logger ]; then
30
	LOGGER="/usr/bin/logger -s -p user.notice -t dhclient"
31
else
32
	LOGGER="echo"
33
fi
34

    
35
#
36
# Helper functions that implement common actions.
37
#
38

    
39
check_hostname() {
40
	current_hostname=`$HOSTNAME`
41
	if [ -z "$current_hostname" ] || \
42
	   [ "$current_hostname" = "$old_host_name" -a \
43
	     "$new_hostname" != "$old_host_name" ]; then
44
		$LOGGER "New Hostname ($interface): $new_host_name"
45
		$HOSTNAME "$new_host_name"
46
	fi
47
}
48

    
49
arp_flush() {
50
	$ARP -an -i "$interface" | \
51
		$SED -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' | \
52
		/bin/sh >/dev/null 2>&1
53
}
54

    
55
delete_old_address() {
56
	/bin/rm -f "/var/db/${interface}_ip"
57
	eval $IFCONFIG "$interface" inet -alias "$old_ip_address" "$medium"
58
}
59

    
60
add_new_address() {
61

    
62
	$LOGGER "Starting add_new_address()"
63

    
64
	$LOGGER "ifconfig $interface inet $new_ip_address netmask $new_subnet_mask broadcast $new_broadcast_address $medium"
65

    
66
	eval $IFCONFIG "$interface" \
67
		inet "$new_ip_address" \
68
		netmask "$new_subnet_mask" \
69
		broadcast "$new_broadcast_address" \
70
		"$medium"
71

    
72
	$LOGGER "New IP Address ($interface): $new_ip_address"
73
	$LOGGER "New Subnet Mask ($interface): $new_subnet_mask"
74
	$LOGGER "New Broadcast Address ($interface): $new_broadcast_address"
75
	$LOGGER "New Routers ($interface): $new_routers"
76

    
77

    
78
	# This is necessary otherwise dpinger will try to ping all 1s address
79
	if [ -n "$new_routers" ] && [ "$new_routers" != "255.255.255.255" ]; then
80
		echo "$new_routers" > "/tmp/${interface}_router"
81
		/bin/rm -f "/tmp/${interface}_router.last"
82
	fi
83
	echo "$new_ip_address" > "/var/db/${interface}_ip"
84
}
85

    
86
delete_old_alias() {
87
	if [ -n "$alias_ip_address" ]; then
88
		$IFCONFIG "$interface" inet -alias "$alias_ip_address" > /dev/null 2>&1
89
		$ROUTE delete "$alias_ip_address" "$LOCALHOST" > /dev/null 2>&1
90
	fi
91
}
92

    
93
add_new_alias() {
94
	if [ -n "$alias_ip_address" ]; then
95
		$IFCONFIG "$interface" inet alias "$alias_ip_address" netmask \
96
		    "$alias_subnet_mask"
97
		$ROUTE add "$alias_ip_address" "$LOCALHOST"
98
	fi
99
}
100

    
101
fill_classless_routes() {
102
	set $1
103
	while [ $# -ge 5 ]; do
104
		if [ "$1" -eq 0 ]; then
105
			route="default"
106
		elif [ "$1" -le 8 ]; then
107
			route="$2.0.0.0/$1"
108
			shift
109
		elif [ "$1" -le 16 ]; then
110
			route="$2.$3.0.0/$1"
111
			shift; shift
112
		elif [ "$1" -le 24 ]; then
113
			route="$2.$3.$4.0/$1"
114
			shift; shift; shift
115
		else
116
			route="$2.$3.$4.$5/$1"
117
			shift; shift; shift; shift
118
		fi
119
		shift
120
		router="$1.$2.$3.$4"
121
		classless_routes="$classless_routes $route $router"
122
		shift; shift; shift; shift
123
	done
124
}
125

    
126
delete_old_routes() {
127
	$LOGGER "Deleting old routes"
128

    
129
	if [ -n "$old_classless_routes" ]; then
130
		fill_classless_routes "$old_classless_routes"
131
		set $classless_routes
132
		while [ $# -gt 1 ]; do
133
			$ROUTE delete "$1" "$2"
134
			shift; shift
135
		done
136
		return 0;
137
	fi
138

    
139
	# Only allow the default route to be overridden if it's on our own interface
140
	if [ -f "/tmp/${interface}_defaultgw" ]; then
141
		for router in $old_routers; do
142
			#  delete local route to the router ip address.
143
			#  cleans up our route to a gateway possibly outside of the assigned subnet
144
			$ROUTE delete -host "$router" -iface "$interface"
145

    
146
			$ROUTE delete default "$router" >/dev/null 2>&1
147
		done
148
		if [ -f "/tmp/${interface}_router" ]; then
149
			/bin/mv "/tmp/${interface}_router" "/tmp/${interface}_router.last"
150
		fi
151
	fi
152

    
153
	if [ -n "$old_static_routes" ]; then
154
		set $old_static_routes
155
		while [ $# -gt 1 ]; do
156
			$ROUTE delete "$1" "$2"
157
			shift; shift
158
		done
159
		if [ -f "/tmp/${interface}_router" ]; then
160
			/bin/mv "/tmp/${interface}_router" "/tmp/${interface}_router.last"
161
		fi
162
	fi
163

    
164
	arp_flush
165
}
166

    
167
add_new_routes() {
168
	$LOGGER "Adding new routes to interface: $interface"
169

    
170
	# RFC 3442: If the DHCP server returns both a Classless Static
171
	# Routes option and a Router option, the DHCP client MUST ignore
172
	# the Router option.
173
	#
174
	# DHCP clients that support this option (Classless Static Routes)
175
	# MUST NOT install the routes specified in the Static Routes
176
	# option (option code 33) if both a Static Routes option and the
177
	# Classless Static Routes option are provided.
178
	if [ -n "$new_classless_routes" ]; then
179
		fill_classless_routes "$new_classless_routes"
180
		$LOGGER "New Classless Static Routes ($interface): $classless_routes"
181
		set $classless_routes
182
		while [ $# -gt 1 ]; do
183
			if [ "0.0.0.0" = "$2" ]; then
184
				$ROUTE add "$1" -iface "$interface"
185
			else
186
				$ROUTE add "$1" "$2"
187
			fi
188
			shift; shift
189
		done
190
		return
191
	fi
192

    
193
	ADDED_ROUTE=no
194
	# Only allow the default route to be overridden if it's on our own interface
195
	if [ -f "/tmp/${interface}_defaultgw" ]; then
196
		OLD_ROUTER=$(cat "/tmp/${interface}_defaultgw")
197
		$ROUTE delete default "${OLD_ROUTER}"
198
		for router in $new_routers; do
199
			if [ "$new_ip_address" = "$router" ] || [ "$router" = "255.255.255.255" ]; then
200
				$ROUTE add default -iface "$interface"
201
				echo $ROUTE add default -iface "$interface" | $LOGGER
202
				# NOTE: Do not activate this for all ones address since pf(4) will try to forward packets to it.
203
				if [ "$new_ip_address" = "$router" ]; then
204
					echo "$router" > "/tmp/${interface}_router"
205
					/bin/rm -f "/tmp/${interface}_router.last"
206
				fi
207
			else
208
				#  add local route to the router ip address.
209
				#  this will not cause any harm if the router is within the subnet
210
				#  but it will prevent route troubles if the router is outside of the subnet
211
				#  this is useful for captive subnets or similar gateway out-of-subnet situations
212
				$ROUTE add -host "$router" -iface "$interface"
213
				echo $ROUTE add -host "$router" -iface "$interface" | $LOGGER
214

    
215
				$ROUTE add default "$router"
216
				echo $ROUTE add default "$router" | $LOGGER
217
				echo "$router" > "/tmp/${interface}_router"
218
				/bin/rm -f "/tmp/${interface}_router.last"
219
			fi
220
			ADDED_ROUTE=yes
221
			# 2nd and subsequent default routers error out, so explicitly
222
			# stop processing the list after the first one.
223
			break
224
		done
225
	fi
226

    
227
	if [ -n "$new_static_routes" ]; then
228
		$LOGGER "New Static Routes ($interface): $new_static_routes"
229
		set $new_static_routes
230
		while [ $# -gt 1 ]; do
231
			$ROUTE add "$1" "$2"
232
			if [ "$ADDED_ROUTE" = "no" ]; then
233
				echo "$2" > "/tmp/${interface}_router"
234
				/bin/rm -f "/tmp/${interface}_router.last"
235
			fi
236
			shift; shift
237
		done
238
	fi
239
}
240

    
241
add_new_resolv_conf() {
242
	$LOGGER "Creating resolv.conf"
243
	if [ -f "/var/etc/nameserver_$interface" ]; then
244
		# Remove old entries
245
		for nameserver in `cat "/var/etc/nameserver_$interface"`; do
246
			$ROUTE delete "$nameserver" >/dev/null 2>&1
247
		done
248
	fi
249
	if [ -n "$new_domain_name_servers" ]; then
250
		/bin/rm -f "/var/etc/nameserver_$interface"
251
		ALLOWOVERRIDE=$(/usr/local/sbin/read_xml_tag.sh boolean system/dnsallowoverride)
252
		for nameserver in $new_domain_name_servers; do
253
			# Add a route to the nameserver out the correct interface
254
			# so that multiple wans work correctly with multiple dns
255
			# also backup the nameserver for later route removal
256
			if [ "$ALLOWOVERRIDE" = "true" ]; then
257
				echo "$nameserver" >> "/var/etc/nameserver_$interface"
258
				$ROUTE add "$nameserver" -iface "$interface"
259
			fi
260
		done
261
		echo "$new_domain_name" > "/var/etc/searchdomain_$interface"
262
	fi
263

    
264
	return 0
265
}
266

    
267
# Notify rc.newwanip of changes to an interface
268
notify_rc_newwanip() {
269
	/usr/local/sbin/pfSctl -c "interface newip $interface"
270
}
271

    
272
#
273
# Start of active code.
274
#
275
exit_status=0
276

    
277
# Invoke the local dhcp client enter hooks, if they exist.
278
if [ -f /etc/dhclient-enter-hooks ]; then
279
	$LOGGER "dhclient-enter-hooks"
280
	. /etc/dhclient-enter-hooks
281
	# allow the local script to abort processing of this state
282
	# local script must set exit_status variable to nonzero.
283
	if [ $exit_status -ne 0 ]; then
284
		exit $exit_status
285
	fi
286
fi
287

    
288
$LOGGER "$reason"
289
case $reason in
290
MEDIUM)
291
	eval "$IFCONFIG $interface $medium"
292
	/bin/sleep 1
293
	;;
294

    
295
PREINIT)
296
	delete_old_alias
297
	eval "$IFCONFIG $interface up"
298
	if [ -f "/tmp/${interface}_router" ]; then
299
		/bin/mv "/tmp/${interface}_router" "/tmp/${interface}_router.last"
300
	fi
301
	;;
302

    
303
ARPCHECK|ARPSEND)
304
	;;
305

    
306
BOUND|RENEW|REBIND|REBOOT)
307
	check_hostname
308
	changes="no"
309
	if [ -n "$old_ip_address" ]; then
310
		if [ -n "$alias_ip_address" ] && \
311
		   [ "$old_ip_address" != "$alias_ip_address" ]; then
312
			delete_old_alias
313
			changes="yes"
314
		fi
315
		if [ "$old_ip_address" != "$new_ip_address" ]; then
316
			delete_old_address
317
			delete_old_routes
318
			changes="yes"
319
		fi
320
	fi
321
	if [ "$reason" = BOUND ] || \
322
	   [ "$reason" = REBOOT ] || \
323
	   [ -z "$old_ip_address" ] || \
324
	   [ "$old_ip_address" != "$new_ip_address" ]; then
325
		add_new_address
326
		add_new_routes
327
		changes="yes"
328
	fi
329
	if [ -n "$alias_ip_address" ] && \
330
       [ "$new_ip_address" != "$alias_ip_address" ]; then
331
		add_new_alias
332
		changes="yes"
333
	fi
334
	add_new_resolv_conf
335
	if [ "$changes" = "yes" ] ; then
336
		notify_rc_newwanip
337
	fi
338
	;;
339

    
340
EXPIRE|FAIL|RELEASE)
341
	delete_old_alias
342
	if [ -n "$old_ip_address" ]; then
343
		delete_old_address
344
		delete_old_routes
345
	fi
346
	;;
347

    
348
TIMEOUT)
349
	# This case must exit zero only if the cached address
350
	# is considered valid. See dhclient-script(8).
351
	exit_status=1
352
	delete_old_alias
353
	add_new_address
354
	/bin/sleep 1
355
	if [ -n "$new_routers" ]; then
356
		$LOGGER "New Routers ($interface): $new_routers"
357
		set "$new_routers"
358
		if /sbin/ping -q -c 1 -t 1 "$1"; then
359
			if [ "$new_ip_address" != "$alias_ip_address" ]; then
360
				add_new_alias
361
			fi
362
			add_new_routes
363
			if add_new_resolv_conf; then
364
				notify_rc_newwanip
365
			fi
366
			exit_status=0
367
		fi
368
	fi
369
	if [ "$exit_status" -ne 0 ]; then
370
		eval "$IFCONFIG" "$interface" inet -alias "$new_ip_address" "$medium"
371
		delete_old_routes
372
	fi
373
	;;
374
esac
375

    
376
# Invoke the local dhcp client exit hooks, if they exist.
377
if [ -f /etc/dhclient-exit-hooks ]; then
378
	$LOGGER "dhclient-exit-hooks"
379
	. /etc/dhclient-exit-hooks
380
	# allow the local script to abort processing of this state
381
	# local script must set exit_status variable to nonzero.
382
fi
383
exit $exit_status
(18-18/37)