]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/dhclient-script
pkgbase: Put dhclient in its own package
[FreeBSD/FreeBSD.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                                 if [ "$new_subnet_mask" = "255.255.255.255" ]; then
177                                         route add "$router" -iface "$interface" >/dev/null 2>&1
178                                 fi
179
180                                 route add default $router >/dev/null 2>&1
181                         fi
182                 fi
183                 # 2nd and subsequent default routers error out, so explicitly
184                 # stop processing the list after the first one.
185                 break
186         done
187
188         if [ -n "$new_static_routes" ]; then
189                 $LOGGER "New Static Routes ($interface): $new_static_routes"
190                 set $new_static_routes
191                 while [ $# -gt 1 ]; do
192                         route add $1 $2
193                         shift; shift
194                 done
195         fi
196 }
197
198 add_new_resolv_conf() {
199         # XXX Old code did not create/update resolv.conf unless both
200         # $new_domain_name and $new_domain_name_servers were provided.  PR
201         # #3135 reported some ISP's only provide $new_domain_name_servers and
202         # thus broke the script. This code creates the resolv.conf if either
203         # are provided.
204
205         local tmpres=/var/run/resolv.conf.${interface}
206         rm -f $tmpres
207
208         if [ -n "$new_domain_search" ]; then
209                 echo "search $new_domain_search" >>$tmpres
210         elif [ -n "$new_domain_name" ]; then
211                 echo "search $new_domain_name" >>$tmpres
212         fi
213
214         if [ -n "$new_domain_name_servers" ]; then
215                 for nameserver in $new_domain_name_servers; do
216                         echo "nameserver $nameserver" >>$tmpres
217                 done
218         fi
219
220         if [ -f $tmpres ]; then
221                 if [ -f /etc/resolv.conf.tail ]; then
222                         cat /etc/resolv.conf.tail >>$tmpres
223                 fi
224
225                 case $resolvconf_enable in
226                 # "no", "false", "off", or "0"
227                 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
228                         # When resolv.conf is not changed actually, we don't
229                         # need to update it.
230                         # If /usr is not mounted yet, we cannot use cmp, then
231                         # the following test fails.  In such case, we simply
232                         # ignore an error and do update resolv.conf.
233                         if cmp -s $tmpres /etc/resolv.conf; then
234                                 rm -f $tmpres
235                                 return 0
236                         fi 2>/dev/null
237
238                         # In case (e.g. during OpenBSD installs)
239                         # /etc/resolv.conf is a symbolic link, take
240                         # care to preserve the link and write the new
241                         # data in the correct location.
242
243                         if [ -f /etc/resolv.conf ]; then
244                                 cat /etc/resolv.conf > /etc/resolv.conf.save
245                         fi
246                         cat $tmpres > /etc/resolv.conf
247
248                         # Try to ensure correct ownership and permissions.
249                         chown -RL root:wheel /etc/resolv.conf
250                         chmod -RL 644 /etc/resolv.conf
251                         ;;
252
253                 *)
254                         /sbin/resolvconf -a ${interface} < $tmpres
255                         ;;
256                 esac
257
258                 rm -f $tmpres
259
260                 return 0
261         fi
262
263         return 1
264 }
265
266 # Must be used on exit.   Invokes the local dhcp client exit hooks, if any.
267 exit_with_hooks() {
268         exit_status=$1
269         if [ -f /etc/dhclient-exit-hooks ]; then
270                 . /etc/dhclient-exit-hooks
271         fi
272         # probably should do something with exit status of the local script
273         exit $exit_status
274 }
275
276 # Get the interface with the current ipv4 default route on it using only
277 # commands that are available prior to /usr being mounted.
278 is_default_interface()
279 {
280         routeget="`route -n get -inet default`"
281         oldifs="$IFS"
282         IFS="
283 "
284         defif=
285         for line in $routeget ; do
286                 case $line in
287                 *interface:*)
288                         defif=${line##*: }
289                         ;;
290                 esac
291         done
292         IFS=${oldifs}
293
294         if [ -z "$defif" -o "$defif" = "$interface" ]; then
295                 return 0
296         else
297                 return 1
298         fi
299 }
300
301 #
302 # Start of active code.
303 #
304
305 # Invoke the local dhcp client enter hooks, if they exist.
306 if [ -f /etc/dhclient-enter-hooks ]; then
307         exit_status=0
308         . /etc/dhclient-enter-hooks
309         # allow the local script to abort processing of this state
310         # local script must set exit_status variable to nonzero.
311         if [ $exit_status -ne 0 ]; then
312                 exit $exit_status
313         fi
314 fi
315
316 : ${resolvconf_enable="YES"}
317
318 case $reason in
319 MEDIUM)
320         eval "$IFCONFIG $interface $medium"
321         eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1
322         sleep 1
323         ;;
324
325 PREINIT)
326         delete_old_alias
327         $IFCONFIG $interface inet alias 0.0.0.0 netmask 255.0.0.0 broadcast 255.255.255.255 up
328         ;;
329
330 ARPCHECK|ARPSEND)
331         ;;
332
333 BOUND|RENEW|REBIND|REBOOT)
334         check_hostname
335         if [ -n "$old_ip_address" ]; then
336                 if [ "$old_ip_address" != "$alias_ip_address" ]; then
337                         delete_old_alias
338                 fi
339                 if [ "$old_ip_address" != "$new_ip_address" ]; then
340                         delete_old_address
341                         delete_old_routes
342                 fi
343         fi
344         if [ "$reason" = BOUND ] || \
345            [ "$reason" = REBOOT ] || \
346            [ -z "$old_ip_address" ] || \
347            [ "$old_ip_address" != "$new_ip_address" ]; then
348                 add_new_address
349                 add_new_routes
350         fi
351         if [ "$new_ip_address" != "$alias_ip_address" ]; then
352                 add_new_alias
353         fi
354         if is_default_interface; then
355                 add_new_resolv_conf
356         fi
357         ;;
358
359 EXPIRE|FAIL)
360         delete_old_alias
361         if [ -n "$old_ip_address" ]; then
362                 delete_old_address
363                 delete_old_routes
364         fi
365         if [ -x $ARP ]; then
366                 $ARP -d -a -i $interface
367         fi
368         # XXX Why add alias we just deleted above?
369         add_new_alias
370         if is_default_interface; then
371                 case $resolvconf_enable in
372                 # "no", "false", "off", or "0"
373                 [Nn][Oo]|[Ff][Aa][Ll][Ss][Ee]|[Oo][Ff][Ff]|0)
374                         if [ -f /etc/resolv.conf.save ]; then
375                                 cat /etc/resolv.conf.save > /etc/resolv.conf
376                         fi
377                         ;;
378                 *)
379                         /sbin/resolvconf -d ${interface}
380                         ;;
381                 esac
382         fi
383         ;;
384
385 TIMEOUT)
386         delete_old_alias
387         add_new_address
388         sleep 1
389         if [ -n "$new_routers" ]; then
390                 $LOGGER "New Routers ($interface): $new_routers"
391                 set "$new_routers"
392                 if ping -q -c 1 -t 1 "$1"; then
393                         if [ "$new_ip_address" != "$alias_ip_address" ]; then
394                                 add_new_alias
395                         fi
396                         add_new_routes
397                         if ! is_default_interface; then
398                                 exit_with_hooks 0
399                         fi
400                         if add_new_resolv_conf; then
401                                 exit_with_hooks 0
402                         fi
403                 fi
404         fi
405         eval "$IFCONFIG $interface inet -alias $new_ip_address $medium"
406         delete_old_routes
407         exit_with_hooks 1
408         ;;
409 esac
410
411 exit_with_hooks 0