]> CyberLeo.Net >> Repos - FreeBSD/releng/9.0.git/blob - sbin/dhclient/dhclient-script
Copy stable/9 to releng/9.0 as part of the FreeBSD 9.0-RELEASE release
[FreeBSD/releng/9.0.git] / sbin / dhclient / dhclient-script
1 #!/bin/sh
2 #
3 # $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $
4 # $FreeBSD$
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
22 ARP=/usr/sbin/arp
23 HOSTNAME=/bin/hostname
24 IFCONFIG='/sbin/ifconfig -n'
25
26 LOCALHOST=127.0.0.1
27
28 if [ -x /usr/bin/logger ]; then
29         LOGGER="/usr/bin/logger -s -p user.notice -t dhclient"
30 else
31         LOGGER=echo
32 fi
33
34 #
35 # Helper functions that implement common actions.
36 #
37
38 check_hostname() {
39         current_hostname=`$HOSTNAME`
40         if [ -z "$current_hostname" ]; then
41                 $LOGGER "New Hostname ($interface): $new_host_name"
42                 $HOSTNAME $new_host_name
43         elif [ "$current_hostname" = "$old_host_name" -a \
44                "$new_host_name" != "$old_host_name" ]; then
45                 $LOGGER "New Hostname ($interface): $new_host_name"
46                 $HOSTNAME $new_host_name
47         fi
48 }
49
50 arp_flush() {
51         arp -an -i $interface | \
52                 sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' | \
53                 sh >/dev/null 2>&1
54 }
55
56 delete_old_address() {
57         eval "$IFCONFIG $interface inet -alias $old_ip_address $medium"
58 }
59
60 add_new_address() {
61         eval "$IFCONFIG $interface \
62                 inet $new_ip_address \
63                 netmask $new_subnet_mask \
64                 broadcast $new_broadcast_address \
65                 $medium"
66
67         $LOGGER "New IP Address ($interface): $new_ip_address"
68         $LOGGER "New Subnet Mask ($interface): $new_subnet_mask"
69         $LOGGER "New Broadcast Address ($interface): $new_broadcast_address"
70         $LOGGER "New Routers ($interface): $new_routers"
71 }
72
73 delete_old_alias() {
74         if [ -n "$alias_ip_address" ]; then
75                 $IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1
76                 #route delete $alias_ip_address $LOCALHOST > /dev/null 2>&1
77         fi
78 }
79
80 add_new_alias() {
81         if [ -n "$alias_ip_address" ]; then
82                 $IFCONFIG $interface inet alias $alias_ip_address netmask \
83                     $alias_subnet_mask
84                 #route add $alias_ip_address $LOCALHOST
85         fi
86 }
87
88 fill_classless_routes() {
89         set $1
90         while [ $# -ge 5 ]; do
91                 if [ $1 -eq 0 ]; then
92                         route="default"
93                 elif [ $1 -le 8 ]; then
94                         route="$2.0.0.0/$1"
95                         shift
96                 elif [ $1 -le 16 ]; then
97                         route="$2.$3.0.0/$1"
98                         shift; shift
99                 elif [ $1 -le 24 ]; then
100                         route="$2.$3.$4.0/$1"
101                         shift; shift; shift
102                 else
103                         route="$2.$3.$4.$5/$1"
104                         shift; shift; shift; shift
105                 fi
106                 shift
107                 router="$1.$2.$3.$4"
108                 classless_routes="$classless_routes $route $router"
109                 shift; shift; shift; shift
110         done
111 }
112
113 delete_old_routes() {
114         #route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1
115         if [ -n "$old_classless_routes" ]; then
116                 fill_classless_routes "$old_classless_routes"
117                 set $classless_routes
118                 while [ $# -gt 1 ]; do
119                         route delete "$1" "$2"
120                         shift; shift
121                 done
122                 return 0;
123         fi
124
125         # If we supported multiple default routes, we'd be removing each
126         # one here.  We don't so just delete the default route if it's
127         # through our interface.
128         if is_default_interface; then
129                 route delete default >/dev/null 2>&1
130         fi
131
132         if [ -n "$old_static_routes" ]; then
133                 set $old_static_routes
134                 while [ $# -gt 1 ]; do
135                         route delete "$1" "$2"
136                         shift; shift
137                 done
138         fi
139
140         arp_flush
141 }
142
143 add_new_routes() {
144         #route add $new_ip_address $LOCALHOST >/dev/null 2>&1
145
146         # RFC 3442: If the DHCP server returns both a Classless Static
147         # Routes option and a Router option, the DHCP client MUST ignore
148         # the Router option.
149         #
150         # DHCP clients that support this option (Classless Static Routes)
151         # MUST NOT install the routes specified in the Static Routes
152         # option (option code 33) if both a Static Routes option and the
153         # Classless Static Routes option are provided.
154
155         if [ -n "$new_classless_routes" ]; then
156                 fill_classless_routes "$new_classless_routes"
157                 $LOGGER "New Classless Static Routes ($interface): $classless_routes"
158                 set $classless_routes
159                 while [ $# -gt 1 ]; do
160                         if [ "0.0.0.0" = "$2" ]; then
161                                 route add "$1" -iface "$interface"
162                         else
163                                 route add "$1" "$2"
164                         fi
165                         shift; shift
166                 done
167                 return
168         fi
169
170         for router in $new_routers; do
171                 if is_default_interface; then
172
173                         if [ "$new_ip_address" = "$router" ]; then
174                                 route add default -iface $router >/dev/null 2>&1
175                         else
176                                 route add default $router >/dev/null 2>&1
177                         fi
178                 fi
179                 # 2nd and subsequent default routers error out, so explicitly
180                 # stop processing the list after the first one.
181                 break
182         done
183
184         if [ -n "$new_static_routes" ]; then
185                 $LOGGER "New Static Routes ($interface): $new_static_routes"
186                 set $new_static_routes
187                 while [ $# -gt 1 ]; do
188                         route add $1 $2
189                         shift; shift
190                 done
191         fi
192 }
193
194 add_new_resolv_conf() {
195         # XXX Old code did not create/update resolv.conf unless both
196         # $new_domain_name and $new_domain_name_servers were provided.  PR
197         # #3135 reported some ISP's only provide $new_domain_name_servers and
198         # thus broke the script. This code creates the resolv.conf if either
199         # are provided.
200
201         local tmpres=/var/run/resolv.conf.${interface}
202         rm -f $tmpres
203
204         if [ -n "$new_domain_name" ]; then
205                 echo "search $new_domain_name" >>$tmpres
206         fi
207
208         if [ -n "$new_domain_name_servers" ]; then
209                 for nameserver in $new_domain_name_servers; do
210                         echo "nameserver $nameserver" >>$tmpres
211                 done
212         fi
213
214         if [ -f $tmpres ]; then
215                 if [ -f /etc/resolv.conf.tail ]; then
216                         cat /etc/resolv.conf.tail >>$tmpres
217                 fi
218
219                 case $resolvconf_enable in
220                 # "no", "false", "off", or "0"
221                 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
222                         # When resolv.conf is not changed actually, we don't
223                         # need to update it.
224                         # If /usr is not mounted yet, we cannot use cmp, then
225                         # the following test fails.  In such case, we simply
226                         # ignore an error and do update resolv.conf.
227                         if cmp -s $tmpres /etc/resolv.conf; then
228                                 rm -f $tmpres
229                                 return 0
230                         fi 2>/dev/null
231
232                         # In case (e.g. during OpenBSD installs)
233                         # /etc/resolv.conf is a symbolic link, take
234                         # care to preserve the link and write the new
235                         # data in the correct location.
236
237                         if [ -f /etc/resolv.conf ]; then
238                                 cat /etc/resolv.conf > /etc/resolv.conf.save
239                         fi
240                         cat $tmpres > /etc/resolv.conf
241
242                         # Try to ensure correct ownership and permissions.
243                         chown -RL root:wheel /etc/resolv.conf
244                         chmod -RL 644 /etc/resolv.conf
245                         ;;
246
247                 *)
248                         /sbin/resolvconf -a ${interface} < $tmpres
249                         ;;
250                 esac
251
252                 rm -f $tmpres
253
254                 return 0
255         fi
256
257         return 1
258 }
259
260 # Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
261 exit_with_hooks() {
262         exit_status=$1
263         if [ -f /etc/dhclient-exit-hooks ]; then
264                 . /etc/dhclient-exit-hooks
265         fi
266         # probably should do something with exit status of the local script
267         exit $exit_status
268 }
269
270 # Get the interface with the current ipv4 default route on it using only
271 # commands that are available prior to /usr being mounted.
272 is_default_interface()
273 {
274         routeget="`route -n get -inet default`"
275         oldifs="$IFS"
276         IFS="
277 "
278         defif=
279         for line in $routeget ; do
280                 case $line in
281                 *interface:*)
282                         defif=${line##*: }
283                         ;;
284                 esac
285         done
286         IFS=${oldifs}
287
288         if [ -z "$defif" -o "$defif" = "$interface" ]; then
289                 return 0
290         else
291                 return 1
292         fi
293 }
294
295 #
296 # Start of active code.
297 #
298
299 # Invoke the local dhcp client enter hooks, if they exist.
300 if [ -f /etc/dhclient-enter-hooks ]; then
301         exit_status=0
302         . /etc/dhclient-enter-hooks
303         # allow the local script to abort processing of this state
304         # local script must set exit_status variable to nonzero.
305         if [ $exit_status -ne 0 ]; then
306                 exit $exit_status
307         fi
308 fi
309
310 : ${resolvconf_enable="YES"}
311
312 case $reason in
313 MEDIUM)
314         eval "$IFCONFIG $interface $medium"
315         eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
316         sleep 1
317         ;;
318
319 PREINIT)
320         delete_old_alias
321         $IFCONFIG $interface inet alias 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255 up
322         ;;
323
324 ARPCHECK|ARPSEND)
325         ;;
326
327 BOUND|RENEW|REBIND|REBOOT)
328         check_hostname
329         if [ -n "$old_ip_address" ]; then
330                 if [ "$old_ip_address" != "$alias_ip_address" ]; then
331                         delete_old_alias
332                 fi
333                 if [ "$old_ip_address" != "$new_ip_address" ]; then
334                         delete_old_address
335                         delete_old_routes
336                 fi
337         fi
338         if [ "$reason" = BOUND ] || \
339            [ "$reason" = REBOOT ] || \
340            [ -z "$old_ip_address" ] || \
341            [ "$old_ip_address" != "$new_ip_address" ]; then
342                 add_new_address
343                 add_new_routes
344         fi
345         if [ "$new_ip_address" != "$alias_ip_address" ]; then
346                 add_new_alias
347         fi
348         if is_default_interface; then
349                 add_new_resolv_conf
350         fi
351         ;;
352
353 EXPIRE|FAIL)
354         delete_old_alias
355         if [ -n "$old_ip_address" ]; then
356                 delete_old_address
357                 delete_old_routes
358         fi
359         if [ -x $ARP ]; then
360                 $ARP -d -a -i $interface
361         fi
362         # XXX Why add alias we just deleted above?
363         add_new_alias
364         if is_default_interface; then
365                 case $resolvconf_enable in
366                 # "no", "false", "off", or "0"
367                 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
368                         if [ -f /etc/resolv.conf.save ]; then
369                                 cat /etc/resolv.conf.save > /etc/resolv.conf
370                         fi
371                         ;;
372                 *)
373                         /sbin/resolvconf -d ${interface}
374                         ;;
375                 esac
376         fi
377         ;;
378
379 TIMEOUT)
380         delete_old_alias
381         add_new_address
382         sleep 1
383         if [ -n "$new_routers" ]; then
384                 $LOGGER "New Routers ($interface): $new_routers"
385                 set "$new_routers"
386                 if ping -q -c 1 -t 1 "$1"; then
387                         if [ "$new_ip_address" != "$alias_ip_address" ]; then
388                                 add_new_alias
389                         fi
390                         add_new_routes
391                         if ! is_default_interface; then
392                                 exit_with_hooks 0
393                         fi
394                         if add_new_resolv_conf; then
395                                 exit_with_hooks 0
396                         fi
397                 fi
398         fi
399         eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
400         delete_old_routes
401         exit_with_hooks 1
402         ;;
403 esac
404
405 exit_with_hooks 0