Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main > by-pkgid > d006fe78cb68bf6ab4454a7d936aea0f > files > 5

libdhcp-1.20-13.el5.x86_64.rpm

  -------------------------------------------------------------------------
  LIBDHCP : library programming interface to the ISC DHCP and DHPv6 clients

                             An Overview

    Copyright (C) 2006  Red Hat, Inc. All rights reserved.

    Red Hat Authors: Jason Vas Dias <jvdias@redhat.com>
                     David Cantrell <dcantrell@redhat.com>

  -------------------------------------------------------------------------

LIBDHCP enables programs to invoke the ISC dhclient (IPv4 DHCP) and DHCPv6
client (IPv6 DHCP) libraries, libdhcp4client and libdhcp6client, within one
process, and to use the lease objects returned to configure network interface
parameters.

The primary, tested, intended interface is as follows, though there are quite
a few other ways of using the code (by no means all of them bug free ! :-).

First, include the main interface header:

#include <libdhcp/dhcp_nic.h>

it will include all required headers from libdhcp.

Choose which IPv6/IPv4 DHCP policy you wish libdhcp to implement -
enum type "DHCP_Preference" in dhcp_nic.h :
    /* Don't do IPv4 DHCP */
    DHCPv4_DISABLE  = 1,

    /* Don't do IPv6 DHCP */
    DHCPv6_DISABLE  = 2,

    /* Configure IPv6 addresses / routes / DNS first */
    IPv6_PREFERENCE = 4,

    /* Don't configure DHCPv4 addresses */
    DHCPv4_DISABLE_ADDRESSES = 8,

    /* Don't configure DHCPv4 routes */
    DHCPv4_DISABLE_ROUTES    = 16,

    /* Don't configure DHCPv4 resolv.conf entries */
    DHCPv4_DISABLE_RESOLVER  = 32,

    /* Don't configure DHCPv6 address (ie. use radvd) */
    DHCPv6_DISABLE_ADDRESSES = 64,

    /* Don't configure DHCPv6 resolv.conf entries */
    DHCPv6_DISABLE_RESOLVER  = 128,

    /* Don't set hostname if DHCPv4 host-name option sent */
    DHCPv4_DISABLE_HOSTNAME_SET=256

You can specify the "capabilities" the DHCP clients are allowed to exercise,
with enum type "DHCP_Capability" from libdhcp.h:

 /* DHCP client "capabilities" */
    /* use / do not use persistent lease database files */
    DHCP_USE_LEASE_DATABASE   = 1,

    /* use / do not use pid file */
    DHCP_USE_PID_FILE         = 2,

 /*
  * DHCPv6 supports these capabilities in process, 
  * while the DHCPv4 client would fork and exec the dhclient-script to
  * implement them if these bits are set - otherwise, if no bits are set,
  * the callback is called and the script is not run.
  */
    /* configure interfaces UP/DOWN as required */
    DHCP_CONFIGURE_INTERFACES = 4,

    /* configure interface addresses as required */
    DHCP_CONFIGURE_ADDRESSES  = 8,

    /* configure routes as required */
    DHCP_CONFIGURE_ROUTES     =16,

    /* configure resolv.conf as required */
    DHCP_CONFIGURE_RESOLVER   =32,

    /* DHCPv6 only: */
    /* configure radvd.conf & restart radvd as required */
    DHCP_CONFIGURE_RADVD      =64,


Then, call the main dhcp interface function, 'do_dhcp' (from dhcp_nic.h) with
the values you chose:

extern 
DHCP_nic *do_dhcp
( 
    DHCP_Preference preference,
    char                  *eth_if_name,
    LIBDHCP_Capability     dhc_cap, 
    time_t                 timeout,    
    LIBDHCP_Error_Handler  error_handler,
    uint8_t                log_level,
    ... /* extra DHCPv4 dhclient arguments;
	 * last arg MUST be 0 .
	 */
);

The timeout is a hard timeout that each client has until it gives up.
The timeout should not be 0 at the moment, otherwise if for instance
DHCPv6 runs first, and no DHCPv6 servers are contactable, the process
will continue indefinitely, and DHCPv4 servers will not be tried. It
is intended to get each client running in a separate thread in the
next release, and then a timeout of 0 can be specified safely.

You can define an error handler to handle all debug / error / info
log messages emanating from the clients:
 int( *LIBDHCP_Error_Handler )
    ( struct libdhcp_control_s *ctl,
      int priority, /* ala syslog(3): LOG_EMERG=0 - LOG_DEBUG=7
                                      (+ LOG_FATAL=8 : finished -> 1)   */
      const char *fmt,
      va_list ap
    );

