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