[prev in list] [next in list] [prev in thread] [next in thread] 

List:       dhcp-client
Subject:    Re: Using dhclient for IP-Aliasing
From:       "Schulz, Martin" <martin.schulz () eds ! com>
Date:       2000-03-22 14:12:59
[Download RAW message or body]

   *** From dhcp-client -- To unsubscribe, see the end of this message. ***

"Rasmus Ronlev" wrote:
> 
> Hi,
> 
> I just (today) downloaded the dhcp(d) utilities, as in the source
> distribution: dhcp-3.0b1pl13.tar.gz, and played arround with it for all
> day long (now into the night, having no life a friday night :).
> 
> I think I've studied the README + man pages rather carefully, but a
> solution for my needs still seem far away. What I want to do is the
> following:
> 
> - To set up a 'secondary' IP, on a mashine, that has and is supposed to
> run with a fixed IP. The secondary IP would have to be obtained using
> dhcp (dhclient), as it is not needed to be a fixed IP, and the network
> admin doesn't feel that I should tie up more than one IP from the 'fixed
> IP address pool'.
> 
> The fixed IP is running without problems on the eth0 device of a Linux
> 2.2.14 kernel based system. The IP obtained through dhcp should be
> assigned to eth0:0.
> What I'm looking for here, is how to make that happen using dhclient (+
> a script, if this is nessecary - as it seems to be :).
> 
> The idea solution would be to have two scripts, one to run, to optain an
> IP from the dhcp server, and another one to kill the IP and release it
> to the dhcp server, as I do not always need an alias'ed IP address on
> the mashine, just for uses sometimes (which is also why I didn't just
> get a 2nd fixed IP).
> 
> When I try to run dhclient with the parameters: dhclient eth0:0 I get an
> error, that the script (that comes with the source) can not bind to the
> device, and the script just loops, if I run dhclient without any
> parameters, with the interface "eth0:0" { ... statement in the
> /etc/dhcleint.conf file. So, I'm pretty much buggered, and would
> appreciate any insight any people might have to get the outlined setup
> running.
> 
> Regards,
> Rasmus Ronlev, rasmus@ronlev.com
> 
>
I've had a similar experience, being flabberghasted by the absence of a
decent 'model' of the client IP management. (Is the interface to be reset?
Are aliases to be preserved? etc.). But then I haven't bothered to read the
RFC either.

The beauty is that the client logic is dealt with in dhclient-script, so you
can do there what you want.
The pity is that the linux default script is so-so.

The dhclient.conf allows you to declare an alias, which is duefully passed
on to the dhclient-script, where it gets (not so duefully) clobbered.

Here's what I did to get the dhclient-script 'respect' my alias (not a claim
to fame, but works fine for me):

# in /etc/dhclient.conf:
alias {
  interface "eth0";
  fixed-address 192.168.100.100;
  option subnet-mask 255.255.255.0;
  option domain-name "mydomain";
  option broadcast-address 192.168.100.255;
}

Then use a modified dhclient-script like the attached. It's still attached,
isn't it?

Setting up multiple IP addresses under Linux 2.2 is trivial, once you use
the right tool.
(The older :0 aliasing syntax is deprecated and not necessary at all)

However, here's the double catch:
1) You need the 'ip' program (which is useful in its own right):
   Download iproute2 from ftp://ftp.inr.ac.ru/ip-routing/ or simply
   ftp://rpmfind.net/linux/SuSE-Linux/i386/6.3/suse/n1/iproute2.rpm
2) The ip programs expects its subnet masks as simple ints 0-32 (#of hi
bits set in mask),
   and for simplicity the script expects these to be set in the
new_mask_bits and
   alias_mask_bits shell/environment variables.

To get around point 2, either compute the _mask_bits from the _mask
variables or patch
the dhclient source (v. 2.0) as follows (sorry if netscape screwed up
the paste with spaces):

