Options in ISC's DHCP
Ted Lemon
Ted.Lemon at nominum.com
Wed Feb 19 00:11:01 UTC 2003
> Would you be willing to provide a brief overview of how options are
> handled by the ISC DHCP implementation? Any pointers would be greatly
> appreciated!
>
> Our current theory is that options are being stored within the universe
> structure's option field. However, we do not see where the formats for
> these options are defined.
The formats are defined in tables.c and stables.c, and you can also
define them in the configuration language. The format information is
stored in the universe structure. Option formats are used for
parsing options and for formatting options in order to print them or
store them in the lease database.
When a packet from a DHCP client comes in, and when a packet is
generated to send to the client, the options received or options to be
sent are stored in an option_state structure. The option state
structure for a packet being sent also contains configuration options -
this is the DHCP option space.
The option_state structure contains an array of sets of options, one
for each option space (a.k.a. universe). The values of individual
options are stored in option_cache structures. Option cache
structures can contain option data either as a data_string or as an
evaluation tree. Sometimes you'll see both a data string and an eval
tree - this means that the option has already been evaluated. For
incoming options, there is never anything but a data_string, because
the incoming options came in as binary data.
Option sets are either hash tables or a linked lists, depending on the
kind of option space. This is all handled automatically through
function pointers in the universe structure, so you normally just have
to call the appropriate function - e.g., lookup_option, save_option,
etc.
Option values from the configuration file are parsed into executable
statement structures. The usual statement type is option_statement,
which sets the value of the specified option to the specified value.
The option is identified by name, using the option space name, if any,
and the value of the option is represented as an evaluation tree.
Option values are associated with particular scopes using the group
structure. Each group contains a linked list of configuration file
statements. You'll see group structures hanging off of things like
subnets, shared networks, host declarations and the like.
When a message arrives from the client, the DHCP server unpacks it as
described above, and then assigns the client an IP address (best case
scenario, of course :'). This IP address then determines the subnet
and shared network to which the client is assigned. Other information
in the client's request may result in the message being associated with
a host declaration and/or a class declaration as well.
Once the shared network, subnet, host declaration (if any) and class of
the client have been determined, the server executes the statements
referred to by the group structure associated with each of these data
structures. It first executes the statements in the host declaration,
if any, then the statements in the class, if any, then the statements
in the subnet, then the statements in the shared net, and finally the
statements in the global scope - root_group.
When the statements are executed, I think in ack_lease() (look for
execute_statements_in_scope()), it passes in a option_state structure
into which the new options will be stored, and another option state
structure containing the options the clients sent, and also the
incoming packet and a bunch of other things, so that the configuration
language can use all of that stuff in generating the outgoing options.
When all the in-scope groups have been executed, you have an
option_state structure containing all the options that the server
*might* want to send, as well as the complete set of configuration
options that are appropriate for the scope. ack_lease() then stuffs a
bunch of other options into the structure - things like lease times,
message type, that sort of thing. It also checks the value of
configuration options, and in some cases the value of options the
client has sent - e.g., whether a parameter request list has been sent,
and what's in it. You can see dozens of examples of how this works in
the ack_lease() function.
Finally, ack_lease() calls the cons_options() function, which runs down
the parameter request list, if one was sent, and sends all the options
in it, or if no parameter list was sent, it just fakes one up out of
the list of all the options that are available to send. It packs all
the options into the packet, and you'll see there's some special code
in there to make sure the relay agent information option gets packed
last. You should try to understand what ack_lease() and
cons_options() do - this will get you a good part of the way to
understanding how to stuff in an authentication option into the packet.
What I would suggest you do is just stuff a zero-value authentication
option of the right size into the outgoing option_state structure, and
then have cons_options record the position in the packet of the option
state structure (you can record it on the packet structure that
contains the raw packet and associated data). Then when the packet's
been generated, compute the signature and stuff it into the packet
structure, and then you can send the packet out on the wire to fend for
itself.
More information about the dhcp-hackers
mailing list