dhclient-script revision 230728
143410Snewton#!/bin/sh
243410Snewton#
343410Snewton# $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $
443410Snewton# $FreeBSD: stable/9/sbin/dhclient/dhclient-script 230728 2012-01-29 10:55:19Z dumbbell $
543410Snewton#
643410Snewton# Copyright (c) 2003 Kenneth R Westerback <krw@openbsd.org>
743410Snewton#
843410Snewton# Permission to use, copy, modify, and distribute this software for any
943410Snewton# purpose with or without fee is hereby granted, provided that the above
1043410Snewton# copyright notice and this permission notice appear in all copies.
1143410Snewton#
1243410Snewton# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1343410Snewton# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1443410Snewton# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1543410Snewton# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1643410Snewton# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1743410Snewton# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1843410Snewton# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1943410Snewton#
2043410Snewton#
2143410Snewton
2243410SnewtonARP=/usr/sbin/arp
2343410SnewtonHOSTNAME=/bin/hostname
2443410SnewtonIFCONFIG='/sbin/ifconfig -n'
2543410Snewton
2643410SnewtonLOCALHOST=127.0.0.1
2743410Snewton
2843410Snewtonif [ -x /usr/bin/logger ]; then
2943410Snewton	LOGGER="/usr/bin/logger -s -p user.notice -t dhclient"
3043410Snewtonelse
3143410Snewton	LOGGER=echo
3249263Snewtonfi
3343410Snewton
3443410Snewton#
35119420Sobrien# Helper functions that implement common actions.
36119420Sobrien#
37119420Sobrien
3843410Snewtoncheck_hostname() {
3943410Snewton	current_hostname=`$HOSTNAME`
4043410Snewton	if [ -z "$current_hostname" ]; then
4143410Snewton		$LOGGER "New Hostname ($interface): $new_host_name"
4243410Snewton		$HOSTNAME $new_host_name
4343410Snewton	elif [ "$current_hostname" = "$old_host_name" -a \
4443410Snewton	       "$new_host_name" != "$old_host_name" ]; then
4543410Snewton		$LOGGER "New Hostname ($interface): $new_host_name"
4643410Snewton		$HOSTNAME $new_host_name
4743410Snewton	fi
4843410Snewton}
4943410Snewton
5043410Snewtonarp_flush() {
5143410Snewton	arp -an -i $interface | \
5243410Snewton		sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' | \
5343410Snewton		sh >/dev/null 2>&1
5443410Snewton}
5543410Snewton
5643410Snewtondelete_old_address() {
5743410Snewton	eval "$IFCONFIG $interface inet -alias $old_ip_address $medium"
5843410Snewton}
5965314Sobrien
6065314Sobrienadd_new_address() {
6165314Sobrien	eval "$IFCONFIG $interface \
6265314Sobrien		inet $new_ip_address \
6365314Sobrien		netmask $new_subnet_mask \
6465314Sobrien		broadcast $new_broadcast_address \
6543410Snewton		$medium"
6692739Salfred
6792739Salfred	$LOGGER "New IP Address ($interface): $new_ip_address"
6843410Snewton	$LOGGER "New Subnet Mask ($interface): $new_subnet_mask"
6943410Snewton	$LOGGER "New Broadcast Address ($interface): $new_broadcast_address"
70115550Sphk	$LOGGER "New Routers ($interface): $new_routers"
7143410Snewton}
7243410Snewton
7343410Snewtondelete_old_alias() {
7443410Snewton	if [ -n "$alias_ip_address" ]; then
7543410Snewton		$IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1
7643410Snewton		#route delete $alias_ip_address $LOCALHOST > /dev/null 2>&1
7743410Snewton	fi
7843410Snewton}
7943410Snewton
8043410Snewtonadd_new_alias() {
8143410Snewton	if [ -n "$alias_ip_address" ]; then
8243410Snewton		$IFCONFIG $interface inet alias $alias_ip_address netmask \
8343410Snewton		    $alias_subnet_mask
8443410Snewton		#route add $alias_ip_address $LOCALHOST
8543410Snewton	fi
8643410Snewton}
8743410Snewton
8843410Snewtonfill_classless_routes() {
8943410Snewton	set $1
9043410Snewton	while [ $# -ge 5 ]; do
9189059Smsmith		if [ $1 -eq 0 ]; then
9252114Snewton			route="default"
9352114Snewton		elif [ $1 -le 8 ]; then
9443410Snewton			route="$2.0.0.0/$1"
95116546Sphk			shift
96116546Sphk		elif [ $1 -le 16 ]; then
97116546Sphk			route="$2.$3.0.0/$1"
98116546Sphk			shift; shift
99116546Sphk		elif [ $1 -le 24 ]; then
100116546Sphk			route="$2.$3.$4.0/$1"
101116546Sphk			shift; shift; shift
10243410Snewton		else
10343410Snewton			route="$2.$3.$4.$5/$1"
10443410Snewton			shift; shift; shift; shift
105126080Sphk		fi
106126080Sphk		shift
107111815Sphk		router="$1.$2.$3.$4"
108111815Sphk		classless_routes="$classless_routes $route $router"
10947625Sphk		shift; shift; shift; shift
11043410Snewton	done
11143410Snewton}
11243410Snewton
11343410Snewtondelete_old_routes() {
11443410Snewton	#route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1
11543410Snewton	if [ -n "$old_classless_routes" ]; then
11643410Snewton		fill_classless_routes "$old_classless_routes"
11743410Snewton		set $classless_routes
11843410Snewton		while [ $# -gt 1 ]; do
11944208Snewton			route delete "$1" "$2"
12044208Snewton			shift; shift
12144208Snewton		done
12244208Snewton		return 0;
12344208Snewton	fi
12449344Snewton
12552114Snewton	# If we supported multiple default routes, we'd be removing each
12652114Snewton	# one here.  We don't so just delete the default route if it's
12752114Snewton	# through our interface.
12852114Snewton	if is_default_interface; then
12952114Snewton		route delete default >/dev/null 2>&1
13052114Snewton	fi
13152114Snewton
13252114Snewton	if [ -n "$old_static_routes" ]; then
13352114Snewton		set $old_static_routes
13452114Snewton		while [ $# -gt 1 ]; do
13552114Snewton			route delete "$1" "$2"
13652114Snewton			shift; shift
13752114Snewton		done
13852114Snewton	fi
13952114Snewton
14052114Snewton	arp_flush
14152114Snewton}
14252114Snewton
14352114Snewtonadd_new_routes() {
14452114Snewton	#route add $new_ip_address $LOCALHOST >/dev/null 2>&1
14552114Snewton
14652114Snewton	# RFC 3442: If the DHCP server returns both a Classless Static
14752114Snewton	# Routes option and a Router option, the DHCP client MUST ignore
14852114Snewton	# the Router option.
14952114Snewton	#
15052114Snewton	# DHCP clients that support this option (Classless Static Routes)
15152114Snewton	# MUST NOT install the routes specified in the Static Routes
15244208Snewton	# option (option code 33) if both a Static Routes option and the
15344208Snewton	# Classless Static Routes option are provided.
15449344Snewton
15553000Sphk	if [ -n "$new_classless_routes" ]; then
15653000Sphk		fill_classless_routes "$new_classless_routes"
15753000Sphk		$LOGGER "New Classless Static Routes ($interface): $classless_routes"
15853000Sphk		set $classless_routes
15953000Sphk		while [ $# -gt 1 ]; do
16053000Sphk			if [ "0.0.0.0" = "$2" ]; then
16153000Sphk				route add "$1" -iface "$interface"
16253000Sphk			else
16353000Sphk				route add "$1" "$2"
16453000Sphk			fi
16552114Snewton			shift; shift
16644208Snewton		done
16744208Snewton		return
16844208Snewton	fi
16944208Snewton
17044208Snewton	for router in $new_routers; do
17144208Snewton		if is_default_interface; then
17244208Snewton
17344208Snewton			if [ "$new_ip_address" = "$router" ]; then
17444208Snewton				route add default -iface $router >/dev/null 2>&1
17544208Snewton			else
17644208Snewton				route add default $router >/dev/null 2>&1
17744208Snewton			fi
17844208Snewton		fi
17960060Sgreen		# 2nd and subsequent default routers error out, so explicitly
18044208Snewton		# stop processing the list after the first one.
18143410Snewton		break
18243410Snewton	done
18343410Snewton
18443410Snewton	if [ -n "$new_static_routes" ]; then
18543410Snewton		$LOGGER "New Static Routes ($interface): $new_static_routes"
18643410Snewton		set $new_static_routes
18743410Snewton		while [ $# -gt 1 ]; do
18843410Snewton			route add $1 $2
18983366Sjulian			shift; shift
19043410Snewton		done
19143410Snewton	fi
192121256Sdwmalone}
19343410Snewton
19443410Snewtonadd_new_resolv_conf() {
19543410Snewton	# XXX Old code did not create/update resolv.conf unless both
19643410Snewton	# $new_domain_name and $new_domain_name_servers were provided.  PR
19783366Sjulian	# #3135 reported some ISP's only provide $new_domain_name_servers and
19843410Snewton	# thus broke the script. This code creates the resolv.conf if either
19971448Sjhb	# are provided.
20083366Sjulian
20171448Sjhb	local tmpres=/var/run/resolv.conf.${interface}
20243410Snewton	rm -f $tmpres
20371448Sjhb
20471448Sjhb	if [ -n "$new_domain_search" ]; then
20543410Snewton		echo "search $new_domain_search" >>$tmpres
20643410Snewton	elif [ -n "$new_domain_name" ]; then
20743410Snewton		echo "search $new_domain_name" >>$tmpres
20843410Snewton	fi
20943410Snewton
21043410Snewton	if [ -n "$new_domain_name_servers" ]; then
21143410Snewton		for nameserver in $new_domain_name_servers; do
21243410Snewton			echo "nameserver $nameserver" >>$tmpres
21343410Snewton		done
21443410Snewton	fi
21543410Snewton
21643410Snewton	if [ -f $tmpres ]; then
21743410Snewton		if [ -f /etc/resolv.conf.tail ]; then
21843410Snewton			cat /etc/resolv.conf.tail >>$tmpres
21943410Snewton		fi
22043410Snewton
22143410Snewton		case $resolvconf_enable in
22243410Snewton		# "no", "false", "off", or "0"
22343410Snewton		[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
22443410Snewton			# When resolv.conf is not changed actually, we don't
22543410Snewton			# need to update it.
22643410Snewton			# If /usr is not mounted yet, we cannot use cmp, then
22743410Snewton			# the following test fails.  In such case, we simply
22843410Snewton			# ignore an error and do update resolv.conf.
22943410Snewton			if cmp -s $tmpres /etc/resolv.conf; then
23043410Snewton				rm -f $tmpres
23143410Snewton				return 0
23243410Snewton			fi 2>/dev/null
23343410Snewton
23443410Snewton			# In case (e.g. during OpenBSD installs)
23543410Snewton			# /etc/resolv.conf is a symbolic link, take
23643410Snewton			# care to preserve the link and write the new
23743410Snewton			# data in the correct location.
23843410Snewton
23943410Snewton			if [ -f /etc/resolv.conf ]; then
24043410Snewton				cat /etc/resolv.conf > /etc/resolv.conf.save
24143410Snewton			fi
24243410Snewton			cat $tmpres > /etc/resolv.conf
24343410Snewton
24443410Snewton			# Try to ensure correct ownership and permissions.
24543410Snewton			chown -RL root:wheel /etc/resolv.conf
24683366Sjulian			chmod -RL 644 /etc/resolv.conf
24743410Snewton			;;
24843410Snewton
24943410Snewton		*)
25043410Snewton			/sbin/resolvconf -a ${interface} < $tmpres
25143410Snewton			;;
25283366Sjulian		esac
25343410Snewton
254121256Sdwmalone		rm -f $tmpres
25543410Snewton
25688739Srwatson		return 0
25791406Sjhb	fi
25889306Salfred
259121256Sdwmalone	return 1
260121256Sdwmalone}
261121256Sdwmalone
262121256Sdwmalone# Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
263121256Sdwmaloneexit_with_hooks() {
264121256Sdwmalone	exit_status=$1
26589306Salfred	if [ -f /etc/dhclient-exit-hooks ]; then
266121256Sdwmalone		. /etc/dhclient-exit-hooks
267121256Sdwmalone	fi
268121256Sdwmalone	# probably should do something with exit status of the local script
26943410Snewton	exit $exit_status
27043410Snewton}
27143410Snewton
27289306Salfred# Get the interface with the current ipv4 default route on it using only
273109153Sdillon# commands that are available prior to /usr being mounted.
27443410Snewtonis_default_interface()
27549413Sgreen{
27643410Snewton	routeget="`route -n get -inet default`"
27789306Salfred	oldifs="$IFS"
27843410Snewton	IFS="
27943410Snewton"
280121256Sdwmalone	defif=
28171448Sjhb	for line in $routeget ; do
28283366Sjulian		case $line in
28371448Sjhb		*interface:*)
28443410Snewton			defif=${line##*: }
28543410Snewton			;;
28643410Snewton		esac
28743410Snewton	done
28883366Sjulian	IFS=${oldifs}
28983366Sjulian
29043410Snewton	if [ -z "$defif" -o "$defif" = "$interface" ]; then
29183366Sjulian		return 0
29243410Snewton	else
29343410Snewton		return 1
29443410Snewton	fi
29543410Snewton}
29643410Snewton
29743410Snewton#
29843410Snewton# Start of active code.
29943410Snewton#
30043410Snewton
30143410Snewton# Invoke the local dhcp client enter hooks, if they exist.
30243410Snewtonif [ -f /etc/dhclient-enter-hooks ]; then
30343410Snewton	exit_status=0
30443410Snewton	. /etc/dhclient-enter-hooks
30543410Snewton	# allow the local script to abort processing of this state
30643410Snewton	# local script must set exit_status variable to nonzero.
30743410Snewton	if [ $exit_status -ne 0 ]; then
30843410Snewton		exit $exit_status
30943410Snewton	fi
31043410Snewtonfi
31143410Snewton
31243410Snewton: ${resolvconf_enable="YES"}
31343410Snewton
31443410Snewtoncase $reason in
315107849SalfredMEDIUM)
316107849Salfred	eval "$IFCONFIG $interface $medium"
317107849Salfred	eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
31843410Snewton	sleep 1
31943410Snewton	;;
32043410Snewton
32143410SnewtonPREINIT)
32243410Snewton	delete_old_alias
32343410Snewton	$IFCONFIG $interface inet alias 0.0.0.0 netmask 255.0.0.0 broadcast 255.255.255.255 up
32443410Snewton	;;
32543410Snewton
32683366SjulianARPCHECK|ARPSEND)
32743410Snewton	;;
32843410Snewton
32943410SnewtonBOUND|RENEW|REBIND|REBOOT)
33043410Snewton	check_hostname
33171448Sjhb	if [ -n "$old_ip_address" ]; then
33283366Sjulian		if [ "$old_ip_address" != "$alias_ip_address" ]; then
33371448Sjhb			delete_old_alias
33443410Snewton		fi
33543410Snewton		if [ "$old_ip_address" != "$new_ip_address" ]; then
33643410Snewton			delete_old_address
33743410Snewton			delete_old_routes
33843410Snewton		fi
33943410Snewton	fi
34043410Snewton	if [ "$reason" = BOUND ] || \
34143410Snewton	   [ "$reason" = REBOOT ] || \
34243410Snewton	   [ -z "$old_ip_address" ] || \
34343410Snewton	   [ "$old_ip_address" != "$new_ip_address" ]; then
34443410Snewton		add_new_address
34543410Snewton		add_new_routes
34643410Snewton	fi
34743410Snewton	if [ "$new_ip_address" != "$alias_ip_address" ]; then
34843410Snewton		add_new_alias
34943410Snewton	fi
35043410Snewton	if is_default_interface; then
35143410Snewton		add_new_resolv_conf
35243410Snewton	fi
35343410Snewton	;;
35443410Snewton
35543410SnewtonEXPIRE|FAIL)
35643410Snewton	delete_old_alias
357109153Sdillon	if [ -n "$old_ip_address" ]; then
35843410Snewton		delete_old_address
35989306Salfred		delete_old_routes
36089306Salfred	fi
36189306Salfred	if [ -x $ARP ]; then
36289306Salfred		$ARP -d -a -i $interface
36343410Snewton	fi
36489306Salfred	# XXX Why add alias we just deleted above?
36543410Snewton	add_new_alias
36643410Snewton	if is_default_interface; then
367111119Simp		case $resolvconf_enable in
36843410Snewton		# "no", "false", "off", or "0"
36943410Snewton		[Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
37043410Snewton			if [ -f /etc/resolv.conf.save ]; then
37143410Snewton				cat /etc/resolv.conf.save > /etc/resolv.conf
37289306Salfred			fi
37389306Salfred			;;
37489306Salfred		*)
37589306Salfred			/sbin/resolvconf -d ${interface}
37689306Salfred			;;
37789306Salfred		esac
37889306Salfred	fi
37989306Salfred	;;
38089306Salfred
38189306SalfredTIMEOUT)
38289306Salfred	delete_old_alias
38389306Salfred	add_new_address
38489306Salfred	sleep 1
38543410Snewton	if [ -n "$new_routers" ]; then
38643410Snewton		$LOGGER "New Routers ($interface): $new_routers"
38743410Snewton		set "$new_routers"
38843410Snewton		if ping -q -c 1 -t 1 "$1"; then
38943410Snewton			if [ "$new_ip_address" != "$alias_ip_address" ]; then
39043410Snewton				add_new_alias
39143410Snewton			fi
39243410Snewton			add_new_routes
39343410Snewton			if ! is_default_interface; then
39443410Snewton				exit_with_hooks 0
395109153Sdillon			fi
39643410Snewton			if add_new_resolv_conf; then
39771448Sjhb				exit_with_hooks 0
39871448Sjhb			fi
39971448Sjhb		fi
40071448Sjhb	fi
40171448Sjhb	eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
40243410Snewton	delete_old_routes
40343410Snewton	exit_with_hooks 1
40443410Snewton	;;
40571448Sjhbesac
40643410Snewton
40743410Snewtonexit_with_hooks 0
40843410Snewton