2
0
mirror of https://gitlab.isc.org/isc-projects/dhcp synced 2025-08-31 14:25:41 +00:00

Move a lot of packet discard code into ack_lease(), after we've evaluated the statements associated with a packet. Use new-style option processing. No more explicit user/vendor class support. Revamp lease time processing. Get client identifier directly from host declaration.

This commit is contained in:
Ted Lemon
1998-06-25 03:56:24 +00:00
parent ece6ea338c
commit b1dd98c948

View File

@@ -42,7 +42,7 @@
#ifndef lint #ifndef lint
static char copyright[] = static char copyright[] =
"$Id: dhcp.c,v 1.63 1998/04/19 23:34:43 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; "$Id: dhcp.c,v 1.64 1998/06/25 03:56:24 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n";
#endif /* not lint */ #endif /* not lint */
#include "dhcpd.h" #include "dhcpd.h"
@@ -109,12 +109,6 @@ void dhcpdiscover (packet)
return; return;
} }
/* Make sure this packet satisfies the configured minimum
number of seconds. */
if (packet -> raw -> secs <
packet -> shared_network -> group -> min_secs)
return;
/* If we didn't find a lease, try to allocate one... */ /* If we didn't find a lease, try to allocate one... */
if (!lease) { if (!lease) {
lease = packet -> shared_network -> last_lease; lease = packet -> shared_network -> last_lease;
@@ -162,24 +156,7 @@ void dhcpdiscover (packet)
} }
} }
/* If this subnet won't boot unknown clients, ignore the ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
request. */
if (!lease -> host &&
!lease -> subnet -> group -> boot_unknown_clients) {
note ("Ignoring unknown client %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
} else if (lease -> host &&
!lease -> host -> group -> allow_booting) {
note ("Declining to boot client %s",
lease -> host -> name
? lease -> host -> name
: print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
} else
ack_lease (packet, lease, DHCPOFFER, cur_time + 120);
} }
void dhcprequest (packet) void dhcprequest (packet)
@@ -422,32 +399,29 @@ void nak_lease (packet, cip)
unsigned char nak = DHCPNAK; unsigned char nak = DHCPNAK;
struct packet outgoing; struct packet outgoing;
struct hardware hto; struct hardware hto;
int i;
struct tree_cache *options [256]; struct option_state options;
struct tree_cache dhcpnak_tree;
struct tree_cache dhcpmsg_tree;
memset (options, 0, sizeof options); memset (&options, 0, sizeof options);
memset (&outgoing, 0, sizeof outgoing); memset (&outgoing, 0, sizeof outgoing);
memset (&raw, 0, sizeof raw); memset (&raw, 0, sizeof raw);
outgoing.raw = &raw; outgoing.raw = &raw;
/* Set DHCP_MESSAGE_TYPE to DHCPNAK */ /* Set DHCP_MESSAGE_TYPE to DHCPNAK */
options [DHO_DHCP_MESSAGE_TYPE] = &dhcpnak_tree; i = DHO_DHCP_MESSAGE_TYPE;
options [DHO_DHCP_MESSAGE_TYPE] -> value = &nak; options.dhcp_options [i] =
options [DHO_DHCP_MESSAGE_TYPE] -> len = sizeof nak; option_cache (make_const_data (&nak, sizeof nak, 0, 0),
options [DHO_DHCP_MESSAGE_TYPE] -> buf_size = sizeof nak; dhcp_universe.options [i]);
options [DHO_DHCP_MESSAGE_TYPE] -> timeout = 0xFFFFFFFF;
options [DHO_DHCP_MESSAGE_TYPE] -> tree = (struct tree *)0;
/* Set DHCP_MESSAGE to whatever the message is */ /* Set DHCP_MESSAGE to whatever the message is */
options [DHO_DHCP_MESSAGE] = &dhcpmsg_tree; i = DHO_DHCP_MESSAGE;
options [DHO_DHCP_MESSAGE] -> value = (unsigned char *)dhcp_message; options.server_options [i] =
options [DHO_DHCP_MESSAGE] -> buf_size = option_cache (make_const_data (dhcp_message,
options [DHO_DHCP_MESSAGE] -> len = strlen (dhcp_message); strlen (dhcp_message),
options [DHO_DHCP_MESSAGE] -> timeout = 0xFFFFFFFF; 1, 0),
options [DHO_DHCP_MESSAGE] -> tree = (struct tree *)0; dhcp_universe.options [i]);
/* Do not use the client's requested parameter list. */ /* Do not use the client's requested parameter list. */
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].len = 0; packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].len = 0;
packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data = packet -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data =
@@ -455,8 +429,7 @@ void nak_lease (packet, cip)
/* Set up the option buffer... */ /* Set up the option buffer... */
outgoing.packet_length = outgoing.packet_length =
cons_options (packet, outgoing.raw, 0, cons_options (packet, outgoing.raw, 0, &options, 0, 0, 0);
options, packet -> agent_options, 0, 0, 0);
/* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/
raw.siaddr = packet -> interface -> primary_address; raw.siaddr = packet -> interface -> primary_address;
@@ -544,9 +517,11 @@ void ack_lease (packet, lease, offer, when)
struct lease_state *state; struct lease_state *state;
TIME lease_time; TIME lease_time;
TIME offered_lease_time; TIME offered_lease_time;
struct data_string d1;
TIME comp_lease_time;
struct class *vendor_class, *user_class;
int i; int i;
int val;
/* If we're already acking this lease, don't do it again. */ /* If we're already acking this lease, don't do it again. */
if (lease -> state) { if (lease -> state) {
@@ -554,44 +529,7 @@ void ack_lease (packet, lease, offer, when)
return; return;
} }
if (packet -> options [DHO_DHCP_CLASS_IDENTIFIER].len) { /* XXX Process class restrictions. */
vendor_class =
find_class (0,
(char *)packet ->
options [DHO_DHCP_CLASS_IDENTIFIER].data,
packet ->
options [DHO_DHCP_CLASS_IDENTIFIER].len);
} else {
vendor_class = (struct class *)0;
}
if (packet -> options [DHO_DHCP_USER_CLASS_ID].len) {
user_class =
find_class (1,
(char *)packet ->
options [DHO_DHCP_USER_CLASS_ID].data,
packet ->
options [DHO_DHCP_USER_CLASS_ID].len);
} else {
user_class = (struct class *)0;
}
/*
* If there is not a specific host entry, and either the
* vendor class or user class (if they exist) deny booting,
* then bug out.
*/
if (!lease -> host) {
if (vendor_class && !vendor_class -> group -> allow_booting) {
debug ("Booting denied by vendor class");
return;
}
if (user_class && !user_class -> group -> allow_booting) {
debug ("Booting denied by user class");
return;
}
}
/* Allocate a lease state structure... */ /* Allocate a lease state structure... */
state = new_lease_state ("ack_lease"); state = new_lease_state ("ack_lease");
@@ -624,24 +562,104 @@ void ack_lease (packet, lease, offer, when)
lease -> client_hostname = 0; lease -> client_hostname = 0;
} }
/* Choose a filename; first from the host_decl, if any, then from /* Process all of the executable statements associated with
the user class, then from the vendor class. */ this lease. */
if (lease -> host && lease -> host -> group -> filename) memset (&state -> options, 0, sizeof state -> options);
state -> filename = lease -> host -> group -> filename;
else if (user_class && user_class -> group -> filename) /* Steal the agent options from the packet. */
state -> filename = user_class -> group -> filename; if (packet -> agent_options) {
else if (vendor_class && vendor_class -> group -> filename) state -> options.agent_options = packet -> agent_options;
state -> filename = vendor_class -> group -> filename; packet -> agent_options = (struct agent_options *)0;
else state -> filename = (char *)0; }
/* Execute the subnet statements. */
execute_statements_in_scope (packet, &state -> options,
lease -> subnet -> group,
(struct group *)0);
/* Vendor and user classes are only supported for DHCP clients. */
if (state -> offer) {
/* XXX process class stuff here. */
}
/* If we have a host_decl structure, run the options associated
with its group. */
if (lease -> host)
execute_statements_in_scope (packet, &state -> options,
lease -> host -> group,
lease -> subnet -> group);
/* Make sure this packet satisfies the configured minimum
number of seconds. */
if (state -> options.server_options [SV_MIN_SECS]) {
d1 = evaluate_data_expression
(packet,
(state -> options.server_options
[SV_MIN_SECS] -> expression));
if (d1.len && packet -> raw -> secs < d1.data [0])
return;
}
/* Drop the request if it's not allowed for this client. */
if (!lease -> host &&
state -> options.server_options [SV_BOOT_UNKNOWN_CLIENTS]) {
d1 = evaluate_data_expression
(packet, (state -> options.server_options
[SV_BOOT_UNKNOWN_CLIENTS] -> expression));
if (d1.len && !d1.data [0]) {
note ("Ignoring unknown client %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
return;
}
}
/* Drop the request if it's not allowed for this client. */
if (!offer &&
state -> options.server_options [SV_ALLOW_BOOTP]) {
d1 = evaluate_data_expression
(packet, (state -> options.server_options
[SV_ALLOW_BOOTP] -> expression));
if (d1.len && !d1.data [0]) {
note ("Ignoring BOOTP client %s",
print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
return;
}
}
if (state -> options.server_options [SV_ALLOW_BOOTING]) {
d1 = evaluate_data_expression
(packet, (state -> options.server_options
[SV_ALLOW_BOOTING] -> expression));
if (d1.len && !d1.data [0]) {
note ("Declining to boot client %s",
lease -> host -> name
? lease -> host -> name
: print_hw_addr (packet -> raw -> htype,
packet -> raw -> hlen,
packet -> raw -> chaddr));
return;
}
}
/* Figure out the filename. */
if (state -> options.server_options [SV_FILENAME])
state -> filename =
(evaluate_data_expression
(packet,
(state -> options.
server_options [SV_FILENAME] -> expression)));
/* Choose a server name as above. */ /* Choose a server name as above. */
if (lease -> host && lease -> host -> group -> server_name) if (state -> options.server_options [SV_SERVER_NAME])
state -> server_name = lease -> host -> group -> server_name; state -> server_name =
else if (user_class && user_class -> group -> server_name) (evaluate_data_expression
state -> server_name = user_class -> group -> server_name; (packet,
else if (vendor_class && vendor_class -> group -> server_name) (state -> options.
state -> server_name = vendor_class -> group -> server_name; server_options [SV_SERVER_NAME] -> expression)));
else state -> server_name = (char *)0;
/* At this point, we have a lease that we can offer the client. /* At this point, we have a lease that we can offer the client.
Now we construct a lease structure that contains what we want, Now we construct a lease structure that contains what we want,
@@ -659,70 +677,83 @@ void ack_lease (packet, lease, offer, when)
/* Figure out how long a lease to assign. If this is a /* Figure out how long a lease to assign. If this is a
dynamic BOOTP lease, its duration must be infinite. */ dynamic BOOTP lease, its duration must be infinite. */
if (offer) { if (offer) {
if (packet -> options [DHO_DHCP_LEASE_TIME].len == 4) { if (packet -> options [DHO_DHCP_LEASE_TIME].len ==
sizeof (u_int32_t)) {
lease_time = getULong lease_time = getULong
(packet -> options [DHO_DHCP_LEASE_TIME].data); (packet -> options [DHO_DHCP_LEASE_TIME].data);
comp_lease_time = DEFAULT_MAX_LEASE_TIME;
/* Don't let the client ask for a longer lease than i = SV_MAX_LEASE_TIME;
is supported for this subnet or host. */ if (state ->
if (lease -> host && options.server_options [i]) {
lease -> host -> group -> max_lease_time) { d1 = evaluate_data_expression
if (lease_time > (packet,
lease -> host -> group -> max_lease_time) state -> options.
lease_time = (lease -> host -> server_options [i] -> expression);
group -> max_lease_time); if (d1.len == sizeof (u_int32_t))
} else { comp_lease_time = getULong (d1.data);
if (lease_time >
lease -> subnet -> group -> max_lease_time)
lease_time = (lease -> subnet ->
group -> max_lease_time);
} }
/* Enforce the maximum lease length. */
if (lease_time > comp_lease_time)
lease_time = comp_lease_time;
} else { } else {
if (lease -> host i = SV_DEFAULT_LEASE_TIME;
&& lease -> host -> group -> default_lease_time) lease_time = DEFAULT_DEFAULT_LEASE_TIME;
lease_time = (lease -> host -> if (state ->
group -> default_lease_time); options.server_options [i]) {
else d1 = evaluate_data_expression
lease_time = (lease -> subnet -> (packet,
group -> default_lease_time); state -> options.
server_options [i] -> expression);
if (d1.len == sizeof (u_int32_t))
lease_time = getULong (d1.data);
}
} }
/* Enforce a minimum lease time, if specified. */ i = SV_MIN_LEASE_TIME;
if (lease -> host) { comp_lease_time = DEFAULT_MIN_LEASE_TIME;
if (lease_time < if (state -> options.server_options [i]) {
lease -> host -> group -> min_lease_time) d1 = evaluate_data_expression
lease_time = (lease -> (packet,
host -> group -> min_lease_time); state -> options.
} else { server_options [i] -> expression);
if (lease_time < if (d1.len == sizeof (u_int32_t))
lease -> subnet -> group -> min_lease_time) comp_lease_time = getULong (d1.data);
lease_time = (lease -> subnet ->
group -> min_lease_time);
} }
if (lease_time < comp_lease_time)
lease_time = comp_lease_time;
state -> offered_expiry = cur_time + lease_time; state -> offered_expiry = cur_time + lease_time;
if (when) if (when)
lt.ends = when; lt.ends = when;
else else
lt.ends = state -> offered_expiry; lt.ends = state -> offered_expiry;
} else { } else {
if (lease -> host && lease_time = MAX_TIME - cur_time;
lease -> host -> group -> bootp_lease_length)
lt.ends = (cur_time + i = SV_BOOTP_LEASE_LENGTH;
lease -> host -> if (state -> options.server_options [i]) {
group -> bootp_lease_length); d1 = evaluate_data_expression
else if (lease -> subnet -> group -> bootp_lease_length) (packet,
lt.ends = (cur_time + state -> options.
lease -> subnet -> server_options [i] -> expression);
group -> bootp_lease_length); if (d1.len == sizeof (u_int32_t))
else if (lease -> host && lease_time = getULong (d1.data);
lease -> host -> group -> bootp_lease_cutoff) }
lt.ends = lease -> host -> group -> bootp_lease_cutoff;
else i = SV_BOOTP_LEASE_CUTOFF;
lt.ends = (lease -> subnet -> if (state -> options.server_options [i]) {
group -> bootp_lease_cutoff); d1 = evaluate_data_expression
state -> offered_expiry = lt.ends; (packet,
state -> options.
server_options [i] -> expression);
if (d1.len == sizeof (u_int32_t))
lease_time = getULong (d1.data) - cur_time;
}
lt.ends = state -> offered_expiry = cur_time + lease_time;
lt.flags = BOOTP_LEASE; lt.flags = BOOTP_LEASE;
} }
@@ -805,136 +836,58 @@ void ack_lease (packet, lease, offer, when)
options [DHO_DHCP_MAX_MESSAGE_SIZE].data); options [DHO_DHCP_MAX_MESSAGE_SIZE].data);
} }
/* Steal the agent options from the packet. */
if (packet -> agent_options) {
state -> agent_options = packet -> agent_options;
packet -> agent_options = (struct agent_options *)0;
}
/* Figure out what options to send to the client: */
/* Start out with the subnet options... */
memcpy (state -> options,
lease -> subnet -> group -> options,
sizeof state -> options);
/* Vendor and user classes are only supported for DHCP clients. */
if (state -> offer) {
/* If we have a vendor class, install those options,
superseding any subnet options. */
if (vendor_class) {
for (i = 0; i < 256; i++)
if (vendor_class -> group -> options [i])
state -> options [i] =
(vendor_class -> group ->
options [i]);
}
/* If we have a user class, install those options,
superseding any subnet and vendor class options. */
if (user_class) {
for (i = 0; i < 256; i++)
if (user_class -> group -> options [i])
state -> options [i] =
(user_class -> group ->
options [i]);
}
}
/* If we have a host_decl structure, install the associated
options, superseding anything that's in the way. */
if (lease -> host) {
for (i = 0; i < 256; i++)
if (lease -> host -> group -> options [i])
state -> options [i] = (lease -> host ->
group -> options [i]);
}
/* If we didn't get a hostname from an option somewhere, see if
we can get one from the lease. */
i = DHO_HOST_NAME;
if (!state -> options [i] && lease -> hostname) {
state -> options [i] = new_tree_cache ("hostname");
state -> options [i] -> flags = TC_TEMPORARY;
state -> options [i] -> value =
(unsigned char *)lease -> hostname;
state -> options [i] -> len = strlen (lease -> hostname);
state -> options [i] -> buf_size = state -> options [i] -> len;
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
}
/* Now, if appropriate, put in DHCP-specific options that /* Now, if appropriate, put in DHCP-specific options that
override those. */ override those. */
if (state -> offer) { if (state -> offer) {
i = DHO_DHCP_MESSAGE_TYPE; i = DHO_DHCP_MESSAGE_TYPE;
state -> options [i] = new_tree_cache ("message-type"); state -> options.dhcp_options [i] =
state -> options [i] -> flags = TC_TEMPORARY; option_cache (make_const_data (&state -> offer,
state -> options [i] -> value = &state -> offer; sizeof state -> offer,
state -> options [i] -> len = sizeof state -> offer; 0, 0),
state -> options [i] -> buf_size = sizeof state -> offer; dhcp_universe.options [i]);
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
i = DHO_DHCP_SERVER_IDENTIFIER; i = DHO_DHCP_SERVER_IDENTIFIER;
if (!state -> options [i]) { if (!state -> options.dhcp_options [i]) {
state -> options [i] = new_tree_cache ("server-id"); state -> options.dhcp_options [i] =
state -> options [i] -> value = (option_cache
(unsigned char *)&state -> (make_const_data
ip -> primary_address; ((unsigned char *)
state -> options [i] -> len = &state -> ip -> primary_address,
sizeof state -> ip -> primary_address; sizeof state -> ip -> primary_address,
state -> options [i] -> buf_size 0, 0),
= state -> options [i] -> len; dhcp_universe.options [i]));
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
} }
/* Sanity check the lease time. */ offered_lease_time =
if ((state -> offered_expiry - cur_time) < 15) state -> offered_expiry - cur_time;
offered_lease_time = (lease -> subnet ->
group -> default_lease_time);
else if (state -> offered_expiry - cur_time >
lease -> subnet -> group -> max_lease_time)
offered_lease_time = (lease -> subnet ->
group -> max_lease_time);
else
offered_lease_time =
state -> offered_expiry - cur_time;
putULong ((unsigned char *)&state -> expiry, putULong ((unsigned char *)&state -> expiry,
offered_lease_time); offered_lease_time);
i = DHO_DHCP_LEASE_TIME; i = DHO_DHCP_LEASE_TIME;
if (state -> options [i]) if (state -> options.dhcp_options [i])
warn ("dhcp-lease-time option for %s overridden.", warn ("dhcp-lease-time option for %s overridden.",
inet_ntoa (state -> ciaddr)); inet_ntoa (state -> ciaddr));
state -> options [i] = new_tree_cache ("lease-expiry"); state -> options.dhcp_options [i] =
state -> options [i] -> flags = TC_TEMPORARY; option_cache (make_const_data ((unsigned char *)
state -> options [i] -> value = &state -> expiry,
(unsigned char *)&state -> expiry; sizeof state -> expiry,
state -> options [i] -> len = sizeof state -> expiry; 0, 0),
state -> options [i] -> buf_size = sizeof state -> expiry; dhcp_universe.options [i]);
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
/* Renewal time is lease time * 0.5. */ /* Renewal time is lease time * 0.5. */
offered_lease_time /= 2; offered_lease_time /= 2;
putULong ((unsigned char *)&state -> renewal, putULong ((unsigned char *)&state -> renewal,
offered_lease_time); offered_lease_time);
i = DHO_DHCP_RENEWAL_TIME; i = DHO_DHCP_RENEWAL_TIME;
if (state -> options [i]) if (state -> options.dhcp_options [i])
warn ("dhcp-renewal-time option for %s overridden.", warn ("dhcp-renewal-time option for %s overridden.",
inet_ntoa (state -> ciaddr)); inet_ntoa (state -> ciaddr));
state -> options [i] = new_tree_cache ("renewal-time"); state -> options.dhcp_options [i] =
state -> options [i] -> flags = TC_TEMPORARY; option_cache (make_const_data ((unsigned char *)
state -> options [i] -> value = &state -> renewal,
(unsigned char *)&state -> renewal; sizeof state -> renewal,
state -> options [i] -> len = sizeof state -> renewal; 0, 0),
state -> options [i] -> buf_size = sizeof state -> renewal; dhcp_universe.options [i]);
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
/* Rebinding time is lease time * 0.875. */ /* Rebinding time is lease time * 0.875. */
offered_lease_time += (offered_lease_time / 2 offered_lease_time += (offered_lease_time / 2
@@ -942,87 +895,95 @@ void ack_lease (packet, lease, offer, when)
putULong ((unsigned char *)&state -> rebind, putULong ((unsigned char *)&state -> rebind,
offered_lease_time); offered_lease_time);
i = DHO_DHCP_REBINDING_TIME; i = DHO_DHCP_REBINDING_TIME;
if (state -> options [i]) if (state -> options.dhcp_options [i])
warn ("dhcp-rebinding-time option for %s overridden.", warn ("dhcp-rebinding-time option for %s overridden.",
inet_ntoa (state -> ciaddr)); inet_ntoa (state -> ciaddr));
state -> options [i] = new_tree_cache ("rebind-time"); state -> options.dhcp_options [i] =
state -> options [i] -> flags = TC_TEMPORARY; option_cache (make_const_data ((unsigned char *)
state -> options [i] -> value = &state -> rebind,
(unsigned char *)&state -> rebind; sizeof state -> rebind,
state -> options [i] -> len = sizeof state -> rebind; 0, 0),
state -> options [i] -> buf_size = sizeof state -> rebind; dhcp_universe.options [i]);
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
/* If we used the vendor class the client specified, we
have to return it. */
if (vendor_class) {
i = DHO_DHCP_CLASS_IDENTIFIER;
state -> options [i] =
new_tree_cache ("class-identifier");
state -> options [i] -> flags = TC_TEMPORARY;
state -> options [i] -> value =
(unsigned char *)vendor_class -> name;
state -> options [i] -> len =
strlen (vendor_class -> name);
state -> options [i] -> buf_size =
state -> options [i] -> len;
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
}
/* If we used the user class the client specified, we
have to return it. */
if (user_class) {
i = DHO_DHCP_USER_CLASS_ID;
state -> options [i] = new_tree_cache ("user-class");
state -> options [i] -> flags = TC_TEMPORARY;
state -> options [i] -> value =
(unsigned char *)user_class -> name;
state -> options [i] -> len =
strlen (user_class -> name);
state -> options [i] -> buf_size =
state -> options [i] -> len;
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0;
}
} }
/* Use the subnet mask from the subnet declaration if no other /* Use the subnet mask from the subnet declaration if no other
mask has been provided. */ mask has been provided. */
i = DHO_SUBNET_MASK; i = DHO_SUBNET_MASK;
if (!state -> options [i]) { if (!state -> options.dhcp_options [i]) {
state -> options [i] = new_tree_cache ("subnet-mask"); state -> options.dhcp_options [i] =
state -> options [i] -> flags = TC_TEMPORARY; (option_cache
state -> options [i] -> value = (make_const_data (lease -> subnet -> netmask.iabuf,
lease -> subnet -> netmask.iabuf; lease -> subnet -> netmask.len,
state -> options [i] -> len = lease -> subnet -> netmask.len; 0, 0),
state -> options [i] -> buf_size = dhcp_universe.options [i]));
lease -> subnet -> netmask.len; }
state -> options [i] -> timeout = 0xFFFFFFFF;
state -> options [i] -> tree = (struct tree *)0; /* Use the hostname from the host declaration if there is one
and no hostname has otherwise been provided, and if the
use-host-decl-name flag is set. */
i = DHO_HOST_NAME;
if (!state -> options.dhcp_options [i] &&
lease -> host && lease -> host -> name) {
d1 = evaluate_data_expression
(packet, (state -> options.server_options
[SV_USE_HOST_DECL_NAMES] -> expression));
if (d1.len && d1.data [0]) {
state -> options.dhcp_options [i] =
(option_cache
(make_const_data (lease -> host -> name,
strlen (lease ->
host -> name),
1, 0),
dhcp_universe.options [i]));
}
}
/* If we don't have a hostname yet, and we've been asked to do
a reverse lookup to find the hostname, do it. */
if (!state -> options.dhcp_options [i]
&& state -> options.server_options [SV_GET_LEASE_HOSTNAMES]) {
d1 = evaluate_data_expression
(packet, (state -> options.server_options
[SV_GET_LEASE_HOSTNAMES] -> expression));
if (d1.len && d1.data [0]) {
struct in_addr ia;
struct hostent *h;
memcpy (&ia, lease -> ip_addr.iabuf, 4);
h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET);
if (!h)
warn ("No hostname for %s", inet_ntoa (ia));
else {
state -> options.dhcp_options [i] =
option_cache
(make_const_data
(h -> h_name,
strlen (h -> h_name) + 1,
1, 1),
dhcp_universe.options [i]);
}
}
} }
/* If so directed, use the leased IP address as the router address. /* If so directed, use the leased IP address as the router address.
This supposedly makes Win95 machines ARP for all IP addresses, This supposedly makes Win95 machines ARP for all IP addresses,
so if the local router does proxy arp, you win. */ so if the local router does proxy arp, you win. */
if ((lease -> host &&
lease -> host -> group -> use_lease_addr_for_default_route) ||
(lease -> subnet -> group -> use_lease_addr_for_default_route)) {
i = DHO_ROUTERS;
if (state -> options [i] && i = SV_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE;
state -> options [i] -> flags & TC_TEMPORARY) if (state -> options.server_options [i]) {
free_tree_cache (state -> options [i], "dhcp_reply"); d1 = evaluate_data_expression
(packet,
state -> options [i] = new_tree_cache ("routers"); state -> options.server_options [i] -> expression);
state -> options [i] -> flags = TC_TEMPORARY; if (d1.len && d1.data) {
state -> options [i] -> value = i = DHO_ROUTERS;
lease -> ip_addr.iabuf;
state -> options [i] -> len = lease -> ip_addr.len; state -> options.dhcp_options [i] =
state -> options [i] -> buf_size = lease -> ip_addr.len; option_cache (make_const_data
state -> options [i] -> timeout = 0xFFFFFFFF; (lease -> ip_addr.iabuf,
state -> options [i] -> tree = (struct tree *)0; lease -> ip_addr.len, 0, 0),
dhcp_universe.options [i]);
}
} }
#ifdef DEBUG_PACKET #ifdef DEBUG_PACKET
@@ -1058,6 +1019,7 @@ void dhcp_reply (lease)
int nulltp, bootpp; int nulltp, bootpp;
struct agent_options *a, *na; struct agent_options *a, *na;
struct option_tag *ot, *not; struct option_tag *ot, *not;
struct data_string d1;
if (!state) if (!state)
error ("dhcp_reply was supplied lease with no state!"); error ("dhcp_reply was supplied lease with no state!");
@@ -1067,16 +1029,28 @@ void dhcp_reply (lease)
/* Copy in the filename if given; otherwise, flag the filename /* Copy in the filename if given; otherwise, flag the filename
buffer as available for options. */ buffer as available for options. */
if (state -> filename) if (state -> filename.len && state -> filename.data) {
strncpy (raw.file, state -> filename, sizeof raw.file); memcpy (raw.file,
else state -> filename.data,
state -> filename.len > sizeof raw.file
? sizeof raw.file : state -> filename.len);
if (sizeof raw.file > state -> filename.len)
memset (&raw.file [state -> filename.len], 0,
(sizeof raw.file) - state -> filename.len);
} else
bufs |= 1; bufs |= 1;
/* Copy in the server name if given; otherwise, flag the /* Copy in the server name if given; otherwise, flag the
server_name buffer as available for options. */ server_name buffer as available for options. */
if (state -> server_name) if (state -> server_name.len && state -> server_name.data) {
strncpy (raw.sname, state -> server_name, sizeof raw.sname); memcpy (raw.sname,
else state -> server_name.data,
state -> server_name.len > sizeof raw.sname
? sizeof raw.sname : state -> server_name.len);
if (sizeof raw.sname > state -> server_name.len)
memset (&raw.sname [state -> server_name.len], 0,
(sizeof raw.sname) - state -> server_name.len);
} else
bufs |= 2; /* XXX */ bufs |= 2; /* XXX */
memcpy (raw.chaddr, lease -> hardware_addr.haddr, sizeof raw.chaddr); memcpy (raw.chaddr, lease -> hardware_addr.haddr, sizeof raw.chaddr);
@@ -1099,20 +1073,23 @@ void dhcp_reply (lease)
/* Insert such options as will fit into the buffer. */ /* Insert such options as will fit into the buffer. */
packet_length = cons_options ((struct packet *)0, &raw, packet_length = cons_options ((struct packet *)0, &raw,
state -> max_message_size, state -> max_message_size,
state -> options, &state -> options,
state -> agent_options,
bufs, nulltp, bootpp); bufs, nulltp, bootpp);
/* Having done the cons_options(), we can release the tree_cache /* Having done the cons_options(), we can release the tree_cache
entries. */ entries. */
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
if (state -> options [i] && if (state -> options.dhcp_options [i])
state -> options [i] -> flags & TC_TEMPORARY) free_option_cache (state -> options.dhcp_options [i],
free_tree_cache (state -> options [i], "dhcp_reply"); "dhcp_reply");
if (state -> options.server_options [i])
free_option_cache (state -> options.dhcp_options [i],
"dhcp_reply");
} }
/* We can also release the agent options, if any... */ /* We can also release the agent options, if any... */
for (a = state -> agent_options; a; a = na) { for (a = state -> options.agent_options; a; a = na) {
na = a -> next; na = a -> next;
for (ot = a -> first; ot; ot = not) { for (ot = a -> first; ot; ot = not) {
not = ot -> next; not = ot -> next;
@@ -1124,17 +1101,16 @@ void dhcp_reply (lease)
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4); memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
/* Figure out the address of the next server. */ /* Figure out the address of the next server. */
if (lease -> host && lease -> host -> group -> next_server.len) raw.siaddr = state -> ip -> primary_address;
memcpy (&raw.siaddr, if (state -> options.server_options [SV_NEXT_SERVER]) {
lease -> host -> group -> next_server.iabuf, 4); d1 = evaluate_data_expression
else if (lease -> subnet -> group -> next_server.len) ((struct packet *)0,
memcpy (&raw.siaddr, (state -> options.
lease -> subnet -> group -> next_server.iabuf, 4); server_options [SV_NEXT_SERVER] -> expression));
else if (lease -> subnet -> interface_address.len) /* If there was more than one answer, take the first. */
memcpy (&raw.siaddr, if (d1.len >= 4 && d1.data)
lease -> subnet -> interface_address.iabuf, 4); memcpy (&raw.siaddr, d1.data, 4);
else }
raw.siaddr = state -> ip -> primary_address;
raw.giaddr = state -> giaddr; raw.giaddr = state -> giaddr;
@@ -1346,7 +1322,7 @@ struct lease *find_lease (packet, share, ours)
int i = DHO_DHCP_CLIENT_IDENTIFIER; int i = DHO_DHCP_CLIENT_IDENTIFIER;
/* If for some reason the client has more than one lease /* If for some reason the client has more than one lease
on the subnet that matches its uid, pick the one that on the subnet that matches its uid, pick the one that
it asked for. If we have a host */ it asked for. */
if (packet -> options [i].data && if (packet -> options [i].data &&
ip_lease -> uid_len == packet -> options [i].len && ip_lease -> uid_len == packet -> options [i].len &&
!memcmp (packet -> options [i].data, !memcmp (packet -> options [i].data,
@@ -1501,17 +1477,8 @@ struct lease *mockup_lease (packet, share, hp)
mock.next = mock.prev = (struct lease *)0; mock.next = mock.prev = (struct lease *)0;
mock.shared_network = mock.subnet -> shared_network; mock.shared_network = mock.subnet -> shared_network;
mock.host = hp; mock.host = hp;
mock.uid = hp -> client_identifier.data;
if (hp -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) { mock.uid_len = hp -> client_identifier.len;
mock.uid = hp -> group ->
options [DHO_DHCP_CLIENT_IDENTIFIER] -> value;
mock.uid_len = hp -> group ->
options [DHO_DHCP_CLIENT_IDENTIFIER] -> len;
} else {
mock.uid = (unsigned char *)0;
mock.uid_len = 0;
}
mock.hardware_addr = hp -> interface; mock.hardware_addr = hp -> interface;
mock.starts = mock.timestamp = mock.ends = MIN_TIME; mock.starts = mock.timestamp = mock.ends = MIN_TIME;
mock.flags = STATIC_LEASE; mock.flags = STATIC_LEASE;