summaryrefslogtreecommitdiff
path: root/server/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/dhcp.c')
-rw-r--r--server/dhcp.c107
1 files changed, 55 insertions, 52 deletions
diff --git a/server/dhcp.c b/server/dhcp.c
index 35648561..21fadf57 100644
--- a/server/dhcp.c
+++ b/server/dhcp.c
@@ -34,7 +34,7 @@
#ifndef lint
static char copyright[] =
-"$Id: dhcp.c,v 1.192.2.66 2007/03/27 03:49:20 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
+"$Id: dhcp.c,v 1.192.2.67 2007/04/20 15:27:36 dhankins Exp $ Copyright (c) 2004-2007 Internet Systems Consortium. All rights reserved.\n";
#endif /* not lint */
#include "dhcpd.h"
@@ -98,38 +98,31 @@ void dhcp (packet)
}
/* There is a problem with the relay agent information option,
- which is that in order for a normal relay agent to append
- this option, the relay agent has to have been involved in
- getting the packet from the client to the server. Note
- that this is the software entity known as the relay agent,
- _not_ the hardware entity known as a router in which the
- relay agent may be running, so the fact that a router has
- forwarded a packet does not mean that the relay agent in
- the router was involved.
-
- So when the client is in INIT or INIT-REBOOT or REBINDING
- state, the relay agent gets to tack on its options, but
- when it's not, the relay agent doesn't get to do this,
- which means that any decisions the DHCP server may make
- based on the agent options will be made incorrectly.
-
- We work around this in the following way: if this is a
- DHCPREQUEST and doesn't have relay agent information
- options, we see if there's an existing lease for this IP
- address and this client that _does_ have stashed agent
- options. If so, then we tack those options onto the
- packet as if they came from the client. Later on, when we
- are deciding whether to steal the agent options from the
- packet, if the agent options stashed on the lease are the
- same as those stashed on the packet, we don't steal them -
- this ensures that the client never receives its agent
- options. */
-
- if (packet -> packet_type == DHCPREQUEST &&
- packet -> raw -> ciaddr.s_addr &&
- !packet -> raw -> giaddr.s_addr &&
- (packet -> options -> universe_count < agent_universe.index ||
- !packet -> options -> universes [agent_universe.index]))
+ * which is that in order for a normal relay agent to append
+ * this option, the relay agent has to have been involved in
+ * getting the packet from the client to the server. Note
+ * that this is the software entity known as the relay agent,
+ * _not_ the hardware entity known as a router in which the
+ * relay agent may be running, so the fact that a router has
+ * forwarded a packet does not mean that the relay agent in
+ * the router was involved.
+ *
+ * So when the client broadcasts (DHCPDISCOVER, or giaddr is set),
+ * we can be sure that there are either agent options in the
+ * packet, or there aren't supposed to be. When the giaddr is not
+ * set, it's still possible that the client is on a directly
+ * attached subnet, and agent options are being appended by an l2
+ * device that has no address, and so sets no giaddr.
+ *
+ * But in either case it's possible that the packets we receive
+ * from the client in RENEW state may not include the agent options,
+ * so if they are not in the packet we must "pretend" the last values
+ * we observed were provided.
+ */
+ if (packet->packet_type == DHCPREQUEST &&
+ packet->raw->ciaddr.s_addr && !packet->raw->giaddr.s_addr &&
+ (packet->options->universe_count <= agent_universe.index ||
+ packet->options->universes[agent_universe.index] == NULL))
{
struct iaddr cip;
@@ -185,6 +178,12 @@ void dhcp (packet)
&(packet -> options -> universes
[agent_universe.index]),
lease -> agent_options, MDL);
+
+ if (packet->options->universe_count <= agent_universe.index)
+ packet->options->universe_count =
+ agent_universe.index + 1;
+
+ packet->agent_options_stashed = ISC_TRUE;
}
nolease:
@@ -1555,20 +1554,28 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
* on the lease. We do not check giaddr to detect the presence of
* a relay, as this excludes "l2" relay agents which have no giaddr
* to set.
+ *
+ * XXX: If the user configures options for the relay agent information
+ * (state->options->universes[agent_universe.index] is not NULL),
+ * we're still required to duplicate other values provided by the
+ * relay agent. So we need to merge the old values not configured
+ * by the user into the new state, not just give up.
*/
- if (packet->options->universe_count > agent_universe.index &&
- packet->options->universes [agent_universe.index] &&
- (state -> options -> universe_count <= agent_universe.index ||
- !state -> options -> universes [agent_universe.index]) &&
- lease -> agent_options !=
- ((struct option_chain_head *)
- packet -> options -> universes [agent_universe.index])) {
+ if (!packet->agent_options_stashed &&
+ packet->options->universe_count > agent_universe.index &&
+ packet->options->universes[agent_universe.index] != NULL &&
+ (state->options->universe_count <= agent_universe.index ||
+ state->options->universes[agent_universe.index] == NULL)) {
option_chain_head_reference
((struct option_chain_head **)
&(state -> options -> universes [agent_universe.index]),
(struct option_chain_head *)
packet -> options -> universes [agent_universe.index],
MDL);
+
+ if (state->options->universe_count <= agent_universe.index)
+ state->options->universe_count =
+ agent_universe.index + 1;
}
/* If we are offering a lease that is still currently valid, preserve
@@ -2204,19 +2211,15 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp)
option_chain_head_reference (&lt -> agent_options,
lease -> agent_options, MDL);
- /* If we got relay agent information options, and the packet really
- * looks like it came through a relay agent, and if this feature is
- * not disabled, save the relay agent information options that came
- * in with the packet, so that we can use them at renewal time when
- * the packet won't have gone through a relay agent. We do not
- * check giaddr to detect the presence of a relay, as this excludes
- * "l2" relay agents which have no giaddr to set.
+ /* If we got relay agent information options from the packet, then
+ * cache them for renewal in case the relay agent can't supply them
+ * when the client unicasts. The options may be from an addressed
+ * "l3" relay, or from an unaddressed "l2" relay which does not set
+ * giaddr.
*/
- if (packet->options->universe_count > agent_universe.index &&
- packet->options->universes [agent_universe.index] &&
- (state -> options -> universe_count <= agent_universe.index ||
- state -> options -> universes [agent_universe.index] ==
- packet -> options -> universes [agent_universe.index])) {
+ if (!packet->agent_options_stashed &&
+ packet->options->universe_count > agent_universe.index &&
+ packet->options->universes[agent_universe.index] != NULL) {
oc = lookup_option (&server_universe, state -> options,
SV_STASH_AGENT_OPTIONS);
if (!oc ||