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