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