Subject: Re: Dhclient weirdness
To: None <firstname.lastname@example.org>
From: Christos Zoulas <email@example.com>
Date: 04/16/2003 23:37:53
In article <Pine.NEB.firstname.lastname@example.org>,
John <email@example.com> wrote:
>I ran across some a very strange dhclient problem and went to some effort
>to fix it -- I want to share my fix with the public.
>I haven't decided if this is a bug in dhclient or not.
>My netbsd 1.6 i386 machine has two interfaces, an rtk on a private network
>with a static ip and an fxp on the internet with a dynamic ip. Naturally,
>I want my routing table's default route to be the one assigned via dhcp to
>the fxp interface.
>The problem was, my IP changed and dhclient automatically reconfigured the
>fxp to the new IP, but it did not alter the default route. (Which caused
>loss of inet connectivity, needless to say.)
>I determined this is due to the environment that /sbin/dhclient passes to
>I have control of the dhcp server (its a dsl router-gadget) and can
>instruct it to assign the fxp a public IP or a private network IP. When
>transitioning from a public IP to a private one, the environment passed to
>dhclient-script does not include the variables old_ip_address or
>old_routers, and so it decides not to adjust the default route. During
>transition from a private IP to a public one, the environment does include
>those two variables, but they are wrong. old_ip_address incorrectly
>equals new_ip_address and the same goes for old_routers. So, it seems the
>problem is influenced by the dhcp server device, although /sbin/dhclient
>should still set the correct old_ values regardless.
>I fixed the problem by writing a /etc/dhclient-enter-hooks script. The
>hook script runs before dhclient-script makes any changes to the active
>config, and if it is run during a BOUND event it uses ifconfig to
>determine the fxp's current IP address, and it uses "netstat -nr" to
>determine the current default route. It then assigns these determined
>values to the variables old_ip_address and old_routers. This has caused
>dhclient-script to work correctly in all my testing.
>If someone would be kind enough to let me know if I ougth to submit a PR,
>I will be happy to do so! Should I also forward this to the ISC??
>Oh yeah.. I might have hit upon a second unrelated bug.. In my
>dhclient-enter-hooks script, I used a command like:
>old_ip_address=`ifconfig fxp0 | grep inet | head -1 | cut -d\ -f 2`
>and this command works great during interactive testing, but results in an
>empty old_ip_address variable when the script is run via dhclient-script.
>I fixed the problem with:
>old_ip_address1=`ifconfig fxp0 | grep inet | head -1`
>old_ip_address=`echo $old_ip_address1 | cut -d\ -f 2`
>Thanks again netbsd community!!
>Fyi, my dhclient-enter-hooks script is attached.
># It seems that if the IP we had been assigned is changed, there is a problem.
># NetBSD 1.6's /sbin/dhclient-script doesn't want to set the default route
># for a primary interface change in some circumstances.
># This script detects that situation and corrects it.
># For the detection part, the env during a failure looks like this:
># old_ip_address != our current ip
># old_routers != the real default route
># For the correction part, we need to correctly set the variables
># First things first, the only dhclient case we need to fix is the BOUND case
># (ip addr chg). We'll do this at the VERY START because 99% of the times
># we are run will be reason=RENEW.
>if [ \( "x$reason" != "xBOUND" \) ]; then
> return 0
># Function to check for a valid IP address...
># Inputs like " 220.127.116.11" and "18.104.22.168 " will fail, so will "255.255.300.255".
># Of course, "255.255.255.255" and "0.0.0.0" and everything in between work.
># Returns 0 on valid input, 1 for a failure
> local IP_NUM_REGEX IP_REGEX REGEX_RESULT
> if [ $# -ne 1 ]; then
> return 1
> REGEX_RESULT="`echo "$1" | egrep "$IP_REGEX" > /dev/null 2>&1 ;echo $?`"
> if [ "$REGEX_RESULT" -ne 0 ]; then
> # echo Fatal: Couldn\'t determine IP\! >&2
> # exit 1
> return 1 # Signal a failure
> return 0 # The argument is indeed strictly an IP
># Load our existing IP address... Store it as $old_ip_address
># The line imm. below is buggy, so we use two vars and it works.. Humm??
>#real_old_ip_address="`ifconfig $interface |grep inet| head -1 | cut -d\ -f 2`"
>real_old_ip_address1="`ifconfig $interface |grep inet| head -1`"
>real_old_ip_address="`echo $real_old_ip_address1 | cut -d\ -f 2`"
>if Verify_IP_Addr "$real_old_ip_address"; then
> export old_ip_address
># Load our default route's IP addres... Store it as $old_routers
># Similarly, the line below is buggy, so the two var approach fixes it..
>#real_old_routers="`netstat -nr | grep default | sed 's/^ *default *//' | \
># cut -d\ -f 1`"
>real_old_routers1="`netstat -nr | grep default | head -1`"
>real_old_routers="`echo $real_old_routers1 | sed 's/^ *default *//' |
>cut -d\ -f 1`"
>if Verify_IP_Addr "$real_old_routers"; then
> export old_routers
>unset real_old_ip_address real_old_routers
># This is debugging stuff -- just ignore all of this.
># (Yes, really debugging - I think we hit a bug in /bin/sh or /usr/bin/head)
>#echo Date is `date`
>#real_old_ip_address1="`ifconfig $interface |grep inet| head -1`"
>#real_old_ip_address="`echo $real_old_ip_address1 | cut -d\ -f 2`"
>#real_old_routers1="`netstat -nr | grep default | head -1`"
>#real_old_routers="`echo $real_old_routers1 | sed 's/^ *default *//' |
>cut -d\ -f 1`"
>#echo Got \[$real_old_ip_address\] and \[$real_old_routers\]
>#echo Was given \[$old_ip_address\] and \[$old_routers\]
>#unset real_old_ip_address real_old_routers
>#) >> /tmp/out 2>&1