[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2. dhcp-client

dhcp-client is a highly configurable and extendable DHCP client. Out of the box it has been built to start up and perform DHCP for a basic network setup with minimal fuss.

This chapter of the manual is divided into two parts. A quickstart guide written to get things up and going with minimal fuss and absolutely no file editing, and a more in depth reference manual to making use of the other DHCP client features.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.1 Quickstart

These instructions are for a quick no-hassle basic DHCP client setup. You don't really need to do much except know the following:

As the root user run the following command:

dhcp-client -i <interface>

Where you substitute <interface> with the name of your interface. Alternatively if the interface is down you can omit the `-i' and dhcp-client will automatically use the first ethernet interface which is not up.

You should be greeted by copyright text and the output of the client as it queries the DHCP server and configures your system. Once the client is done, it will fork into the background and continue to renew your lease as timers expire. In the event of the lease expiring the client will down your interface and cleanup any of the system configuration it had done before.

Although you can run the client in the foreground, if you do not, the client will send the rest of its messages to syslogd. Currently it logs to the daemon service [ FIXME: in the future the syslog service will be configurable ].


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2 Client Configuration

dhcp-client accepts a number of configuration directives. Some of these can be passed by the command line, and others through a configuration file.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.1 Command Line Options


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.2 The Configuration File

dhcp-client will look for two files for a configuration information. Both these files should be located in the system configuration directory. By default this is defined as `/usr/local/etc' You can change this definition at build time by specifying a different prefix to the configure script.

The first file that is checked for begins with the name of the interface the client is configuring. For example, if the name of our interface is "xl0" then the configuration file to be checked will be `/usr/local/etc/dhcp-agent/dhcp-client/xl0.conf'

If this file does not exist then the default configuration file is `/usr/local/etc/dhcp-agent/dhcp-client/default.conf'

This allows dhcp-client to accept configuration per interface, and use a default file without forcing the user to name interfaces in the actual configuration file. It is believed that configuration files are more portable this way and are not dependant on interface names.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.3 Layout of Configuration File.

The configuration file is made up of directives. Each directive can take up one line or fall on multiple lines . Each directive is terminated by a semicolon. Whitespace is ignored unless it is found in a quoted sting. Newlines are always ignored.

 
foobar = yada,
blah;

And:

 
foobar = yada, blah;

Are the same.

The parser also recognizes strings in two different formats. Quoted and unquoted.

 
"foobar"

Is parsed exactly the same as

 
foobar

However:

 
foo bar

Will parse as two different strings, so you should use:

 
"foo bar"

Quoting is useful for strings which contain whitespace. Newlines in quoted strings will result in an error unless preceeded by the '\' character. There should be no need to put newlines in quoted strings and expect them to be evaluated without the backslash (much like a Makefile). If you want newlines to be silently ignored you need to convince the author that they should be :-)

The '\' character can be used to escape double quotes too.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.2.4 Configuration Directives

DHCP Option Handling

The following directives affect DHCP option handling by the client

Client Configuration Directive: request

This directive instructs the client to request a set of dhcp options. The request directive accepts a list of strings which name the options to be requested:

 
request subnet-mask, ip-address-lease-time, renewal-time,
        rebinding-time, interface-mtu, domain-name, domain-name-servers;

Client Configuration Directive: require

This directive instructs the client to require a set of dhcp options to be passed before accepting the lease. This is useful to make sure you receive a minimum of desired options. If these options are never met the client will eventually timeout. If this directive is not set, the first DHCP lease offer will be accepted.

 
require subnet-mask, ip-address-lease-time, renewal-time,
        rebinding-time, interface-mtu;

Client Configuration Directive: configure

This directive instructs the client to only configure a set of dhcp options. This is useful if the server is passing you options you would rather not configure but implicitly claim to configure by accepting the lease. This directive does not define how options are configured. In order to define how configuration is done see "Writing Client Extensions," for more info.

 
configure subnet-mask, ip-address-lease-time, renewal-time,
          rebinding-time, interface-mtu, domain-name, domain-name-servers;

Client Configuration Directive: append

This directive instructs the client to append a value to a DHCP option prior to system configuration. If this option is a list of values, the value specified is merely appended. If this value is a string the value is appended to the string. If this option is a single datum then you should be using the override option instead.

 
append domain-name-servers = 127.0.0.1, 192.168.0.1;

Client Configuration Directive: prepend

This directive works the same as the append directive only the values are placed at the beginning of the list or string. You should not use prepend on single datum options and should use override instead.

 
prepend domain-name-servers = 127.0.0.1, 192.168.0.1;

Client Configuration Directive: override

This directive instructs the client to overwrite a DHCP option with a specified value prior to system configuration. This is useful to for clients that wish to use an alternate value for a DHCP option than the one passed by the DHCP server.

 
override domain-name = "example.com";

Variable Settings

Client Configuration Directive: set

This directive instructs the client to set a variable to a defined value.

 
set default-subnet-mask = 255.255.255.0;

Client Configuration Directive: enable

This directive instructs the client to set a boolean variable to a defined value. The boolean variable only accepts "yes" or "no" for values.

 
enable do-measure-router-latency = no;

Configurable Variables

dhcp-client accepts a number of variables to configure default values, values passed to the server, and control some of its behaviour.

Client Configuration Variable: hostname

This variable can be set to a string which is passed as the hostname DHCP option to the server. This allows servers to pass configuration based on a hostname passed by the client. It will also instruct the client to set the hostname to that variable. If you want to pass a hostname to the server you should set this variable and not use the "override" directive because the "override" directive only affects system configuration.

 
set hostname = "foo.example.com";

Client Configuration Variable: dhcp-discovery-retries

This variable can be set to an integer value which instructs the client on how many times it should retry a DHCP discover before it gives up.

 
set dhcp-discovery-retries = 3;

Client Configuration Variable: icmp-retries

This variable can be set to an integer value which instructs the client on how many times it should retry an ICMP operation. This affects operations such as router latency discovery, ICMP netmask discovery etc.

 
set icmp-retries = 3;

Client Configuration Variable: default-interface-mtu

This variable can be set to an integer value which instructs the client on what it's default interface MTU should be. This MTU is used during the initial DHCP discovery messages, and later used to configure the interface MTU if no MTU was specified by the DHCP server.

 
set default-interface-mtu = 1500;

Client Configuration Variable: default-subnet-mask

This variable can be set to a netmask value to specify a default subnet mask in case none is provided by the DHCP operation. Unlike the "override" directive this provides a fallback in case no subnet-mask is provided by the server.

 
set default-subnet-mask = 255.255.255.0;

Client Configuration Variable: do-measure-router-latency

This variable can be set to a boolean value to indicate whether or not the client should attempt to send ICMP ECHO requests to routers passed by the DHCP server and determine which is one has the least latency to become the default route. Disabling this variable stops this operation from taking place, and the first router is used as the default route. This is useful if the routers cannot be reached by ICMP ECHO requests.

 
enable do-measure-router-latency = yes;


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3 Writing Client Extensions

dhcp-client uses guile (GNU's Ubiquitous Intelligent Language for Extensions) to extend itself. Extensions can currently be written for handling DHCP options. The rest of this section assumes you are familiar with the Scheme programming language. If you are not familiar with the Scheme programming language then you cannot extend the client to configure options is not programmed to handle.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.1 The Sysconf Script

dhcp-client calls a sysconf script which is placed in the same directory as the configuration file. This script, like the configuration file, can be named either "default.sysconf" or after an interface name.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.2 Looking At The Sysconf Script

The default sysconf script which is shipped with dhcp-agent is made up of several lambda expressions which are placed inside closures. If you're not familiar with the concept of closures, refer to the guile documentation.

Under each closure is a configure/unconfigure lambda expression which are bound to top level symbols. These symbols are then placed in two hooks, one for the bound state, and one for the release state.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.3 The DNS Configuration: An Example

We'll walk through the DNS configuration (a very simple example) to see how it was written. After this example a more in-depth discussion follows. If you notice some details are skipped over, don't worry. It will become clear later.

 
(define configure-dns #f)
(define unconfigure-dns #f)

First we define two top level symbols to false. We'll later bind against these in the closure.

 
(let ((configured-domain-name #f)
       (configured-domain-name-servers #f)

We begin the closure by defining two variables which will be used to hold any configured domain name and domain name servers. For DNS configuration these aren't useful, but for other sysconf code keeping the values of configured data is useful when it comes time to unconfigure the system on a DHCP RELEASE.

 
      ; check to see if we really need to configure
       (do-configure 
        (lambda()
          (and (client-configure? client-control
          'dhcp-domain-name-servers) 
               (client-configure? client-control 'dhcp-domain-name)
               (defined? 'dhcp-domain-name-servers)
               (defined? 'dhcp-domain-name)))))

Here we define a lambda expression which will tell us whether or not we should be performing any configuration for dns. The expression will return true if the options "domain-name-servers" and "domain-name" have been passed to us by the DHCP server. Also it checks if the user has requested that we configure these options.

 
  ; configure dns options
  (set! configure-dns

        (lambda ()
          (if (do-configure)
              (let ((resolv-conf-file-port (open "/etc/resolv.conf" O_WRONLY 0644)))
                (client-info-message "configuring resolver")
                (map-in-order
                 (lambda (dns-server)
                   (simple-format resolv-conf-file-port "nameserver ~A\n" dns-server))  dhcp-domain-name-servers)
                (simple-format resolv-conf-file-port "search ~A\n" dhcp-domain-name)
                (close-port resolv-conf-file-port)

                                        ; now setup the options so we can use them again in unconfigure.
                (set! configured-domain-name dhcp-domain-name)
                (set! configured-domain-name-servers dhcp-domain-name-servers)))))

The "configure-dns" function will first check if "do-configure" returns true. It will then open "/etc/resolv.conf" and notify the user that the resolver is being configured. It then writes out the contents of the string list "dhcp-domain-name-servers" to the file prefixing each string with the keyword "nameserver." Finally the "search" keyword is written with the domain name.

After the configuration is complete, the values are stored in "configured-domain-name" and "configured-domain-name-servers." This allows us to remember the values in the event of unconfiguring the system.

 
                                        ; unconfigure dns options
  (set! unconfigure-dns
        (lambda()

         ; We shouldn't really be doing anything. Any name server
         ; is a good server :-)

          #t)))

As mentioned in the comment there's no need to do any unconfiguration. We'd rather have a resolv.conf than delete it. You can always modify this to delete the file, or insert a different set of values.

 
(add-hook! dhcp-bind-hook configure-dns)
(add-hook! dhcp-release-hook unconfigure-dns)

Finally the two routines are bound to the DHCP BIND and DHCP RELEASE hooks. It is important to add the option handlers in reverse order. You'll notice "configure-interface" is added last so that the interface is configured first.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.4 The DHCP BOUND and DHCP RELEASE hooks

Two hooks are defined at the top level by the client. "dhcp-bind-hook" and "dhcp-release-hook." When the client wants to configure itself it will call "dhcp-bind-hook" and when it releases its lease it will call "dhcp-release-hook."


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.5 How DHCP Options Are Passed To The Sysconf Script

When the DHCP BOUND hook is called, all the options are defined as top level symbols which refer to either a string, or a list of strings depending on whether the option is a single atom, or a list of atoms [ TODO: make list of handled options along with their types. ]

In order to check for the existance of an option, simple use "defined?" to check if the symbol is bound.

 
; check for the routers option

(defined? 'dhcp-routers)

This will return a boolean value of true of false depending on whether the DHCP option has been bound at the top level.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.6 Scheme Routines Provided By The Client

At the top level a "client-control" symbol is bound to a control object which is used in every invocation of routines provided by the client.

Client Sysconf Routine: client-configure? client-control option-symbol

Returns #t of #f depending on whether or not the user has explicitly stated that the dhcp option should be configured.

Client Sysconf Routine: client-interface-up client-control ip-address netmask mtu

Initializes the network interface the client is handling and assigns the requested ip-address, the netmask and mtu.

Client Sysconf Routine: client-set-default-route client-control ip-address

Sets the default route to the ip-address specified.

Client Sysconf Routine: client-remove-default-route client-control ip-address

Removes the default route to the ip-address specified.

Client Sysconf Routine: client-get-default-mtu client-control

Returns the default mtu specified by the user.

Client Sysconf Routine: client-get-default-subnet-mask client-control

Returns the default subnet-mask specified by the user.

Client Sysconf Routine: client-info-message string

Prints out the string using the client's info_message routine.

Client Sysconf Routine: client-error-message string

Prints out the string using the client's error_message routine.

Client Sysconf Routine: client-fatal-message string

Prints out the string using the client's fatal_message routine. This exits after passing the message to the user.

Client Sysconf Routine: client-shutdown client-control

Invokes the shutdown routine in the client and causes the client to exit as cleanly as possible, relinquishing any leases it has. Warning! This should not be called from within a release hook.

Client Sysconf Routine: client-discover-icmp-latency client-control address-list

Accepts a list of addresses address-list and performs ICMP ECHO latency tests to determine which host is responding fastest. A list of address/average-latency pairs is returned.

Client Sysconf Routine: client-do-discover-icmp-latency client-control

Returns #t if the user enabled "do-measure-router-latency" or #f if not.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.3.7 Why Not Just Use A Shell Script?

Traditionally the UNIX initialization process is programmed with simple shell scripts. This is fine because all the variables are passed from the local system (usually set by the administrator or vendor).

In the case of DHCP configuration data is passed from a server which ought to be handled as untrustworthy data unless you're willing to use it in a certain way.

For example, assuming you wish to configure your hostname according to the DHCP server, you will receive the hostname as a string and use that string for your hostname. You don't, though, want the hostname passed to be arbitrary shell code which is run inadvertently from your shell script.

Most DHCP clients in the wild have fixed this problem by quoting the DHCP options as they are passed to the shell. I still foresee this as problematic, and a security hazard.

Guile offers the Scheme programming language which is an incredibly small subset of Lisp. It's easy to pick up. The DHCP options are passed to the Scheme system configuration script as strings or lists of strings. These strings are harmless unless you are specifically asking the Scheme interpreter to evaluate them.

On the other hand most casual users just want basic networking up, and the ability to tweak certain options. The DHCP client already offers this to anyone, irregardless of their knowledge of Scheme.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

2.4 Advanced Client Use

[ TODO ]


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by users on July, 6 2003 using texi2html