"log_level" in the dhcp_nic call sets the maximum level that will be logged.
Two standard error handlers are defined:
  libdhcp_stderr_logger  : writes log messages to stderr
  libdhcp_syslogger      : writes log messages to syslog
No logging is done if "error_handler" is 0 .

You can specify any normal dhclient command line arg in the va_list .

ie. a call that specifies that libdhcp should runs DHCPv4 and DHCPv4,
for interface named "eth0", with extra dhclient args to send the 
dhcp-client-identifier, vendor-class-identifier, and host-name would be:
    
    DHCP_nic *nic =
    do_dhcp
    ( 0,
      "eth0",
      0,
      10, /* each client has 10 seconds to get a lease */
      libdhcp_stderr_logger,
      LOG_INFO,
      "-V","i386-redhat-fc6",
      "-I", "1:00:0D:60:CF:98:E3",
      "-H", "mypc",
      0 /* !!! THE ESSENTIAL TRAILING 0 !!! */
    );
    

This call would then actually invoke the clients in the same process as the
caller (no forks / execs / system() calls involved)  and would return a
"Network Interface Configuration" ( NIC ) structure - well, actually two
NIC structures, one for each client, encapsulated in the "DHCP_nic" structure -
as yet, no interface configuration beyond setting the interface flags 
to (IFF_UP & IFF_RUNNING) would have been done.

( That is, of course, only if you have both the DHCPv6 IPv6 DHCP dhcp6s 
  server and the IPv4 DHCP ISC dhcpd server running on your network.
  An example working /etc/dhcp6s.conf for dhcp6s is:
  ---
  # /etc/dhcp6s.conf
  interface eth0 {
   link eth0 {
        range fec0::10 to fec0::19/64;
   };
  };
  ---
  - see 'man 5 dhcps.conf' and 'man 5 dhcpd.conf'.
).

The dhcp_nic structure can then be configured on the network interfaces with
the call:

   dhcp_nic_configure( nic );

If this returns 0, all configuration parameters have been successfully
applied.


libdhcp contains an interface to the 'libnl' (lib NETLINK) library,
( by Thomas Graf, http://people.suug.ch/~tgr/libnl/ ), in the 
"nic.[ch]" files, that implement its "Network Interface Configurator",
which enables the DHCP client lease parameters to be configured on the
network devices - it is also a full-featured static network configurator.

For example, you can use this function:
  
extern
NIC_Res_t 
nic_configure
(
    NLH_t          nh,
    NIC_t          nic,
    IPaddr_list_t  *addresses,
    IProute_list_t *routes,
    IPaddr_list_t  *dns_servers,
    char           *search_list,
    char           *host_name
);

to configure a list of addresses and routes on an interface ,
and to configure resolv.conf and set the host name.
Zero-valued pointer parameters are safely ignored.
For instance, the calls :

	NIC_t nic = nic_by_name("eth0");
	IPaddr_t 
	    a1 = nic_addr_from_text("172.16.80.1/22"),
	    a2 = nic_addr_from_text("192.168.2.1/16"),
	    a3 = nic_addr_from_text("2006:0:0:5::18/64"),
	    gw1= nic_addr_from_text("192.168.2.254"),
	    n2 = nic_addr_from_text("2006:0:0:6::/64"),
	    gw2= nic_addr_from_text("2006:0:0:5::100"),
	    ns1= nic_addr_from_text("192.168.2.200"),
	    ns2= nic_addr_from_text("2006:0:0:5::200");
	int sa_len;
        IProute_t
            r1 = nic_route_new
		 (  nh,
		    nic_get_index(nic),
          0,                        /* destination: 0 means "default" */ 
          32,                       /* destination prefix bits - 32 default */
		    nic_addr_sa(gw1,&sa_len), /* gateway */
		    -1,                       /* default scope: global */
	       -1,                       /* no priority: increase if more than one
                                       default! */
		    -1,                       /* table: default (local) */
	       -1,                       /*no iif*/
          0L,
          0                         /*no src*/		    
		  ),
	     r2 = nic_route_new
	          ( nh, nic_get_index(nic), 
	            nic_addr_sa(n2,&sa_len), 
               nic_addr_get_prefix(n2),
		         nic_addr_sa(gw2,&sa_len),
               -1,-1,-1,-1, 0L, 0
             );
	IPaddr_list_t 
	     al = nic_address_list_new(a1,a2,a3,0),
             nl = nic_address_list_new(ns2,ns1,0);
	IProute_list_t
	     rl = nic_route_list_new(r1,r2,0);
	nic_set_flags( nic, IFF_UP | IFF_RUNNING );
	nic_configure( nh, nic, al, rl, nl, "my.domain.com", "myhost");

Would configure the "myhost.my.domain.com" interface eth0 with the 
addresses 172.16.80.1/22, 192.168.2.1/16, and 2006:0:0:5::18/64,
the default gateway 192.168.2.254, the additional route
'2006:0:0:6::/64 via 2006:0:0:5::100', and DNS nameservers
192.168.2.200 and 2006:0:0:5::1, IFF all goes according to
plan (and you are running the program as root!).

The complete details of each DHCP lease are also encapsulated in the
DHCP_nic 'lease' field, including all the lease times - see 
'dhcp4_lease.h' and 'dhcp6_lease.h' for details.

DHCv6 does not return options of interest that are not handled by
the default configurer, and there is no support in DHCPv6 for
user defined options, as yet.

But ISC IPv4 DHCP returns MANY options that are not handled in libdhcp,
and supports user defined options, and libdhcp fully supports this also.

Having obtained a DHCPv4_lease in a DHCP_nic 'nic' as nic->dhcp4_lease,
you can define your own option handler:

void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg )
{
    switch ( option->unicode )
    { 
    case DHCP_UNIVERSE:
	switch ( option->code )
	case MY_OPTION_CODE:
	    struct my_option *opt = (void*)&(option->value);
	    ...
    }
}