diff -rc dhcp-2.0/client/dhclient.c dhcp-2.0-new/client/dhclient.c
*** dhcp-2.0/client/dhclient.c  Tue Jun 22 09:36:46 1999
--- dhcp-2.0-new/client/dhclient.c      Sun Jan  9 23:48:21 2000
***************
*** 1936,1941 ****
--- 1936,1942 ----
        struct client_lease *lease;
  {
        int i;
+       int mask_bits;
        u_int8_t dbuf [1500];
        int len;

***************
*** 1961,1970 ****
--- 1962,1977 ----
                netmask.len = lease -> options [DHO_SUBNET_MASK].len;

                subnet = subnet_number (lease -> address, netmask);
+               mask_bits = subnet_bits (netmask);
                if (subnet.len) {
                        fprintf (scriptFile,
"%snetwork_number=\"%s\";\n", 
                                 prefix, piaddr (subnet));
                        fprintf (scriptFile, "export
%snetwork_number\n",
+                                prefix);
+
+                       fprintf (scriptFile, "%smask_bits=\"%d\";\n",
+                                prefix, mask_bits);
+                       fprintf (scriptFile, "export %smask_bits\n",
                                 prefix);

                        if (!lease -> options
[DHO_BROADCAST_ADDRESS].len) {
*** dhcp-2.0/common/inet.c      Sat Apr 24 12:48:10 1999
--- dhcp-2.0-new/common/inet.c  Sun Jan  9 23:48:21 2000
***************
*** 68,73 ****
--- 68,90 ----
        return rv;
  }                                                                 

+ int subnet_bits (mask)
+       struct iaddr mask;
+ {
+       int i;
+       int m;
+       int bits = 0;
+       for (i = 0; i < mask.len && (m = mask.iabuf[i]); i++) {
+
+               while ( m & 0x80 ) {          
+                       m &= ~0x80;
+                       m <<=1;
+                       bits++;
+               }         
+       }
+       return bits;
+ }
+ 
  /* Combine a network number and a integer to produce an internet
address.
     This won't work for subnets with more than 32 bits of host address,
but
     maybe this isn't a problem.
*/                                         

I'm pretty sure that's just as easy to do in version 3.0.

Enjoy and let me know what you think...

	Martin



-- Attached file included as plaintext by Listar --
-- File: dhclient-script

#!/bin/sh

# Invoke the local dhcp client exit hooks, if any.
function exit_with_hooks() {
  exit_status=$1
  if [ -x /etc/dhclient-exit-hooks ]; then
    . /etc/dhclient-exit-hooks
  fi
# probably should do something with exit status of the local script
  exit $exit_status
}

function update_resolv_conf
{
  if [ ! -z "$new_domain_name" -o ! -z "$new_domain_name_servers" ]
  then
      cp /etc/resolv.conf /tmp/resolv.conf.dhclient
      if [ ! -z "$new_domain_name" ]
      then
	  grep -q '^[ \t]*search[ \t][ \t]*'"$new_domain_name" /tmp/resolv.conf.dhclient || \
          	echo search $new_domain_name >>/tmp/resolv.conf.dhclient
      fi
      if [ ! -z "$new_domain_name_servers" ]
      then
      	for nameserver in $new_domain_name_servers; do
	  grep -q '^[ \t]*nameserver[ \t][ \t]*'"$nameserver" /tmp/resolv.conf.dhclient || \
      		echo nameserver $nameserver >>/tmp/resolv.conf.dhclient
        done
      fi

      if [ ! -f /etc/resolv.conf ] \
         || ! diff -q /etc/resolv.conf /tmp/resolv.conf.dhclient
      then
        if [ -f /etc/resolv.conf ]
        then
      	  ln /etc/resolv.conf  /etc/resolv.conf.bak
        fi
      	mv /tmp/resolv.conf.dhclient /etc/resolv.conf
      fi
  fi
}

function config_routers
{
  if [ ! -z "$new_routers" ]
  then  
    for router in $new_routers
    do
	route add default gw $router
    done
  else
    status=1
  fi
}

status=0

# Invoke the local dhcp client enter hooks, if they exist.
if [ -x /etc/dhclient-enter-hooks ]; then
  exit_status=0
  . /etc/dhclient-enter-hooks
  # allow the local script to abort processing of this state
  # local script must set exit_status variable to nonzero.
  if [ $exit_status -ne 0 ]; then
    exit $exit_status
  fi
fi

if [ ! -z "$new_broadcast_address" ]
then
  new_broadcast_arg="broadcast $new_broadcast_address"
fi
if [ ! -z "$old_broadcast_address" ]
then
  old_broadcast_arg="broadcast $old_broadcast_address"
fi
if [ ! -z "$alias_broadcast_address" ]
then
  alias_broadcast_arg="broadcast $alias_broadcast_address"
fi
if [ ! -z "$new_subnet_mask" ]
then
  new_subnet_arg="netmask $new_subnet_mask"
fi
if [ ! -z "$old_subnet_mask" ]
then
  old_subnet_arg="netmask $old_subnet_mask"
fi
if [ ! -z "$alias_subnet_mask" ]
then
  alias_subnet_arg="netmask $alias_subnet_mask"
fi

case "$reason" in
MEDIUM)
	exit_with_hooks 0
	;;
PREINIT)
	if [ ! -z "$alias_ip_address" ]
        then
