Line 0
Link Here
|
|
|
1 |
#!/bin/sh |
2 |
# |
3 |
# $Id: freebsd,v 1.24 2011/05/18 19:55:44 sar Exp $ |
4 |
# |
5 |
# $FreeBSD$ |
6 |
|
7 |
if [ -x /usr/bin/logger ]; then |
8 |
LOGGER="/usr/bin/logger -s -p user.notice -t dhclient" |
9 |
else |
10 |
LOGGER=echo |
11 |
fi |
12 |
|
13 |
make_resolv_conf() { |
14 |
old_domain_search='' |
15 |
old_domain_name_servers='' |
16 |
old_dhcp6_domain_search='' |
17 |
old_dhcp6_name_servers='' |
18 |
while read cmd param net |
19 |
do |
20 |
case "${cmd} ${net}" in |
21 |
("search #IPv4") |
22 |
old_domain_search="${old_domain_search} ${param}" |
23 |
;; |
24 |
("search #IPv6") |
25 |
old_dhcp6_domain_search="${old_dhcp6_domain_search} ${param}" |
26 |
;; |
27 |
("nameserver #IPv4") |
28 |
old_domain_name_servers="${old_domain_name_servers} ${param}" |
29 |
;; |
30 |
("nameserver #IPv6") |
31 |
old_dhcp6_name_servers="${old_dhcp6_name_servers} ${param}" |
32 |
;; |
33 |
esac |
34 |
done < /etc/resolv.conf |
35 |
|
36 |
|
37 |
if [ x"$new_domain_name_servers" != x ]; then |
38 |
( cat /dev/null > /etc/resolv.conf.dhclient ) |
39 |
exit_status=$? |
40 |
if [ $exit_status -ne 0 ]; then |
41 |
$LOGGER "Unable to create /etc/resolv.conf.dhclient: Error $exit_status" |
42 |
else |
43 |
if [ "x$new_domain_search" != x ]; then |
44 |
( echo "search ${new_domain_search} #IPv4" >> /etc/resolv.conf.dhclient ) |
45 |
exit_status=$? |
46 |
elif [ "x$new_domain_name" != x ]; then |
47 |
# Note that the DHCP 'Domain Name Option' is really just a domain |
48 |
# name, and that this practice of using the domain name option as |
49 |
# a search path is both nonstandard and deprecated. |
50 |
( echo "search $new_domain_name #IPv4" >> /etc/resolv.conf.dhclient ) |
51 |
exit_status=$? |
52 |
fi |
53 |
|
54 |
for search in ${old_dhcp6_domain_search} |
55 |
do |
56 |
if [ ${exit_status} -ne 0 ]; then |
57 |
break |
58 |
fi |
59 |
( echo "search ${search} #IPv6" >> /etc/resolv.conf.dhclient ) |
60 |
exit_status=$? |
61 |
done |
62 |
|
63 |
for nameserver in $new_domain_name_servers |
64 |
do |
65 |
if [ $exit_status -ne 0 ]; then |
66 |
break |
67 |
fi |
68 |
( echo "nameserver ${nameserver} #IPv4" >>/etc/resolv.conf.dhclient ) |
69 |
exit_status=$? |
70 |
done |
71 |
for nameserver in ${old_dhcp6_name_servers} |
72 |
do |
73 |
if [ $exit_status -ne 0 ]; then |
74 |
break |
75 |
fi |
76 |
( echo "nameserver ${nameserver} #IPv6" >> /etc/resolv.conf.dhclient ) |
77 |
exit_status=$? |
78 |
done |
79 |
|
80 |
# If there were no errors, attempt to mv the new file into place. |
81 |
if [ $exit_status -eq 0 ]; then |
82 |
( mv /etc/resolv.conf.dhclient /etc/resolv.conf ) |
83 |
exit_status=$? |
84 |
fi |
85 |
|
86 |
if [ $exit_status -ne 0 ]; then |
87 |
$LOGGER "Error while writing new /etc/resolv.conf." |
88 |
fi |
89 |
fi |
90 |
elif [ "x${new_dhcp6_name_servers}" != x ] ; then |
91 |
( cat /dev/null > /etc/resolv.conf.dhclient6 ) |
92 |
exit_status=$? |
93 |
if [ $exit_status -ne 0 ] ; then |
94 |
$LOGGER "Unable to create /etc/resolv.conf.dhclient6: Error $exit_status" |
95 |
else |
96 |
if [ "x${new_dhcp6_domain_search}" != x ] ; then |
97 |
( echo "search ${new_dhcp6_domain_search} #IPv6" >> /etc/resolv.conf.dhclient6 ) |
98 |
exit_status=$? |
99 |
fi |
100 |
|
101 |
for search in ${old_domain_search} |
102 |
do |
103 |
if [ ${exit_status} -ne 0 ]; then |
104 |
break |
105 |
fi |
106 |
( echo "search ${search} #IPv4" >>/etc/resolv.conf.dhclient6 ) |
107 |
exit_status=$? |
108 |
done |
109 |
|
110 |
for nameserver in ${new_dhcp6_name_servers} ; do |
111 |
if [ $exit_status -ne 0 ] ; then |
112 |
break |
113 |
fi |
114 |
# If the nameserver has a link-local address |
115 |
# add a <zone_id> (interface name) to it. |
116 |
case $nameserver in |
117 |
fe80:*) zone_id="%$interface";; |
118 |
FE80:*) zone_id="%$interface";; |
119 |
*) zone_id="";; |
120 |
esac |
121 |
( echo "nameserver ${nameserver}$zone_id #IPv6" >> /etc/resolv.conf.dhclient6 ) |
122 |
exit_status=$? |
123 |
done |
124 |
|
125 |
for nameserver in ${old_domain_name_servers} |
126 |
do |
127 |
if [ $exit_status -ne 0 ]; then |
128 |
break |
129 |
fi |
130 |
( echo "nameserver ${nameserver} #IPv4" >>/etc/resolv.conf.dhclient6 ) |
131 |
exit_status=$? |
132 |
done |
133 |
|
134 |
|
135 |
if [ $exit_status -eq 0 ] ; then |
136 |
( mv /etc/resolv.conf.dhclient6 /etc/resolv.conf ) |
137 |
exit_status=$? |
138 |
fi |
139 |
|
140 |
if [ $exit_status -ne 0 ] ; then |
141 |
$LOGGER "Error while writing new /etc/resolv.conf." |
142 |
fi |
143 |
fi |
144 |
fi |
145 |
} |
146 |
|
147 |
# Must be used on exit. Invokes the local dhcp client exit hooks, if any. |
148 |
exit_with_hooks() { |
149 |
exit_status=$1 |
150 |
if [ -f /etc/dhclient-exit-hooks ]; then |
151 |
. /etc/dhclient-exit-hooks |
152 |
fi |
153 |
# probably should do something with exit status of the local script |
154 |
exit $exit_status |
155 |
} |
156 |
|
157 |
# This function was largely borrowed from dhclient-script that |
158 |
# ships with Centos, authored by Jiri Popelka and David Cantrell |
159 |
# of Redhat. Thanks guys. |
160 |
add_ipv6_addr_with_DAD() { |
161 |
ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} alias |
162 |
|
163 |
if [ ${dad_wait_time} -le 0 ] |
164 |
then |
165 |
# if we're not waiting for DAD, assume we're good |
166 |
return 0 |
167 |
fi |
168 |
|
169 |
# Repeatedly test whether newly added address passed |
170 |
# duplicate address detection (DAD) |
171 |
for i in $(seq 1 ${dad_wait_time}); do |
172 |
sleep 1 # give the DAD some time |
173 |
|
174 |
addr=$(ifconfig ${interface} \ |
175 |
| grep "${new_ip6_address} prefixlen ${new_ip6_prefixlen}") |
176 |
|
177 |
# tentative flag == DAD is still not complete |
178 |
tentative=$(echo "${addr}" | grep tentative) |
179 |
# dadfailed flag == address is already in use somewhere else |
180 |
dadfailed=$(echo "${addr}" | grep duplicated) |
181 |
|
182 |
if [ -n "${dadfailed}" ] ; then |
183 |
# dad failed, remove the address |
184 |
ifconfig ${interface} inet6 ${new_ip6_address}/${new_ip6_prefixlen} -alias |
185 |
exit_with_hooks 3 |
186 |
fi |
187 |
|
188 |
if [ -z "${tentative}" ] ; then |
189 |
if [ -n "${addr}" ]; then |
190 |
# DAD is over |
191 |
return 0 |
192 |
else |
193 |
# address was auto-removed (or not added at all) |
194 |
exit_with_hooks 3 |
195 |
fi |
196 |
fi |
197 |
done |
198 |
|
199 |
return 0 |
200 |
} |
201 |
|
202 |
# Invoke the local dhcp client enter hooks, if they exist. |
203 |
if [ -f /etc/dhclient-enter-hooks ]; then |
204 |
exit_status=0 |
205 |
. /etc/dhclient-enter-hooks |
206 |
# allow the local script to abort processing of this state |
207 |
# local script must set exit_status variable to nonzero. |
208 |
if [ $exit_status -ne 0 ]; then |
209 |
exit $exit_status |
210 |
fi |
211 |
fi |
212 |
|
213 |
if [ x$new_network_number != x ]; then |
214 |
$LOGGER New Network Number: $new_network_number |
215 |
fi |
216 |
|
217 |
if [ x$new_broadcast_address != x ]; then |
218 |
$LOGGER New Broadcast Address: $new_broadcast_address |
219 |
new_broadcast_arg="broadcast $new_broadcast_address" |
220 |
fi |
221 |
if [ x$old_broadcast_address != x ]; then |
222 |
old_broadcast_arg="broadcast $old_broadcast_address" |
223 |
fi |
224 |
if [ x$new_subnet_mask != x ]; then |
225 |
new_netmask_arg="netmask $new_subnet_mask" |
226 |
fi |
227 |
if [ x$old_subnet_mask != x ]; then |
228 |
old_netmask_arg="netmask $old_subnet_mask" |
229 |
fi |
230 |
if [ x$alias_subnet_mask != x ]; then |
231 |
alias_subnet_arg="netmask $alias_subnet_mask" |
232 |
fi |
233 |
if [ x$new_interface_mtu != x ]; then |
234 |
mtu_arg="mtu $new_interface_mtu" |
235 |
fi |
236 |
if [ x$IF_METRIC != x ]; then |
237 |
metric_arg="metric $IF_METRIC" |
238 |
fi |
239 |
|
240 |
if [ x$reason = xMEDIUM ]; then |
241 |
eval "ifconfig $interface $medium" |
242 |
eval "ifconfig $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 |
243 |
sleep 1 |
244 |
exit_with_hooks 0 |
245 |
fi |
246 |
|
247 |
### |
248 |
### DHCPv4 Handlers |
249 |
### |
250 |
|
251 |
if [ x$reason = xPREINIT ]; then |
252 |
if [ x$alias_ip_address != x ]; then |
253 |
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 |
254 |
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 |
255 |
fi |
256 |
ifconfig $interface inet 0.0.0.0 netmask 0.0.0.0 \ |
257 |
broadcast 255.255.255.255 up |
258 |
exit_with_hooks 0 |
259 |
fi |
260 |
|
261 |
if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then |
262 |
exit_with_hooks 0; |
263 |
fi |
264 |
|
265 |
if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ |
266 |
[ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then |
267 |
current_hostname=`/bin/hostname` |
268 |
if [ x$current_hostname = x ] || \ |
269 |
[ x$current_hostname = x$old_host_name ]; then |
270 |
if [ x$current_hostname = x ] || \ |
271 |
[ x$new_host_name != x$old_host_name ]; then |
272 |
$LOGGER "New Hostname: $new_host_name" |
273 |
hostname $new_host_name |
274 |
fi |
275 |
fi |
276 |
if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ |
277 |
[ x$alias_ip_address != x$old_ip_address ]; then |
278 |
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 |
279 |
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 |
280 |
fi |
281 |
if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ] |
282 |
then |
283 |
eval "ifconfig $interface inet -alias $old_ip_address $medium" |
284 |
route delete $old_ip_address 127.1 >/dev/null 2>&1 |
285 |
for router in $old_routers; do |
286 |
route delete default $router >/dev/null 2>&1 |
287 |
done |
288 |
if [ -n "$old_static_routes" ]; then |
289 |
set -- $old_static_routes |
290 |
while [ $# -gt 1 ]; do |
291 |
route delete $1 $2 |
292 |
shift; shift |
293 |
done |
294 |
fi |
295 |
arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' |sh |
296 |
fi |
297 |
if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ |
298 |
[ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then |
299 |
eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ |
300 |
$new_broadcast_arg $mtu_arg $metric_arg $medium" |
301 |
$LOGGER "New IP Address ($interface): $new_ip_address" |
302 |
$LOGGER "New Subnet Mask ($interface): $new_subnet_mask" |
303 |
$LOGGER "New Broadcast Address ($interface): $new_broadcast_address" |
304 |
if [ -n "$new_routers" ]; then |
305 |
$LOGGER "New Routers: $new_routers" |
306 |
fi |
307 |
route add $new_ip_address 127.1 >/dev/null 2>&1 |
308 |
for router in $new_routers; do |
309 |
# If the subnet is captive, eg the netmask is /32 but the default |
310 |
# gateway is (obviously) outside of this, then we need to produce a |
311 |
# host route to reach the gateway. |
312 |
if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then |
313 |
route add -host $router -interface $interface |
314 |
fi |
315 |
route add default $router >/dev/null 2>&1 |
316 |
done |
317 |
if [ -n "$new_static_routes" ]; then |
318 |
$LOGGER "New Static Routes: $new_static_routes" |
319 |
set -- $new_static_routes |
320 |
while [ $# -gt 1 ]; do |
321 |
route add $1 $2 |
322 |
shift; shift |
323 |
done |
324 |
fi |
325 |
else |
326 |
# we haven't changed the address, have we changed other options |
327 |
# that we wish to update? |
328 |
if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then |
329 |
# if we've changed routers delete the old and add the new. |
330 |
$LOGGER "New Routers: $new_routers" |
331 |
for router in $old_routers; do |
332 |
route delete default $router >/dev/null 2>&1 |
333 |
done |
334 |
for router in $new_routers; do |
335 |
# If the subnet is captive, eg the netmask is /32 but the default |
336 |
# gateway is (obviously) outside of this, then we need to produce a |
337 |
# host route to reach the gateway. |
338 |
if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then |
339 |
route add -host $router -interface $interface |
340 |
fi |
341 |
route add default $router >/dev/null 2>&1 |
342 |
done |
343 |
fi |
344 |
fi |
345 |
if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; |
346 |
then |
347 |
ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg |
348 |
route add $alias_ip_address 127.0.0.1 |
349 |
fi |
350 |
make_resolv_conf |
351 |
exit_with_hooks 0 |
352 |
fi |
353 |
|
354 |
if [ x$reason = xEXPIRE ] || [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ |
355 |
|| [ x$reason = xSTOP ]; then |
356 |
if [ x$alias_ip_address != x ]; then |
357 |
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 |
358 |
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 |
359 |
fi |
360 |
if [ x$old_ip_address != x ]; then |
361 |
eval "ifconfig $interface inet -alias $old_ip_address $medium" |
362 |
route delete $old_ip_address 127.1 >/dev/null 2>&1 |
363 |
for router in $old_routers; do |
364 |
route delete default $router >/dev/null 2>&1 |
365 |
done |
366 |
if [ -n "$old_static_routes" ]; then |
367 |
set -- $old_static_routes |
368 |
while [ $# -gt 1 ]; do |
369 |
route delete $1 $2 |
370 |
shift; shift |
371 |
done |
372 |
fi |
373 |
arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \ |
374 |
|sh >/dev/null 2>&1 |
375 |
fi |
376 |
if [ x$alias_ip_address != x ]; then |
377 |
ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg |
378 |
route add $alias_ip_address 127.0.0.1 |
379 |
fi |
380 |
exit_with_hooks 0 |
381 |
fi |
382 |
|
383 |
if [ x$reason = xTIMEOUT ]; then |
384 |
if [ x$alias_ip_address != x ]; then |
385 |
ifconfig $interface inet -alias $alias_ip_address > /dev/null 2>&1 |
386 |
route delete $alias_ip_address 127.0.0.1 > /dev/null 2>&1 |
387 |
fi |
388 |
eval "ifconfig $interface inet $new_ip_address $new_netmask_arg \ |
389 |
$new_broadcast_arg $mtu_arg $metric_arg $medium" |
390 |
$LOGGER "New IP Address ($interface): $new_ip_address" |
391 |
$LOGGER "New Subnet Mask ($interface): $new_subnet_mask" |
392 |
$LOGGER "New Broadcast Address ($interface): $new_broadcast_address" |
393 |
sleep 1 |
394 |
if [ -n "$new_routers" ]; then |
395 |
$LOGGER "New Routers: $new_routers" |
396 |
set -- $new_routers |
397 |
if ping -q -c 1 $1; then |
398 |
if [ x$new_ip_address != x$alias_ip_address ] && \ |
399 |
[ x$alias_ip_address != x ]; then |
400 |
ifconfig $interface inet alias $alias_ip_address $alias_subnet_arg |
401 |
route add $alias_ip_address 127.0.0.1 |
402 |
fi |
403 |
route add $new_ip_address 127.1 >/dev/null 2>&1 |
404 |
for router in $new_routers; do |
405 |
if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then |
406 |
route add -host $router -interface $interface |
407 |
fi |
408 |
route add default $router >/dev/null 2>&1 |
409 |
done |
410 |
set -- $new_static_routes |
411 |
while [ $# -gt 1 ]; do |
412 |
route add $1 $2 |
413 |
shift; shift |
414 |
done |
415 |
make_resolv_conf |
416 |
exit_with_hooks 0 |
417 |
fi |
418 |
fi |
419 |
eval "ifconfig $interface inet -alias $new_ip_address $medium" |
420 |
for router in $old_routers; do |
421 |
route delete default $router >/dev/null 2>&1 |
422 |
done |
423 |
if [ -n "$old_static_routes" ]; then |
424 |
set -- $old_static_routes |
425 |
while [ $# -gt 1 ]; do |
426 |
route delete $1 $2 |
427 |
shift; shift |
428 |
done |
429 |
fi |
430 |
arp -n -a | sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' \ |
431 |
|sh >/dev/null 2>&1 |
432 |
exit_with_hooks 1 |
433 |
fi |
434 |
|
435 |
### |
436 |
### DHCPv6 Handlers |
437 |
### |
438 |
|
439 |
if [ ${reason} = PREINIT6 ] ; then |
440 |
# Ensure interface is up. |
441 |
ifconfig ${interface} up |
442 |
|
443 |
# XXX: Remove any stale addresses from aborted clients. |
444 |
|
445 |
# We need to give the kernel some time to active interface |
446 |
interface_up_wait_time=5 |
447 |
for i in $(seq 0 ${interface_up_wait_time}) |
448 |
do |
449 |
ifconfig ${interface} | grep inactive >/dev/null 2>&1 |
450 |
if [ $? -ne 0 ]; then |
451 |
break; |
452 |
fi |
453 |
sleep 1 |
454 |
done |
455 |
|
456 |
# Wait for duplicate address detection for this interface if the |
457 |
# --dad-wait-time parameter has been specified and is greater than |
458 |
# zero. |
459 |
if [ ${dad_wait_time} -gt 0 ]; then |
460 |
# Check if any IPv6 address on this interface is marked as |
461 |
# tentative. |
462 |
ifconfig ${interface} | grep inet6 | grep tentative \ |
463 |
>/dev/null 2>&1 |
464 |
if [ $? -eq 0 ]; then |
465 |
# Wait for duplicate address detection to complete or for |
466 |
# the timeout specified as --dad-wait-time. |
467 |
for i in $(seq 0 $dad_wait_time) |
468 |
do |
469 |
# We're going to poll for the tentative flag every second. |
470 |
sleep 1 |
471 |
ifconfig ${interface} | grep inet6 | grep tentative \ |
472 |
>/dev/null 2>&1 |
473 |
if [ $? -ne 0 ]; then |
474 |
break; |
475 |
fi |
476 |
done |
477 |
fi |
478 |
fi |
479 |
|
480 |
|
481 |
exit_with_hooks 0 |
482 |
fi |
483 |
|
484 |
if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then |
485 |
echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} |
486 |
|
487 |
exit_with_hooks 0 |
488 |
fi |
489 |
|
490 |
if [ ${reason} = BOUND6 ] ; then |
491 |
if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then |
492 |
exit_with_hooks 2; |
493 |
fi |
494 |
|
495 |
# Add address to interface, check for DAD if dad_wait_time > 0 |
496 |
add_ipv6_addr_with_DAD |
497 |
|
498 |
# Check for nameserver options. |
499 |
make_resolv_conf |
500 |
|
501 |
exit_with_hooks 0 |
502 |
fi |
503 |
|
504 |
if [ ${reason} = RENEW6 ] || [ ${reason} = REBIND6 ] ; then |
505 |
# Make sure nothing has moved around on us. |
506 |
|
507 |
# Nameservers/domains/etc. |
508 |
if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || |
509 |
[ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then |
510 |
make_resolv_conf |
511 |
fi |
512 |
|
513 |
exit_with_hooks 0 |
514 |
fi |
515 |
|
516 |
if [ ${reason} = DEPREF6 ] ; then |
517 |
if [ x${new_ip6_address} = x ] ; then |
518 |
exit_with_hooks 2; |
519 |
fi |
520 |
|
521 |
ifconfig ${interface} inet6 ${new_ip6_address} deprecated |
522 |
|
523 |
exit_with_hooks 0 |
524 |
fi |
525 |
|
526 |
if [ ${reason} = EXPIRE6 -o ${reason} = RELEASE6 -o ${reason} = STOP6 ] ; then |
527 |
if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then |
528 |
exit_with_hooks 2; |
529 |
fi |
530 |
|
531 |
ifconfig ${interface} inet6 ${old_ip6_address}/${old_ip6_prefixlen} -alias |
532 |
|
533 |
exit_with_hooks 0 |
534 |
fi |
535 |
|
536 |
exit_with_hooks 0 |