| #!/bin/sh |
| # dhclient-script for Linux. Dan Halbert, March, 1997. |
| # Updated for Linux 2.[12] by Brian J. Murrell, January 1999. |
| # No guarantees about this. I'm a novice at the details of Linux |
| # networking. |
| # Conversion to use ip for ipv4 (instead of ifconfig, route) by Peter Marschall |
| # Extended for 4.2.2, and ip output to /dev/null removed, by Ken Moffat |
| |
| # Notes: |
| |
| # 0. This script is based on the netbsd script supplied with dhcp-970306. |
| |
| # 1. ifconfig down apparently deletes all relevant routes and flushes |
| # the arp cache, so this doesn't need to be done explicitly. |
| |
| # 2. The alias address handling here has not been tested AT ALL. |
| # I'm just going by the doc of modern Linux ip aliasing, which uses |
| # notations like eth0:0, eth0:1, for each alias. |
| |
| # 3. I have to calculate the network address, and calculate the broadcast |
| # address if it is not supplied. This might be much more easily done |
| # by the dhclient C code, and passed on. |
| |
| # 4. TIMEOUT not tested. ping has a flag I don't know, and I'm suspicious |
| # of the $1 in its args. |
| |
| . /etc/utils.sh |
| |
| ip=ip |
| wifi_ifc=eth2 |
| |
| log() { |
| echo "$@" >&2 |
| } |
| |
| log_file_contents() { |
| local filename="$1" |
| while read line; do |
| log "$filename: $line" |
| done <$filename |
| } |
| |
| routable_ifc() { |
| [ "$interface" != "$wifi_ifc" ] |
| } |
| |
| is_ipv6() { |
| endswith "$reason" "6" |
| } |
| |
| merge_resolv_conf() { |
| # TODO(dgentry) fix uclibc (http://lists.uclibc.org/pipermail/uclibc/2011-June/045440.html) |
| # and then also add /tmp/resolv.conf.dhclient6 |
| local confs="" |
| |
| if [ -e "/tmp/resolv.conf.dhclient" ] ; then |
| confs="$confs /tmp/resolv.conf.dhclient" |
| fi |
| |
| if [ -e /tmp/ipv6_dns_ok ] && [ -e "/tmp/resolv.conf.dhclient6" ]; then |
| confs="$confs /tmp/resolv.conf.dhclient6" |
| fi |
| |
| if [ -n "$confs" ] ; then |
| atomic /tmp/resolv.conf "$(cat $confs)" |
| log_file_contents /tmp/resolv.conf |
| fi |
| } |
| |
| make_resolv_conf() { |
| if [ -n "$new_domain_name_servers" ]; then |
| atomic /tmp/resolv.conf.dhclient "$( |
| if [ -n "$new_domain_search" ]; then |
| echo search $new_domain_search |
| log "dns4 search $new_domain_search" |
| elif [ -n "$new_domain_name" ]; then |
| # Note that the DHCP 'Domain Name Option' is really just a domain |
| # name, and that this practice of using the domain name option as |
| # a search path is both nonstandard and deprecated. |
| echo search $new_domain_name |
| log "dns4 search $new_domain_name" |
| fi |
| for nameserver in $new_domain_name_servers; do |
| echo nameserver $nameserver |
| log "dns4 nameserver $nameserver" |
| done |
| )" |
| merge_resolv_conf |
| elif [ -n "$new_dhcp6_name_servers" ] ; then |
| atomic /tmp/resolv.conf.dhclient6 "$( |
| if [ -n "$new_dhcp6_domain_search" ]; then |
| echo search $new_dhcp6_domain_search |
| log "dns6 search $new_dhcp6_domain_search" |
| fi |
| for nameserver in $new_dhcp6_name_servers; do |
| echo nameserver $nameserver |
| log "dns6 nameserver $nameserver" |
| done |
| )" |
| merge_resolv_conf |
| fi |
| |
| if [ ! -f /tmp/dhclient-logs-uploaded ]; then |
| upload-logs-now |
| atomic /tmp/dhclient-logs-uploaded "done" |
| fi |
| } |
| |
| make_cwmp_files() { |
| if [ -n "$new_cwmp_acs_url" ]; then |
| log "cwmp dhcp acs '$new_cwmp_acs_url'" |
| if is_ipv6; then |
| set-acs dhcp6 "$new_cwmp_acs_url" |
| else |
| set-acs dhcp "$new_cwmp_acs_url" |
| fi |
| fi |
| if [ -n "$new_cwmp_provisioning_code" ]; then |
| atomic /tmp/cwmp/provisioning_code "$new_cwmp_provisioning_code" |
| log "cwmp provisioning '$new_cwmp_provisioning_code'" |
| fi |
| if [ -n "$new_cwmp_retry_minimum_wait_interval" ]; then |
| atomic /tmp/cwmp/retry_minimum_wait_interval "$new_cwmp_retry_minimum_wait_interval" |
| log "cwmp retry minwait '$new_cwmp_retry_minimum_wait_interval'" |
| fi |
| if [ -n "$new_cwmp_retry_interval_multiplier" ]; then |
| atomic /tmp/cwmp/retry_interval_multiplier "$new_cwmp_retry_interval_multiplier" |
| log "cwmp retry mult '$new_cwmp_retry_interval_multiplier'" |
| fi |
| } |
| |
| make_etc_hosts() { |
| atomic /tmp/hosts "$( |
| echo "$new_ip_address $(hostname)" |
| echo "127.0.0.1 localhost" |
| )" |
| log_file_contents /tmp/hosts |
| } |
| |
| make_new_ntp_conf_and_restart() { |
| atomic /tmp/ntpd.conf \ |
| "$(cat /etc/ntpd.conf.default /tmp/ntpd4.conf /tmp/ntpd6.conf \ |
| 2>/dev/null)" |
| log_file_contents /tmp/ntpd.conf |
| restart ntpd |
| } |
| |
| write_ntp_conf_new() |
| { |
| fname=$1 |
| |
| if [ -z "$new_ntp_servers" ]; then |
| rm -f "$fname" |
| log "no new ntp servers" |
| return |
| fi |
| |
| atomic "$fname" "$( |
| for server in $new_ntp_servers; do |
| echo "server $server" |
| done |
| )" |
| } |
| |
| # Must be used on exit. Invokes the local dhcp client exit hooks, if any. |
| exit_with_hooks() { |
| exit_status=$1 |
| case $reason in |
| BOUND|RENEW|REBIND|REBOOT) |
| write_ntp_conf_new /tmp/ntpd4.conf |
| ;; |
| |
| BOUND6|RENEW6|REBIND6|REBOOT6) |
| write_ntp_conf_new /tmp/ntpd6.conf |
| ;; |
| |
| EXPIRE|FAIL|RELEASE|STOP) |
| echo "Removing DHCP4 ntp servers on $reason" |
| rm -f /tmp/ntpd4.conf |
| ;; |
| |
| EXPIRE6|FAIL6|RELEASE6|STOP6) |
| echo "Removing DHCP6 ntp servers on $reason" |
| rm -f /tmp/ntpd6.conf |
| ;; |
| esac |
| make_new_ntp_conf_and_restart |
| exit $exit_status |
| } |
| |
| ### |
| ### DHCPv4 Handlers |
| ### |
| |
| if [ x$new_broadcast_address != x ]; then |
| new_broadcast_arg="broadcast $new_broadcast_address" |
| fi |
| if [ x$old_broadcast_address != x ]; then |
| old_broadcast_arg="broadcast $old_broadcast_address" |
| fi |
| if [ -n "$new_subnet_mask" ]; then |
| new_mask="/$new_subnet_mask" |
| fi |
| if [ -n "$alias_subnet_mask" ]; then |
| alias_mask="/$alias_subnet_mask" |
| fi |
| if [ x$IF_METRIC != x ]; then |
| metric_arg="metric $IF_METRIC" |
| fi |
| |
| if [ x$reason = xMEDIUM ]; then |
| # Linux doesn't do mediums (ok, ok, media). |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xPREINIT ]; then |
| if [ x$alias_ip_address != x ]; then |
| # Bring down alias interface. Its routes will disappear too. |
| $ip -4 addr flush dev ${interface} label ${interface}:0 |
| fi |
| $ip link set dev ${interface} up |
| |
| # We need to give the kernel some time to get the interface up. |
| sleep 1 |
| |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xARPCHECK ] || [ x$reason = xARPSEND ]; then |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xBOUND ] || [ x$reason = xRENEW ] || \ |
| [ x$reason = xREBIND ] || [ x$reason = xREBOOT ]; then |
| |
| if [ x$old_ip_address != x ] && [ x$alias_ip_address != x ] && \ |
| [ x$alias_ip_address != x$old_ip_address ]; then |
| # Possible new alias. Remove old alias. |
| $ip -4 addr flush dev ${interface} label ${interface}:0 |
| fi |
| if [ x$old_ip_address != x ] && [ x$old_ip_address != x$new_ip_address ]; then |
| # IP address changed. Bringing down the interface will delete all routes, |
| # and clear the ARP cache. |
| $ip -4 addr flush dev ${interface} label ${interface} |
| |
| fi |
| if [ x$old_ip_address = x ] || [ x$old_ip_address != x$new_ip_address ] || \ |
| [ x$reason = xBOUND ] || [ x$reason = xREBOOT ]; then |
| |
| $ip -4 addr add ${new_ip_address}${new_mask} ${new_broadcast_arg} \ |
| dev ${interface} label ${interface} 2>/dev/null |
| if [ -n "$new_interface_mtu" ]; then |
| # set MTU |
| $ip link set dev ${interface} mtu ${new_interface_mtu} |
| fi |
| # Add a network route to the computed network address. |
| if routable_ifc; then |
| if [ x$new_routers != x ] && [ x$new_routers != x$old_routers ] ; then |
| # if we've changed routers delete the old and add the new. |
| for router in $old_routers; do |
| $ip -4 route del via $router |
| done |
| fi |
| for router in $new_routers; do |
| if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then |
| $ip -4 route add ${router} dev $interface |
| fi |
| $ip -4 route add default via ${router} dev ${interface} \ |
| ${metric_arg} |
| done |
| fi |
| fi |
| if [ x$new_ip_address != x$alias_ip_address ] && [ x$alias_ip_address != x ]; |
| then |
| $ip -4 addr flush dev ${interface} label ${interface}:0 |
| $ip -4 addr add ${alias_ip_address}${alias_mask} \ |
| dev ${interface} label ${interface}:0 |
| $ip -4 route add ${alias_ip_address} dev ${interface} |
| fi |
| make_resolv_conf |
| make_cwmp_files |
| make_etc_hosts |
| set-acs bounce |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xFAIL ] || [ x$reason = xRELEASE ] \ |
| || [ x$reason = xSTOP ]; then |
| if [ x$alias_ip_address != x ]; then |
| # Turn off alias interface. |
| $ip -4 addr flush dev ${interface} label ${interface}:0 |
| fi |
| if [ x$old_ip_address != x ]; then |
| # Shut down interface, which will delete routes and clear arp cache. |
| $ip -4 addr flush dev ${interface} label ${interface} |
| fi |
| if [ x$alias_ip_address != x ]; then |
| $ip -4 addr add ${alias_ip_address}${alias_network_arg} \ |
| dev ${interface} label ${interface}:0 |
| $ip -4 route add ${alias_ip_address} dev ${interface} |
| fi |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xTIMEOUT ]; then |
| if [ x$alias_ip_address != x ]; then |
| $ip -4 addr flush dev ${interface} label ${interface}:0 |
| fi |
| $ip -4 addr add ${new_ip_address}${new_mask} ${new_broadcast_arg} \ |
| dev ${interface} label ${interface} |
| if [ -n "$new_interface_mtu" ]; then |
| # set MTU |
| ip link set dev ${interface} mtu ${new_interface_mtu} |
| fi |
| set $new_routers |
| if routable_ifc && ping -q -c 1 $1; then |
| if [ x$new_ip_address != x$alias_ip_address ] && \ |
| [ x$alias_ip_address != x ]; then |
| $ip -4 addr add ${alias_ip_address}${alias_mask} \ |
| dev ${interface} label ${interface}:0 |
| $ip -4 route add ${alias_ip_address} dev ${interface} |
| fi |
| for router in $new_routers; do |
| if [ "x$new_subnet_mask" = "x255.255.255.255" ] ; then |
| $ip -4 route add ${router} dev $interface |
| fi |
| $ip -4 route add default via ${router} dev ${interface} \ |
| ${metric_arg} |
| done |
| make_resolv_conf |
| make_cwmp_files |
| make_etc_hosts |
| exit_with_hooks 0 |
| fi |
| $ip -4 addr flush dev ${interface} |
| exit_with_hooks 1 |
| fi |
| |
| ### |
| ### DHCPv6 Handlers |
| ### |
| |
| if [ x$reason = xPREINIT6 ] ; then |
| # Ensure interface is up. |
| $ip link set ${interface} up |
| |
| # Remove any stale addresses from aborted clients. |
| $ip -f inet6 addr flush dev ${interface} scope global permanent |
| |
| exit_with_hooks 0 |
| fi |
| |
| if [ x${old_ip6_prefix} != x ] || [ x${new_ip6_prefix} != x ] ; then |
| echo Prefix ${reason} old=${old_ip6_prefix} new=${new_ip6_prefix} |
| |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xBOUND6 ] ; then |
| if [ x${new_ip6_address} = x ] || [ x${new_ip6_prefixlen} = x ] ; then |
| exit_with_hooks 2; |
| fi |
| |
| $ip -f inet6 addr add ${new_ip6_address}/${new_ip6_prefixlen} \ |
| dev ${interface} scope global |
| |
| # Check for nameserver options. |
| make_resolv_conf |
| make_cwmp_files |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xRENEW6 ] || [ x$reason = xREBIND6 ] ; then |
| # Make sure nothing has moved around on us. |
| |
| # Nameservers/domains/etc. |
| if [ "x${new_dhcp6_name_servers}" != "x${old_dhcp6_name_servers}" ] || |
| [ "x${new_dhcp6_domain_search}" != "x${old_dhcp6_domain_search}" ] ; then |
| make_resolv_conf |
| fi |
| |
| if [ "x${new_cwmp_acs_url}" != "x${old_cwmp_acs_url}" ] || |
| [ "x${new_cwmp_provisioning_code}" != "x${old_cwmp_provisioning_code}" ] || |
| [ "x${new_cwmp_retry_minimum_wait_interval}" != "x${old_cwmp_retry_minimum_wait_interval}" ] || |
| [ "x${new_cwmp_retry_interval_multiplier}" != "x${old_cwmp_retry_interval_multiplier}" ] ; then |
| make_cwmp_files |
| fi |
| |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xDEPREF6 ] ; then |
| if [ x${new_ip6_prefixlen} = x ] ; then |
| exit_with_hooks 2; |
| fi |
| |
| $ip -f inet6 addr change ${new_ip6_address}/${new_ip6_prefixlen} \ |
| dev ${interface} scope global preferred_lft 0 |
| |
| exit_with_hooks 0 |
| fi |
| |
| if [ x$reason = xRELEASE6 -o x$reason = xSTOP6 ] ; then |
| if [ x${old_ip6_address} = x ] || [ x${old_ip6_prefixlen} = x ] ; then |
| exit_with_hooks 2; |
| fi |
| |
| $ip -f inet6 addr del ${old_ip6_address}/${old_ip6_prefixlen} \ |
| dev ${interface} |
| |
| exit_with_hooks 0 |
| fi |
| |
| exit_with_hooks 0 |