mirror of
https://gitlab.isc.org/isc-projects/dhcp
synced 2025-08-31 14:25:41 +00:00
- Do not respond with NAK if ciaddr is set and imputed network doesn't
match, since ciaddr means client is unicasting using IP routing. - Support DHCPINFORM even on unknown networks. - Fix up some invocations of evaluate_option_cache that used post-scope-execution option state rather than packet option state as input for evaluations of options from post-scope-execution option state. - Add support for site-defined option spaces. - Compute boot file server prior to freeing options used in computing it. May fix a core dump that has been reported but that I haven't seen. - Make pool scope less specific than class scope. - Fix some invocations of execute_statements_in_scope that were incorrectly passing output options where they should have passed input options. - Enforce maximum lease length after applying default lease time. - Compute value of bootfile server IP address in ack_lease instead of dhcp_reply, so that expressions using contents of packet can work.
This commit is contained in:
176
server/dhcp.c
176
server/dhcp.c
@@ -22,7 +22,7 @@
|
||||
|
||||
#ifndef lint
|
||||
static char copyright[] =
|
||||
"$Id: dhcp.c,v 1.86 1999/04/12 22:18:58 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
||||
"$Id: dhcp.c,v 1.87 1999/04/23 23:17:52 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998, 1999 The Internet Software Consortium. All rights reserved.\n";
|
||||
#endif /* not lint */
|
||||
|
||||
#include "dhcpd.h"
|
||||
@@ -195,7 +195,7 @@ void dhcprequest (packet)
|
||||
if (!packet -> shared_network ||
|
||||
(packet -> raw -> ciaddr.s_addr &&
|
||||
packet -> raw -> giaddr.s_addr) ||
|
||||
oc) {
|
||||
(oc && !packet -> raw -> ciaddr.s_addr)) {
|
||||
|
||||
/* If we don't know where it came from but we do know
|
||||
where it claims to have come from, it didn't come
|
||||
@@ -365,7 +365,6 @@ void dhcpinform (packet)
|
||||
if (!subnet) {
|
||||
log_info ("%s: unknown subnet %s",
|
||||
msgbuf, inet_ntoa (packet -> raw -> giaddr));
|
||||
return;
|
||||
}
|
||||
|
||||
memset (&d1, 0, sizeof d1);
|
||||
@@ -375,15 +374,17 @@ void dhcpinform (packet)
|
||||
outgoing.raw = &raw;
|
||||
|
||||
/* Execute statements in scope starting with the subnet scope. */
|
||||
execute_statements_in_scope (packet, packet -> options, options,
|
||||
subnet -> group, (struct group *)0);
|
||||
if (subnet)
|
||||
execute_statements_in_scope (packet, packet -> options,
|
||||
options, subnet -> group,
|
||||
(struct group *)0);
|
||||
|
||||
/* Execute statements in the class scopes. */
|
||||
for (i = packet -> class_count; i > 0; i--) {
|
||||
execute_statements_in_scope
|
||||
(packet, packet -> options,
|
||||
options, packet -> classes [i - 1] -> group,
|
||||
subnet -> group);
|
||||
subnet ? subnet -> group : (struct group *)0);
|
||||
}
|
||||
|
||||
/* Figure out the filename. */
|
||||
@@ -398,8 +399,7 @@ void dhcpinform (packet)
|
||||
}
|
||||
|
||||
/* Choose a server name as above. */
|
||||
oc = lookup_option (&server_universe, options,
|
||||
SV_SERVER_NAME);
|
||||
oc = lookup_option (&server_universe, options, SV_SERVER_NAME);
|
||||
if (oc && evaluate_option_cache (&d1, packet, packet -> options, oc)) {
|
||||
i = d1.len;
|
||||
if (i > sizeof raw.sname)
|
||||
@@ -466,7 +466,7 @@ void dhcpinform (packet)
|
||||
/* Use the subnet mask from the subnet declaration if no other
|
||||
mask has been provided. */
|
||||
i = DHO_SUBNET_MASK;
|
||||
if (!lookup_option (&dhcp_universe, options, i)) {
|
||||
if (subnet && !lookup_option (&dhcp_universe, options, i)) {
|
||||
if (option_cache_allocate (&oc, "dhcpinform")) {
|
||||
if (make_const_data (&oc -> expression,
|
||||
subnet -> netmask.iabuf,
|
||||
@@ -485,8 +485,7 @@ void dhcpinform (packet)
|
||||
j = SV_VENDOR_OPTION_SPACE;
|
||||
if (!lookup_option (&dhcp_universe, options, i) &&
|
||||
(oc = lookup_option (&server_universe, options, j)) &&
|
||||
evaluate_option_cache (&d1,
|
||||
packet, options, oc)) {
|
||||
evaluate_option_cache (&d1, packet, packet -> options, oc)) {
|
||||
oc = (struct option_cache *)0;
|
||||
if (option_cache_allocate (&oc, "dhcpinform")) {
|
||||
if (make_encapsulation (&oc -> expression, &d1)) {
|
||||
@@ -498,6 +497,28 @@ void dhcpinform (packet)
|
||||
data_string_forget (&d1, "dhcpinform");
|
||||
}
|
||||
|
||||
/* If a site option space has been specified, use that for
|
||||
site option codes. */
|
||||
i = SV_SITE_OPTION_SPACE;
|
||||
if ((oc = lookup_option (&dhcp_universe, options, i)) &&
|
||||
evaluate_option_cache (&d1, packet, packet -> options, oc)) {
|
||||
struct universe *u;
|
||||
|
||||
u = ((struct universe *)
|
||||
hash_lookup (&universe_hash, d1.data, d1.len));
|
||||
if (!u) {
|
||||
log_error ("unknown option space %s.", d1.data);
|
||||
return;
|
||||
}
|
||||
|
||||
options -> site_universe = u -> index;
|
||||
options -> site_code_min = 128; /* XXX */
|
||||
data_string_forget (&d1, "dhcpinform");
|
||||
} else {
|
||||
options -> site_universe = dhcp_universe.index;
|
||||
options -> site_code_min = 0; /* Trust me, it works. */
|
||||
}
|
||||
|
||||
/* If the client has provided a list of options that it wishes
|
||||
returned, use it to prioritize. Otherwise, prioritize
|
||||
based on the default priority list. */
|
||||
@@ -517,6 +538,20 @@ void dhcpinform (packet)
|
||||
|
||||
log_info ("%s", msgbuf);
|
||||
|
||||
/* Figure out the address of the boot file server. */
|
||||
raw.siaddr = from;
|
||||
if ((oc =
|
||||
lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
|
||||
if (evaluate_option_cache (&d1, packet,
|
||||
packet -> options, oc)) {
|
||||
/* If there was more than one answer,
|
||||
take the first. */
|
||||
if (d1.len >= 4 && d1.data)
|
||||
memcpy (&raw.siaddr, d1.data, 4);
|
||||
data_string_forget (&d1, "dhcpinform");
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the option buffer... */
|
||||
outgoing.packet_length =
|
||||
cons_options (packet, outgoing.raw, 0, options,
|
||||
@@ -529,20 +564,6 @@ void dhcpinform (packet)
|
||||
outgoing.packet_length = BOOTP_MIN_LEN;
|
||||
|
||||
|
||||
/* Figure out the address of the next server. */
|
||||
raw.siaddr = from;
|
||||
if ((oc =
|
||||
lookup_option (&server_universe, options, SV_NEXT_SERVER))) {
|
||||
if (evaluate_option_cache (&d1,
|
||||
packet, packet -> options, oc)) {
|
||||
/* If there was more than one answer,
|
||||
take the first. */
|
||||
if (d1.len >= 4 && d1.data)
|
||||
memcpy (&raw.siaddr, d1.data, 4);
|
||||
data_string_forget (&d1, "dhcpinform");
|
||||
}
|
||||
}
|
||||
|
||||
raw.giaddr = packet -> raw -> giaddr;
|
||||
memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr);
|
||||
raw.hlen = packet -> raw -> hlen;
|
||||
@@ -787,17 +808,24 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
(struct agent_options *)0;
|
||||
}
|
||||
|
||||
/* Execute statements in scope starting with the pool group. */
|
||||
execute_statements_in_scope (packet, state -> options,
|
||||
/* Execute statements in scope starting with the subnet scope. */
|
||||
execute_statements_in_scope (packet, packet -> options,
|
||||
state -> options,
|
||||
lease -> subnet -> group,
|
||||
(struct group *)0);
|
||||
|
||||
/* Vendor and user classes are only supported for DHCP clients. */
|
||||
/* If the lease is from a pool, run the pool scope. */
|
||||
if (lease -> pool)
|
||||
execute_statements_in_scope (packet, packet -> options,
|
||||
state -> options,
|
||||
lease -> pool -> group,
|
||||
lease -> subnet -> group);
|
||||
|
||||
/* Execute statements from class scopes. */
|
||||
if (offer) {
|
||||
for (i = packet -> class_count; i > 0; i--) {
|
||||
execute_statements_in_scope
|
||||
(packet, state -> options,
|
||||
(packet, packet -> options,
|
||||
state -> options,
|
||||
packet -> classes [i - 1] -> group,
|
||||
(lease -> pool
|
||||
@@ -806,17 +834,10 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
}
|
||||
}
|
||||
|
||||
/* If the lease is from a pool, run the pool scope. */
|
||||
if (lease -> pool)
|
||||
execute_statements_in_scope (packet, state -> options,
|
||||
state -> options,
|
||||
lease -> pool -> group,
|
||||
lease -> subnet -> group);
|
||||
|
||||
/* If we have a host_decl structure, run the options associated
|
||||
with its group. */
|
||||
if (lease -> host)
|
||||
execute_statements_in_scope (packet, state -> options,
|
||||
execute_statements_in_scope (packet, packet -> options,
|
||||
state -> options,
|
||||
lease -> host -> group,
|
||||
(lease -> pool
|
||||
@@ -1016,16 +1037,15 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
data_string_forget (&d1, "ack_lease");
|
||||
}
|
||||
}
|
||||
|
||||
/* Enforce the maximum lease length. */
|
||||
if (lease_time < 0 || /* XXX */
|
||||
lease_time > max_lease_time)
|
||||
lease_time = max_lease_time;
|
||||
|
||||
} else {
|
||||
lease_time = default_lease_time;
|
||||
}
|
||||
|
||||
/* Enforce the maximum lease length. */
|
||||
if (lease_time < 0 || /* XXX */
|
||||
lease_time > max_lease_time)
|
||||
lease_time = max_lease_time;
|
||||
|
||||
min_lease_time = DEFAULT_MIN_LEASE_TIME;
|
||||
if ((oc = lookup_option (&server_universe, state -> options,
|
||||
SV_MIN_LEASE_TIME))) {
|
||||
@@ -1137,7 +1157,7 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
/* Remember the interface on which the packet arrived. */
|
||||
state -> ip = packet -> interface;
|
||||
|
||||
/* Set a flag if this client is a lame Microsoft client that NUL
|
||||
/* Set a flag if this client is a broken client that NUL
|
||||
terminates string options and expects us to do likewise. */
|
||||
lease -> flags &= ~MS_NULL_TERMINATION;
|
||||
if ((oc = lookup_option (&dhcp_universe, packet -> options,
|
||||
@@ -1284,6 +1304,27 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
}
|
||||
option_cache_dereference (&oc, "ack_lease");
|
||||
}
|
||||
} else {
|
||||
state -> from.len =
|
||||
sizeof state -> ip -> primary_address;
|
||||
memcpy (state -> from.iabuf,
|
||||
&state -> ip -> primary_address,
|
||||
state -> from.len);
|
||||
}
|
||||
|
||||
/* Figure out the address of the boot file server. */
|
||||
memcpy (&state -> siaddr, state -> from.iabuf, sizeof state -> siaddr);
|
||||
if ((oc =
|
||||
lookup_option (&server_universe,
|
||||
state -> options, SV_NEXT_SERVER))) {
|
||||
if (evaluate_option_cache (&d1, packet,
|
||||
packet -> options, oc)) {
|
||||
/* If there was more than one answer,
|
||||
take the first. */
|
||||
if (d1.len >= 4 && d1.data)
|
||||
memcpy (&raw.siaddr, d1.data, 4);
|
||||
data_string_forget (&d1, "ack_lease");
|
||||
}
|
||||
}
|
||||
|
||||
/* Use the subnet mask from the subnet declaration if no other
|
||||
@@ -1411,6 +1452,28 @@ void ack_lease (packet, lease, offer, when, msg)
|
||||
data_string_forget (&d1, "ack_lease");
|
||||
}
|
||||
|
||||
/* If a site option space has been specified, use that for
|
||||
site option codes. */
|
||||
i = SV_SITE_OPTION_SPACE;
|
||||
if ((oc = lookup_option (&dhcp_universe, state -> options, i)) &&
|
||||
evaluate_option_cache (&d1, packet, state -> options, oc)) {
|
||||
struct universe *u;
|
||||
|
||||
u = ((struct universe *)
|
||||
hash_lookup (&universe_hash, d1.data, d1.len));
|
||||
if (!u) {
|
||||
log_error ("unknown option space %s.", d1.data);
|
||||
return;
|
||||
}
|
||||
|
||||
state -> options -> site_universe = u -> index;
|
||||
state -> options -> site_code_min = 128; /* XXX */
|
||||
data_string_forget (&d1, "ack_lease");
|
||||
} else {
|
||||
state -> options -> site_code_min = 0;
|
||||
state -> options -> site_universe = dhcp_universe.index;
|
||||
}
|
||||
|
||||
/* If the client has provided a list of options that it wishes
|
||||
returned, use it to prioritize. Otherwise, prioritize
|
||||
based on the default priority list. */
|
||||
@@ -1522,27 +1585,7 @@ void dhcp_reply (lease)
|
||||
|
||||
memcpy (&raw.ciaddr, &state -> ciaddr, sizeof raw.ciaddr);
|
||||
memcpy (&raw.yiaddr, lease -> ip_addr.iabuf, 4);
|
||||
|
||||
/* Figure out the address of the next server. */
|
||||
raw.siaddr = state -> ip -> primary_address;
|
||||
if ((oc =
|
||||
lookup_option (&server_universe,
|
||||
state -> options, SV_NEXT_SERVER))) {
|
||||
if (evaluate_option_cache (&d1, (struct packet *)0,
|
||||
(struct option_state *)0, oc)) {
|
||||
/* If there was more than one answer,
|
||||
take the first. */
|
||||
if (d1.len >= 4 && d1.data)
|
||||
memcpy (&raw.siaddr, d1.data, 4);
|
||||
data_string_forget (&d1, "dhcp_reply");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free all of the entries in the option_state structure
|
||||
* now that we're done with them.
|
||||
*/
|
||||
|
||||
raw.siaddr = state -> siaddr;
|
||||
raw.giaddr = state -> giaddr;
|
||||
|
||||
raw.xid = state -> xid;
|
||||
@@ -1643,6 +1686,9 @@ void dhcp_reply (lease)
|
||||
(struct packet *)0, &raw, packet_length,
|
||||
from, &to, &hto);
|
||||
|
||||
/* Free all of the entries in the option_state structure
|
||||
now that we're done with them. */
|
||||
|
||||
data_string_forget (&state -> parameter_request_list,
|
||||
"dhcp_reply");
|
||||
free_lease_state (state, "dhcp_reply");
|
||||
|
Reference in New Issue
Block a user