and the dhcp4_lease code will guarantee that the option is correctly
laid out as a C structure according to the DHCP option format.

For instance, you could have in your server dhcpd.conf and client
dhclient.conf:
' 
  option space redhat;
  option redhat.install-server code 1 = domain-name;
  option redhat.kickstart code 2 = string;
  option redhat.install-iso code 3 = string;
  option redhat.routes code 4 = array of { ip-address, int8, ip-address,
                                           int8, int16, int8, int32 };
'

And in the dhcpd server's dhcpd.conf:
'
  class "vendor-classes" {
         match option vendor-class-identifier;
       }

  subclass "vendor-classes" "i386-redhat-fc6" {
	option redhat.install-server my.i386repo.server.com;
	option redhat.kickstart "i386-fc6.ks";
  }

  subclass "vendor-classes" "ia64-redhat-fc6" {
	option redhat.install-server my.ia64repo.server.com;
	option redhat.kickstart "ia64-fc6.ks";
  }
  
  option redhat.routes 1.2.3.4 2 4.3.2.1 1 512 2 0xfabdab,
	               8.4.2.1 6 1.4.2.8 4 768 1 0xdabfab;

  option dhcp.redhat-encapsulation code 128 = encapsulate redhat;
'
And the client must be configured to request these options
in dhclient.conf:
   
   request dhcp.redhat-encapsulation;

Then you can define an option handler to handle these options:

void dhcp4_nic_option_handler( DHCPv4_option *option, void *arg )
{
    switch ( option->unicode )
    { 
    case REDHAT_UNIVERSE:
	switch ( option->code )
	case REDHAT_ROUTES:
	    struct r_r
	    {   
	       u_int32_t ip1;
	       u_int8_t   b1;	
	       u_int32_t ip2;
	       u_int16_t  s1;
	       u_int8_t   b2;
	       i_int32_t  i1;
            } * r = (void*) &(option->value),
              * e = &(((r_r*) &(option->value))[option->n_elements]);
	    for(; r < e; r++)		            	
	       ...	
    }
}

and the 'r_r' structure members will be correctly laid out for access
by your C program.


CAVEATS:

As mentioned above, the DHCPv6 and DHCPv4 clients should be able to run
in separate threads - they currently cannot, though the build can enable 
threads with -DDHCP_USE_THREADS - this is for testing & development purposes
only.

Yes, there are memory leaks in this early beta release - I am currently
working to resolve them.

The next feature to be added will be a binary-compatible replacement for the
old 'pump' library, which is currently in development.

ABOVE ALL: USE AT YOUR OWN RISK ! the code is very new and is still in further
development and refinement. 

Please report any issues / suggestions / ideas via Red Hat Bugzilla or by email
to dcantrell@redhat.com.