123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439 |
- #!/bin/sh
- # dhclient-script for Linux. Dan Halbert, March, 1997.
- # Updated for Linux 2.[12] by Brian J. Murrell, January 1999.
- # Modified for Debian. Matt Zimmerman and Eloy Paris, December 2003
- # Modified to remove useless tests for antiquated kernel versions that
- # this doesn't even work with anyway, and introduces a dependency on /usr
- # being mounted, which causes cosmetic errors on hosts that NFS mount /usr
- # Andrew Pollock, February 2005
- # Modified to work on point-to-point links. Andrew Pollock, June 2005
- # Modified to support passing the parameters called with to the hooks. Andrew Pollock, November 2005
- # The alias handling in here probably still sucks. -mdz
- # wait for given file to be writable
- wait_for_rw() {
- local file=$1
- # Find out whether we are going to mount / rw
- exec 9>&0 </etc/fstab
- rootmode=rw
- while read dev mnt type opts dump pass junk; do
- [ "$mnt" != / ] && continue
- case "$opts" in
- ro|ro,*|*,ro|*,ro,*)
- rootmode=ro
- ;;
- esac
- done
- exec 0>&9 9>&-
- # Wait for $file to become writable
- if [ "$rootmode" = "rw" ]; then
- while ! { : >> "$file"; } 2>/dev/null; do
- sleep 0.1
- done
- fi
- }
- # update /etc/resolv.conf based on received values
- make_resolv_conf() {
- local new_resolv_conf
- # DHCPv4
- if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||
- [ -n "$new_domain_name_servers" ]; then
- resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
- resolv_conf="/etc/resolv.conf"
- new_resolv_conf="${resolv_conf}.dhclient-new.$$"
- wait_for_rw "$new_resolv_conf"
- rm -f $new_resolv_conf
- if [ -n "$new_domain_name" ]; then
- echo domain ${new_domain_name%% *} >>$new_resolv_conf
- fi
- if [ -n "$new_domain_search" ]; then
- if [ -n "$new_domain_name" ]; then
- domain_in_search_list=""
- for domain in $new_domain_search; do
- if [ "$domain" = "${new_domain_name}" ] ||
- [ "$domain" = "${new_domain_name}." ]; then
- domain_in_search_list="Yes"
- fi
- done
- if [ -z "$domain_in_search_list" ]; then
- new_domain_search="$new_domain_name $new_domain_search"
- fi
- fi
- echo "search ${new_domain_search}" >> $new_resolv_conf
- elif [ -n "$new_domain_name" ]; then
- echo "search ${new_domain_name}" >> $new_resolv_conf
- fi
- if [ -n "$new_domain_name_servers" ]; then
- for nameserver in $new_domain_name_servers; do
- echo nameserver $nameserver >>$new_resolv_conf
- done
- else # keep 'old' nameservers
- sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf
- fi
- if [ -f $resolv_conf ]; then
- chown --reference=$resolv_conf $new_resolv_conf
- chmod --reference=$resolv_conf $new_resolv_conf
- fi
- mv -f $new_resolv_conf $resolv_conf
- # DHCPv6
- elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then
- resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
- resolv_conf="/etc/resolv.conf"
- new_resolv_conf="${resolv_conf}.dhclient-new.$$"
- wait_for_rw "$new_resolv_conf"
- rm -f $new_resolv_conf
- if [ -n "$new_dhcp6_domain_search" ]; then
- echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf
- fi
- if [ -n "$new_dhcp6_name_servers" ]; then
- for nameserver in $new_dhcp6_name_servers; do
- # append %interface to link-local-address nameservers
- if [ "${nameserver##fe80::}" != "$nameserver" ] ||
- [ "${nameserver##FE80::}" != "$nameserver" ]; then
- nameserver="${nameserver}%${interface}"
- fi
- echo nameserver $nameserver >>$new_resolv_conf
- done
- else # keep 'old' nameservers
- sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p $resolv_conf >>$new_resolv_conf
- fi
- if [ -f $resolv_conf ]; then
- chown --reference=$resolv_conf $new_resolv_conf
- chmod --reference=$resolv_conf $new_resolv_conf
- fi
- mv -f $new_resolv_conf $resolv_conf
- fi
- }
- # set host name
- set_hostname() {
- if [ -n "$new_host_name" ]; then
- local current_hostname=$(hostname)
- # current host name is empty, '(none)' or 'localhost' or differs from new one from DHCP
- if [ -z "$current_hostname" ] ||
- [ "$current_hostname" = '(none)' ] ||
- [ "$current_hostname" = 'localhost' ] ||
- [ "$current_hostname" = "$old_host_name" ]; then
- if [ "$new_host_name" != "$current_host_name" ]; then
- hostname "$new_host_name"
- fi
- fi
- fi
- }
- # run given script
- run_hook() {
- local script="$1"
- local exit_status=0
- if [ -f $script ]; then
- . $script
- exit_status=$?
- fi
- if [ -n "$exit_status" ] && [ "$exit_status" -ne 0 ]; then
- logger -p daemon.err "$script returned non-zero exit status $exit_status"
- fi
- return $exit_status
- }
- # run scripts in given directory
- run_hookdir() {
- local dir="$1"
- local exit_status=0
- if [ -d "$dir" ]; then
- for script in $(run-parts --list $dir); do
- run_hook $script
- exit_status=$((exit_status|$?))
- done
- fi
- return $exit_status
- }
- # Must be used on exit. Invokes the local dhcp client exit hooks, if any.
- exit_with_hooks() {
- local exit_status=$1
- # Source the documented exit-hook script, if it exists
- if ! run_hook /etc/dhcp/dhclient-exit-hooks; then
- exit_status=$?
- fi
- # Now run scripts in the Debian-specific directory.
- if ! run_hookdir /etc/dhcp/dhclient-exit-hooks.d; then
- exit_status=$?
- fi
- exit $exit_status
- }
- # The 576 MTU is only used for X.25 and dialup connections
- # where the admin wants low latency. Such a low MTU can cause
- # problems with UDP traffic, among other things. As such,
- # disallow MTUs from 576 and below by default, so that broken
- # MTUs are ignored, but higher stuff is allowed (1492, 1500, etc).
- if [ -z "$new_interface_mtu" ] || [ "$new_interface_mtu" -le 576 ]; then
- new_interface_mtu=''
- fi
- # The action starts here
- # Invoke the local dhcp client enter hooks, if they exist.
- run_hook /etc/dhcp/dhclient-enter-hooks
- run_hookdir /etc/dhcp/dhclient-enter-hooks.d
- # Execute the operation
- case "$reason" in
- ### DHCPv4 Handlers
- MEDIUM|ARPCHECK|ARPSEND)
- # Do nothing
- ;;
- PREINIT)
- # The DHCP client is requesting that an interface be
- # configured as required in order to send packets prior to
- # receiving an actual address. - dhclient-script(8)
- # ensure interface is up
- ip link set dev ${interface} up
- if [ -n "$alias_ip_address" ]; then
- # flush alias IP from interface
- ip -4 addr flush dev ${interface} label ${interface}:0
- fi
- ;;
- BOUND|RENEW|REBIND|REBOOT)
- set_hostname
- if [ -n "$old_ip_address" ] && [ -n "$alias_ip_address" ] &&
- [ "$alias_ip_address" != "$old_ip_address" ]; then
- # alias IP may have changed => flush it
- ip -4 addr flush dev ${interface} label ${interface}:0
- fi
- if [ -n "$old_ip_address" ] &&
- [ "$old_ip_address" != "$new_ip_address" ]; then
- # leased IP has changed => flush it
- ip -4 addr flush dev ${interface} label ${interface}
- fi
- if [ -z "$old_ip_address" ] ||
- [ "$old_ip_address" != "$new_ip_address" ] ||
- [ "$reason" = "BOUND" ] || [ "$reason" = "REBOOT" ]; then
- # new IP has been leased or leased IP changed => set it
- ip -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
- ${new_broadcast_address:+broadcast $new_broadcast_address} \
- ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
- ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
- dev ${interface} label ${interface}
- if [ -n "$new_interface_mtu" ]; then
- # set MTU
- ip link set dev ${interface} mtu ${new_interface_mtu}
- fi
- # if we have $new_rfc3442_classless_static_routes then we have to
- # ignore $new_routers entirely
- if [ ! "$new_rfc3442_classless_static_routes" ]; then
- # set if_metric if IF_METRIC is set or there's more than one router
- if_metric="$IF_METRIC"
- if [ "${new_routers%% *}" != "${new_routers}" ]; then
- if_metric=${if_metric:-1}
- fi
- # Is the interface part of a VRF?
- # inspired by https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=964264
- vrf_table="$(ip -d link show dev ${interface} | awk '/vrf_slave/ { print $3 }')"
- vrf_cfg=""
- if [ "${vrf_table}" ]; then
- vrf_cfg="table ${vrf_table}"
- fi
- for router in $new_routers; do
- if [ "$new_subnet_mask" = "255.255.255.255" ]; then
- # point-to-point connection => set explicit route
- ip -4 route add ${router} dev $interface $vrf_cfg >/dev/null 2>&1
- fi
- # set default route
- ip -4 route add default via ${router} dev ${interface} $vrf_cfg \
- ${if_metric:+metric $if_metric} >/dev/null 2>&1
- if [ -n "$if_metric" ]; then
- if_metric=$((if_metric+1))
- fi
- done
- fi
- else # RENEW||REBIND
- ip -4 addr change ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
- ${new_broadcast_address:+broadcast $new_broadcast_address} \
- ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
- ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
- dev ${interface} label ${interface}
- fi
- if [ -n "$alias_ip_address" ] &&
- [ "$new_ip_address" != "$alias_ip_address" ]; then
- # separate alias IP given, which may have changed
- # => flush it, set it & add host route to it
- ip -4 addr flush dev ${interface} label ${interface}:0
- ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
- dev ${interface} label ${interface}:0
- ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
- fi
- # update /etc/resolv.conf
- make_resolv_conf
- ;;
- EXPIRE|FAIL|RELEASE|STOP)
- if [ -n "$alias_ip_address" ]; then
- # flush alias IP
- ip -4 addr flush dev ${interface} label ${interface}:0
- fi
- if [ -n "$old_ip_address" ]; then
- # flush leased IP
- ip -4 addr flush dev ${interface} label ${interface}
- fi
- if [ -n "$alias_ip_address" ]; then
- # alias IP given => set it & add host route to it
- ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
- dev ${interface} label ${interface}:0
- ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
- fi
- ;;
- TIMEOUT)
- if [ -n "$alias_ip_address" ]; then
- # flush alias IP
- ip -4 addr flush dev ${interface} label ${interface}:0
- fi
- # set IP from recorded lease
- ip -4 addr add ${new_ip_address}${new_subnet_mask:+/$new_subnet_mask} \
- ${new_broadcast_address:+broadcast $new_broadcast_address} \
- ${new_dhcp_lease_time:+valid_lft $new_dhcp_lease_time} \
- ${new_dhcp_lease_time:+preferred_lft $new_dhcp_lease_time} \
- dev ${interface} label ${interface}
- if [ -n "$new_interface_mtu" ]; then
- # set MTU
- ip link set dev ${interface} mtu ${new_interface_mtu}
- fi
- # if there is no router recorded in the lease or the 1st router answers pings
- if [ -z "$new_routers" ] || ping -q -c 1 "${new_routers%% *}"; then
- # if we have $new_rfc3442_classless_static_routes then we have to
- # ignore $new_routers entirely
- if [ ! "$new_rfc3442_classless_static_routes" ]; then
- if [ -n "$alias_ip_address" ] &&
- [ "$new_ip_address" != "$alias_ip_address" ]; then
- # separate alias IP given => set up the alias IP & add host route to it
- ip -4 addr add ${alias_ip_address}${alias_subnet_mask:+/$alias_subnet_mask} \
- dev ${interface} label ${interface}:0
- ip -4 route add ${alias_ip_address} dev ${interface} >/dev/null 2>&1
- fi
- # set if_metric if IF_METRIC is set or there's more than one router
- if_metric="$IF_METRIC"
- if [ "${new_routers%% *}" != "${new_routers}" ]; then
- if_metric=${if_metric:-1}
- fi
- # set default route
- for router in $new_routers; do
- ip -4 route add default via ${router} dev ${interface} \
- ${if_metric:+metric $if_metric} >/dev/null 2>&1
- if [ -n "$if_metric" ]; then
- if_metric=$((if_metric+1))
- fi
- done
- fi
- # update /etc/resolv.conf
- make_resolv_conf
- else
- # flush all IPs from interface
- ip -4 addr flush dev ${interface}
- exit_with_hooks 2
- fi
- ;;
- ### DHCPv6 Handlers
- # TODO handle prefix change: ?based on ${old_ip6_prefix} and ${new_ip6_prefix}?
- PREINIT6)
- # ensure interface is up
- ip link set ${interface} up
- # flush any stale global permanent IPs from interface
- ip -6 addr flush dev ${interface} scope global permanent
- ;;
- BOUND6|RENEW6|REBIND6)
- if [ "${new_ip6_address}" ]; then
- # set leased IP
- ip -6 addr replace ${new_ip6_address} \
- dev ${interface} scope global valid_lft ${new_max_life} \
- preferred_lft ${new_preferred_life}
- fi
- # update /etc/resolv.conf
- if [ "${reason}" = BOUND6 ] ||
- [ "${new_dhcp6_name_servers}" != "${old_dhcp6_name_servers}" ] ||
- [ "${new_dhcp6_domain_search}" != "${old_dhcp6_domain_search}" ]; then
- make_resolv_conf
- fi
- ;;
- DEPREF6)
- # set preferred lifetime of leased IP to 0
- ip -6 addr change ${cur_ip6_address} \
- dev ${interface} scope global preferred_lft 0
- ;;
- EXPIRE6|RELEASE6|STOP6)
- if [ -z "${old_ip6_address}" ]; then
- exit_with_hooks 2
- fi
- # delete leased IP
- ip -6 addr del ${old_ip6_address} \
- dev ${interface}
- ;;
- esac
- exit_with_hooks 0
|