1201062Sluigi#!/bin/sh 2201062Sluigi# 3201062Sluigi# $OpenBSD: dhclient-script,v 1.6 2004/05/06 18:22:41 claudio Exp $ 4201062Sluigi# $FreeBSD$ 5201062Sluigi# 6201062Sluigi# Copyright (c) 2003 Kenneth R Westerback <krw@openbsd.org> 7201062Sluigi# 8201062Sluigi# Permission to use, copy, modify, and distribute this software for any 9201062Sluigi# purpose with or without fee is hereby granted, provided that the above 10201062Sluigi# copyright notice and this permission notice appear in all copies. 11201062Sluigi# 12201062Sluigi# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13201062Sluigi# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14201062Sluigi# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15201062Sluigi# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16201062Sluigi# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17201062Sluigi# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18201062Sluigi# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19201062Sluigi# 20201062Sluigi# 21201062Sluigi 22201062SluigiARP=/usr/sbin/arp 23201062SluigiHOSTNAME=/bin/hostname 24201062SluigiIFCONFIG='/sbin/ifconfig -n' 25201062Sluigi 26201062SluigiLOCALHOST=127.0.0.1 27201062Sluigi 28201062Sluigiif [ -x /usr/bin/logger ]; then 29201062Sluigi LOGGER="/usr/bin/logger -s -p user.notice -t dhclient" 30201062Sluigielse 31201062Sluigi LOGGER=echo 32201062Sluigifi 33201062Sluigi 34201062Sluigi# 35201062Sluigi# Helper functions that implement common actions. 36201062Sluigi# 37201062Sluigi 38201062Sluigicheck_hostname() { 39201062Sluigi current_hostname=`$HOSTNAME` 40201062Sluigi if [ -z "$current_hostname" ]; then 41201062Sluigi $LOGGER "New Hostname ($interface): $new_host_name" 42201062Sluigi $HOSTNAME $new_host_name 43201062Sluigi elif [ "$current_hostname" = "$old_host_name" -a \ 44201062Sluigi "$new_host_name" != "$old_host_name" ]; then 45201062Sluigi $LOGGER "New Hostname ($interface): $new_host_name" 46201062Sluigi $HOSTNAME $new_host_name 47201062Sluigi fi 48201062Sluigi} 49201062Sluigi 50201062Sluigiarp_flush() { 51201062Sluigi arp -an -i $interface | \ 52201062Sluigi sed -n -e 's/^.*(\(.*\)) at .*$/arp -d \1/p' | \ 53201062Sluigi sh >/dev/null 2>&1 54201062Sluigi} 55201062Sluigi 56201062Sluigidelete_old_address() { 57201062Sluigi eval "$IFCONFIG $interface inet -alias $old_ip_address $medium" 58201062Sluigi} 59201062Sluigi 60201062Sluigiadd_new_address() { 61201062Sluigi eval "$IFCONFIG $interface \ 62201062Sluigi inet $new_ip_address \ 63201062Sluigi netmask $new_subnet_mask \ 64201062Sluigi broadcast $new_broadcast_address \ 65201062Sluigi $medium" 66201062Sluigi 67201062Sluigi $LOGGER "New IP Address ($interface): $new_ip_address" 68201062Sluigi $LOGGER "New Subnet Mask ($interface): $new_subnet_mask" 69201062Sluigi $LOGGER "New Broadcast Address ($interface): $new_broadcast_address" 70201062Sluigi $LOGGER "New Routers ($interface): $new_routers" 71201062Sluigi} 72201062Sluigi 73201062Sluigidelete_old_alias() { 74201062Sluigi if [ -n "$alias_ip_address" ]; then 75201062Sluigi $IFCONFIG $interface inet -alias $alias_ip_address > /dev/null 2>&1 76201062Sluigi #route delete $alias_ip_address $LOCALHOST > /dev/null 2>&1 77201062Sluigi fi 78201062Sluigi} 79201062Sluigi 80201062Sluigiadd_new_alias() { 81201062Sluigi if [ -n "$alias_ip_address" ]; then 82201062Sluigi $IFCONFIG $interface inet alias $alias_ip_address netmask \ 83201062Sluigi $alias_subnet_mask 84201062Sluigi #route add $alias_ip_address $LOCALHOST 85201062Sluigi fi 86201062Sluigi} 87201062Sluigi 88201062Sluigifill_classless_routes() { 89201062Sluigi set $1 90201062Sluigi while [ $# -ge 5 ]; do 91201062Sluigi if [ $1 -eq 0 ]; then 92201062Sluigi route="default" 93201062Sluigi elif [ $1 -le 8 ]; then 94201062Sluigi route="$2.0.0.0/$1" 95201062Sluigi shift 96201062Sluigi elif [ $1 -le 16 ]; then 97201062Sluigi route="$2.$3.0.0/$1" 98201062Sluigi shift; shift 99201062Sluigi elif [ $1 -le 24 ]; then 100201062Sluigi route="$2.$3.$4.0/$1" 101201062Sluigi shift; shift; shift 102201062Sluigi else 103201062Sluigi route="$2.$3.$4.$5/$1" 104201062Sluigi shift; shift; shift; shift 105201062Sluigi fi 106201062Sluigi shift 107201062Sluigi router="$1.$2.$3.$4" 108201062Sluigi classless_routes="$classless_routes $route $router" 109201062Sluigi shift; shift; shift; shift 110201062Sluigi done 111201062Sluigi} 112201062Sluigi 113201062Sluigidelete_old_routes() { 114201062Sluigi #route delete "$old_ip_address" $LOCALHOST >/dev/null 2>&1 115201062Sluigi if [ -n "$old_classless_routes" ]; then 116201062Sluigi fill_classless_routes "$old_classless_routes" 117201062Sluigi set $classless_routes 118201062Sluigi while [ $# -gt 1 ]; do 119201062Sluigi route delete "$1" "$2" 120201062Sluigi shift; shift 121201062Sluigi done 122201062Sluigi return 0; 123201062Sluigi fi 124201062Sluigi 125201062Sluigi # If we supported multiple default routes, we'd be removing each 126201062Sluigi # one here. We don't so just delete the default route if it's 127201062Sluigi # through our interface. 128201062Sluigi if is_default_interface; then 129201062Sluigi route delete default >/dev/null 2>&1 130201062Sluigi fi 131201062Sluigi 132201062Sluigi if [ -n "$old_static_routes" ]; then 133201062Sluigi set $old_static_routes 134201062Sluigi while [ $# -gt 1 ]; do 135201062Sluigi route delete "$1" "$2" 136201062Sluigi shift; shift 137201062Sluigi done 138201062Sluigi fi 139201062Sluigi 140201062Sluigi arp_flush 141201062Sluigi} 142201062Sluigi 143201062Sluigiadd_new_routes() { 144201062Sluigi #route add $new_ip_address $LOCALHOST >/dev/null 2>&1 145201062Sluigi 146201062Sluigi # RFC 3442: If the DHCP server returns both a Classless Static 147201062Sluigi # Routes option and a Router option, the DHCP client MUST ignore 148201062Sluigi # the Router option. 149201062Sluigi # 150201062Sluigi # DHCP clients that support this option (Classless Static Routes) 151201062Sluigi # MUST NOT install the routes specified in the Static Routes 152201062Sluigi # option (option code 33) if both a Static Routes option and the 153201062Sluigi # Classless Static Routes option are provided. 154201062Sluigi 155201062Sluigi if [ -n "$new_classless_routes" ]; then 156201062Sluigi fill_classless_routes "$new_classless_routes" 157201062Sluigi $LOGGER "New Classless Static Routes ($interface): $classless_routes" 158201062Sluigi set $classless_routes 159201062Sluigi while [ $# -gt 1 ]; do 160201062Sluigi if [ "0.0.0.0" = "$2" ]; then 161201062Sluigi route add "$1" -iface "$interface" 162201062Sluigi else 163201062Sluigi route add "$1" "$2" 164201062Sluigi fi 165201062Sluigi shift; shift 166201062Sluigi done 167201062Sluigi return 168201062Sluigi fi 169201062Sluigi 170201062Sluigi for router in $new_routers; do 171201062Sluigi if is_default_interface; then 172201062Sluigi 173201062Sluigi if [ "$new_ip_address" = "$router" ]; then 174201062Sluigi route add default -iface $router >/dev/null 2>&1 175201062Sluigi else 176201062Sluigi route add default $router >/dev/null 2>&1 177201062Sluigi fi 178201062Sluigi fi 179201062Sluigi # 2nd and subsequent default routers error out, so explicitly 180201062Sluigi # stop processing the list after the first one. 181201062Sluigi break 182201062Sluigi done 183201062Sluigi 184201062Sluigi if [ -n "$new_static_routes" ]; then 185201062Sluigi $LOGGER "New Static Routes ($interface): $new_static_routes" 186201062Sluigi set $new_static_routes 187201062Sluigi while [ $# -gt 1 ]; do 188201062Sluigi route add $1 $2 189201062Sluigi shift; shift 190201062Sluigi done 191201062Sluigi fi 192201062Sluigi} 193201062Sluigi 194201062Sluigiadd_new_resolv_conf() { 195201062Sluigi # XXX Old code did not create/update resolv.conf unless both 196201062Sluigi # $new_domain_name and $new_domain_name_servers were provided. PR 197201062Sluigi # #3135 reported some ISP's only provide $new_domain_name_servers and 198201062Sluigi # thus broke the script. This code creates the resolv.conf if either 199201062Sluigi # are provided. 200201062Sluigi 201201062Sluigi local tmpres=/var/run/resolv.conf.${interface} 202201062Sluigi rm -f $tmpres 203201062Sluigi 204201062Sluigi if [ -n "$new_domain_name" ]; then 205201062Sluigi echo "search $new_domain_name" >>$tmpres 206201062Sluigi fi 207201062Sluigi 208201062Sluigi if [ -n "$new_domain_name_servers" ]; then 209201062Sluigi for nameserver in $new_domain_name_servers; do 210201062Sluigi echo "nameserver $nameserver" >>$tmpres 211201062Sluigi done 212201062Sluigi fi 213201062Sluigi 214201062Sluigi if [ -f $tmpres ]; then 215201062Sluigi if [ -f /etc/resolv.conf.tail ]; then 216201062Sluigi cat /etc/resolv.conf.tail >>$tmpres 217201062Sluigi fi 218201062Sluigi 219201062Sluigi # When resolv.conf is not changed actually, we don't 220201062Sluigi # need to update it. 221201062Sluigi # If /usr is not mounted yet, we cannot use cmp, then 222201062Sluigi # the following test fails. In such case, we simply 223201062Sluigi # ignore an error and do update resolv.conf. 224201062Sluigi if cmp -s $tmpres /etc/resolv.conf; then 225201062Sluigi rm -f $tmpres 226201062Sluigi return 0 227201062Sluigi fi 2>/dev/null 228201062Sluigi 229201062Sluigi # In case (e.g. during OpenBSD installs) /etc/resolv.conf 230201062Sluigi # is a symbolic link, take care to preserve the link and write 231201062Sluigi # the new data in the correct location. 232201062Sluigi 233201062Sluigi if [ -f /etc/resolv.conf ]; then 234201062Sluigi cat /etc/resolv.conf > /etc/resolv.conf.save 235201062Sluigi fi 236201062Sluigi cat $tmpres > /etc/resolv.conf 237201062Sluigi rm -f $tmpres 238201062Sluigi 239201062Sluigi # Try to ensure correct ownership and permissions. 240201062Sluigi chown -RL root:wheel /etc/resolv.conf 241201062Sluigi chmod -RL 644 /etc/resolv.conf 242201062Sluigi 243201062Sluigi return 0 244201062Sluigi fi 245201062Sluigi 246201062Sluigi return 1 247201062Sluigi} 248201062Sluigi 249201062Sluigi# Must be used on exit. Invokes the local dhcp client exit hooks, if any. 250201062Sluigiexit_with_hooks() { 251201062Sluigi exit_status=$1 252201062Sluigi if [ -f /etc/dhclient-exit-hooks ]; then 253201062Sluigi . /etc/dhclient-exit-hooks 254201062Sluigi fi 255201062Sluigi # probably should do something with exit status of the local script 256201062Sluigi exit $exit_status 257201062Sluigi} 258201062Sluigi 259201062Sluigi# Get the interface with the current ipv4 default route on it using only 260201062Sluigi# commands that are available prior to /usr being mounted. 261201062Sluigiis_default_interface() 262201062Sluigi{ 263201062Sluigi routeget="`route -n get -inet default`" 264201062Sluigi oldifs="$IFS" 265201062Sluigi IFS=" 266201062Sluigi" 267201062Sluigi defif= 268201062Sluigi for line in $routeget ; do 269201062Sluigi case $line in 270201062Sluigi *interface:*) 271201062Sluigi defif=${line##*: } 272201062Sluigi ;; 273201062Sluigi esac 274201062Sluigi done 275201062Sluigi IFS=${oldifs} 276201062Sluigi 277201062Sluigi if [ -z "$defif" -o "$defif" = "$interface" ]; then 278201062Sluigi return 0 279201062Sluigi else 280201062Sluigi return 1 281201062Sluigi fi 282201062Sluigi} 283201062Sluigi 284201062Sluigi# 285201062Sluigi# Start of active code. 286201062Sluigi# 287201062Sluigi 288201062Sluigi# Invoke the local dhcp client enter hooks, if they exist. 289201062Sluigiif [ -f /etc/dhclient-enter-hooks ]; then 290201062Sluigi exit_status=0 291201062Sluigi . /etc/dhclient-enter-hooks 292201062Sluigi # allow the local script to abort processing of this state 293201062Sluigi # local script must set exit_status variable to nonzero. 294201062Sluigi if [ $exit_status -ne 0 ]; then 295201062Sluigi exit $exit_status 296201062Sluigi fi 297201062Sluigifi 298201062Sluigi 299201062Sluigicase $reason in 300201062SluigiMEDIUM) 301201062Sluigi eval "$IFCONFIG $interface $medium" 302201062Sluigi eval "$IFCONFIG $interface inet -alias 0.0.0.0 $medium" >/dev/null 2>&1 303201062Sluigi sleep 1 304201062Sluigi ;; 305201062Sluigi 306201062SluigiPREINIT) 307201062Sluigi delete_old_alias 308201062Sluigi $IFCONFIG $interface inet alias 0.0.0.0 netmask 0.0.0.0 broadcast 255.255.255.255 up 309201062Sluigi ;; 310201062Sluigi 311201062SluigiARPCHECK|ARPSEND) 312201062Sluigi ;; 313201062Sluigi 314201062SluigiBOUND|RENEW|REBIND|REBOOT) 315201062Sluigi check_hostname 316201062Sluigi if [ -n "$old_ip_address" ]; then 317201062Sluigi if [ "$old_ip_address" != "$alias_ip_address" ]; then 318201062Sluigi delete_old_alias 319201062Sluigi fi 320201062Sluigi if [ "$old_ip_address" != "$new_ip_address" ]; then 321201062Sluigi delete_old_address 322201062Sluigi delete_old_routes 323201062Sluigi fi 324201062Sluigi fi 325201062Sluigi if [ "$reason" = BOUND ] || \ 326201062Sluigi [ "$reason" = REBOOT ] || \ 327201062Sluigi [ -z "$old_ip_address" ] || \ 328201062Sluigi [ "$old_ip_address" != "$new_ip_address" ]; then 329201062Sluigi add_new_address 330201062Sluigi add_new_routes 331201062Sluigi fi 332201062Sluigi if [ "$new_ip_address" != "$alias_ip_address" ]; then 333201062Sluigi add_new_alias 334201062Sluigi fi 335201062Sluigi if is_default_interface; then 336201062Sluigi add_new_resolv_conf 337201062Sluigi fi 338201062Sluigi ;; 339201062Sluigi 340201062SluigiEXPIRE|FAIL) 341201062Sluigi delete_old_alias 342201062Sluigi if [ -n "$old_ip_address" ]; then 343201062Sluigi delete_old_address 344201062Sluigi delete_old_routes 345201062Sluigi fi 346201062Sluigi if [ -x $ARP ]; then 347201062Sluigi $ARP -d -a -i $interface 348201062Sluigi fi 349201062Sluigi # XXX Why add alias we just deleted above? 350201062Sluigi add_new_alias 351201062Sluigi if is_default_interface; then 352201062Sluigi if [ -f /etc/resolv.conf.save ]; then 353201062Sluigi cat /etc/resolv.conf.save > /etc/resolv.conf 354201062Sluigi fi 355201062Sluigi fi 356201062Sluigi ;; 357201062Sluigi 358201062SluigiTIMEOUT) 359201062Sluigi delete_old_alias 360201062Sluigi add_new_address 361201062Sluigi sleep 1 362201062Sluigi if [ -n "$new_routers" ]; then 363201062Sluigi $LOGGER "New Routers ($interface): $new_routers" 364201062Sluigi set "$new_routers" 365201062Sluigi if ping -q -c 1 -t 1 "$1"; then 366201062Sluigi if [ "$new_ip_address" != "$alias_ip_address" ]; then 367201062Sluigi add_new_alias 368201062Sluigi fi 369201062Sluigi add_new_routes 370201062Sluigi if ! is_default_interface; then 371201062Sluigi exit_with_hooks 0 372201062Sluigi fi 373201062Sluigi if add_new_resolv_conf; then 374201062Sluigi exit_with_hooks 0 375201062Sluigi fi 376201062Sluigi fi 377201062Sluigi fi 378201062Sluigi eval "$IFCONFIG $interface inet -alias $new_ip_address $medium" 379201062Sluigi delete_old_routes 380201062Sluigi exit_with_hooks 1 381201062Sluigi ;; 382201062Sluigiesac 383201062Sluigi 384201062Sluigiexit_with_hooks 0 385