#	    Don't delete the alias interface! Add it!
# 	    ip addr del $alias_ip_address dev $interface
	    ip addr add $alias_ip_address/$alias_mask_bits \
					$alias_broadcast_arg dev $interface
  	fi
	if [ ! -z "$old_ip_address" ]
	then
	    ip addr del $old_ip_address dev $interface
	else
	    ip addr del 0 dev $interface
	fi
        ip addr add 0/32 broadcast 255.255.255.255 dev $interface

	ifconfig $interface up

  	# We need to give the kernel some time to get the interface up.
  	sleep 1

  	exit_with_hooks 0
	;;

ARPCHECK|ARPSEND)
  	exit_with_hooks 0
	;;

BOUND|RENEW|REBIND|REBOOT)
  if [ ! -z "$old_ip_address" -a ! -z "$alias_ip_address" -a \
	     "$alias_ip_address" != "$old_ip_address" ]
  then
    	# Possible new alias. Remove old alias.
	ip addr del $alias_ip_address dev $interface
  fi
  if [ ! -z "$old_ip_address" -a "$old_ip_address" != "$new_ip_address" ]
  then
    # IP address changed. Bringing down the interface will delete all routes,
    # and clear the ARP cache.
    ifconfig $interface inet down
  fi
  if [ -z "$old_ip_address" -o "$reason" = "BOUND" -o "$reason" = "REBOOT" ]
  then
	if [ ! -z "$new_ip_address" ]
	then
	    ip addr add $new_ip_address/$new_mask_bits \
					$new_broadcast_arg dev $interface
	fi
        # Add a network route to the computed network address.
        config_routers

  fi
  if [ "$new_ip_address" != "$alias_ip_address" -a ! -z "$alias_ip_address" ];
  then
	    ip addr add $alias_ip_address/$alias_mask_bits \
					$alias_broadcast_arg dev $interface
  fi
  update_resolv_conf
  exit_with_hooks 0
  ;;

EXPIRE|FAIL)

  if [ ! -z "$alias_ip_address" ]
  then
    # Turn off alias interface.
    ip addr del $alias_ip_address dev $interface
  fi
  if [ ! -z "$old_ip_address" ]
  then
    # Shut down interface, which will delete routes and clear arp cache.
    ifconfig $interface inet down
  fi
  if [ ! -z "$alias_ip_address" ]
  then
    ip addr add $alias_ip_address/$alias_mask_bits \
					$alias_broadcast_arg dev $interface
  fi
  exit_with_hooks 0
  ;;

TIMEOUT)
  if [ ! -z "$alias_ip_address" ]
  then
    ip addr del $alias_ip_address dev $interface
  fi
  ip addr add $new_ip_address/$new_mask_bits \
					$new_broadcast_arg dev $interface

  if [ "$new_ip_address" != "$alias_ip_address" -a ! -z "$alias_ip_address" ]
  then
	ip addr add $alias_ip_address/$alias_mask_bits \
					$alias_broadcast_arg dev $interface
  fi
  if [ ! -z "$new_routers" ]
  then  
      set $new_routers
      ping -q -c 1 -i 1 $1 && config_routers
  fi
  
  update_resolv_conf
  ;;

esac

exit_with_hooks $status

-----------------------------------------------------------------------
To unsubscribe from this list, visit http://www.isc.org/dhcp-lists.html
or send mail to dhcp-client-request@isc.org with the subject line of
'unsubscribe'.
-----------------------------------------------------------------------

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic