]> CyberLeo.Net >> Repos - FreeBSD/stable/8.git/blob - sbin/dhclient/dhclient-script
MFC r290326:
[FreeBSD/stable/8.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_search" ]; then
205                 echo "search $new_domain_search" >>$tmpres
206         elif [ -n "$new_domain_name" ]; then
207                 echo "search $new_domain_name" >>$tmpres
208         fi
209
210         if [ -n "$new_domain_name_servers" ]; then
211                 for nameserver in $new_domain_name_servers; do
212                         echo "nameserver $nameserver" >>$tmpres
213                 done
214         fi
215
216         if [ -f $tmpres ]; then
217                 if [ -f /etc/resolv.conf.tail ]; then
218                         cat /etc/resolv.conf.tail >>$tmpres
219                 fi
220
221                 # When resolv.conf is not changed actually, we don't
222                 # need to update it.
223                 # If /usr is not mounted yet, we cannot use cmp, then
224                 # the following test fails.  In such case, we simply
225                 # ignore an error and do update resolv.conf.
226                 if cmp -s $tmpres /etc/resolv.conf; then
227                         rm -f $tmpres
228                         return 0
229                 fi 2>/dev/null
230
231                 # In case (e.g. during OpenBSD installs) /etc/resolv.conf
232                 # is a symbolic link, take care to preserve the link and write
233                 # the new data in the correct location.
234
235                 if [ -f /etc/resolv.conf ]; then
236                         cat /etc/resolv.conf > /etc/resolv.conf.save
237                 fi
238                 cat $tmpres > /etc/resolv.conf
239                 rm -f $tmpres
240
241                 # Try to ensure correct ownership and permissions.
242                 chown -RL root:wheel /etc/resolv.conf
243                 chmod -RL 644 /etc/resolv.conf
244
245                 return 0
246         fi
247
248         return 1
249 }
250
251 # Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
252 exit_with_hooks() {
253         exit_status=$1
254         if [ -f /etc/dhclient-exit-hooks ]; then
255                 . /etc/dhclient-exit-hooks
256         fi
257         # probably should do something with exit status of the local script
258         exit $exit_status
259 }
260
261 # Get the interface with the current ipv4 default route on it using only
262 # commands that are available prior to /usr being mounted.
263 is_default_interface()
264 {
265         routeget="`route -n get -inet default`"
266         oldifs="$IFS"
267         IFS="
268 "
269         defif=
270         for line in $routeget ; do
271                 case $line in
272                 *interface:*)
273                         defif=${line##*: }
274                         ;;
275                 esac
276         done
277         IFS=${oldifs}
278
279         if [ -z "$defif" -o "$defif" = "$interface" ]; then
280                 return 0
281         else
282                 return 1
283         fi
284 }
285
286 #
287 # Start of active code.
288 #
289
290 # Invoke the local dhcp client enter hooks, if they exist.
291 if [ -f /etc/dhclient-enter-hooks ]; then
292         exit_status=0
293         . /etc/dhclient-enter-hooks
294         # allow the local script to abort processing of this state
295         # local script must set exit_status variable to nonzero.
296         if [ $exit_status -ne 0 ]; then
297                 exit $exit_status
298         fi
299 fi
300
301 case $reason in
302 MEDIUM)
303         eval "$IFCONFIG $interface $medium"
304         eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
305         sleep 1
306         ;;
307
308 PREINIT)
309         delete_old_alias
310         $IFCONFIG $interface inet alias 0.0.0.0 netmask 255.0.0.0 broadcast 255.255.255.255 up
311         ;;
312
313 ARPCHECK|ARPSEND)
314         ;;
315
316 BOUND|RENEW|REBIND|REBOOT)
317         check_hostname
318         if [ -n "$old_ip_address" ]; then
319                 if [ "$old_ip_address" != "$alias_ip_address" ]; then
320                         delete_old_alias
321                 fi
322                 if [ "$old_ip_address" != "$new_ip_address" ]; then
323                         delete_old_address
324                         delete_old_routes
325                 fi
326         fi
327         if [ "$reason" = BOUND ] || \
328            [ "$reason" = REBOOT ] || \
329            [ -z "$old_ip_address" ] || \
330            [ "$old_ip_address" != "$new_ip_address" ]; then
331                 add_new_address
332                 add_new_routes
333         fi
334         if [ "$new_ip_address" != "$alias_ip_address" ]; then
335                 add_new_alias
336         fi
337         if is_default_interface; then
338                 add_new_resolv_conf
339         fi
340         ;;
341
342 EXPIRE|FAIL)
343         delete_old_alias
344         if [ -n "$old_ip_address" ]; then
345                 delete_old_address
346                 delete_old_routes
347         fi
348         if [ -x $ARP ]; then
349                 $ARP -d -a -i $interface
350         fi
351         # XXX Why add alias we just deleted above?
352         add_new_alias
353         if is_default_interface; then
354                 if [ -f /etc/resolv.conf.save ]; then
355                         cat /etc/resolv.conf.save > /etc/resolv.conf
356                 fi
357         fi
358         ;;
359
360 TIMEOUT)
361         delete_old_alias
362         add_new_address
363         sleep 1
364         if [ -n "$new_routers" ]; then
365                 $LOGGER "New Routers ($interface): $new_routers"
366                 set "$new_routers"
367                 if ping -q -c 1 -t 1 "$1"; then
368                         if [ "$new_ip_address" != "$alias_ip_address" ]; then
369                                 add_new_alias
370                         fi
371                         add_new_routes
372                         if ! is_default_interface; then
373                                 exit_with_hooks 0
374                         fi
375                         if add_new_resolv_conf; then
376                                 exit_with_hooks 0
377                         fi
378                 fi
379         fi
380         eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
381         delete_old_routes
382         exit_with_hooks 1
383         ;;
384 esac
385
386 exit_with_hooks 0