Commit e3ada096 authored by Marcin Siodelski's avatar Marcin Siodelski

[3390] Implemented DHCPINFORM message processing by the server.

parent 852fb7c1
......@@ -299,7 +299,7 @@ Dhcpv4Srv::run() {
break;
case DHCPINFORM:
processInform(query);
rsp = processInform(query);
break;
default:
......@@ -1133,8 +1133,41 @@ Dhcpv4Srv::adjustRemoteAddr(const Pkt4Ptr& question, const Pkt4Ptr& response) {
static const IOAddress zero_addr("0.0.0.0");
static const IOAddress bcast_addr("255.255.255.255");
// The DHCPINFORM is slightly different than other messages in a sense
// that the server should always unicast the response to the ciaddr.
// It appears however that some clients don't set the ciaddr. We still
// want to provision these clients and we do what we can't to send the
// packet to the address where client can receive it.
if (question->getType() == DHCPINFORM) {
// If client adheres to RFC2131 it will set the ciaddr and in this
// case we always unicast our response to this address.
if (question->getCiaddr() != zero_addr) {
response->setRemoteAddr(question->getCiaddr());
// If we received DHCPINFOM via relay and the ciaddr is not set we
// will try to send the response via relay. The caveat is that the
// relay will not have any idea where to forward the packet because
// the yiaddr is likely not set. So, the broadcast flag is set so
// as the response may be broadcast.
} else if (question->isRelayed()) {
response->setRemoteAddr(question->getGiaddr());
response->setFlags(response->getFlags() | BOOTP_BROADCAST);
// If there is no ciaddr and no giaddr the only thing we can do is
// to use the source address of the packet.
} else {
response->setRemoteAddr(question->getRemoteAddr());
}
// Remote addres is now set so return.
return;
}
// If received relayed message, server responds to the relay address.
if (question->isRelayed()) {
if ((question->getType() == DHCPINFORM) &&
(question->getCiaddr() == zero_addr)) {
response->setFlags(BOOTP_BROADCAST);
}
response->setRemoteAddr(question->getGiaddr());
// If giaddr is 0 but client set ciaddr, server should unicast the
......@@ -1385,9 +1418,26 @@ Dhcpv4Srv::processDecline(Pkt4Ptr& /* decline */) {
Pkt4Ptr
Dhcpv4Srv::processInform(Pkt4Ptr& inform) {
/// @todo Implement this for real. (also see ticket #3116)
return (inform);
Pkt4Ptr ack = Pkt4Ptr(new Pkt4(DHCPACK, inform->getTransid()));
copyDefaultFields(inform, ack);
appendRequestedOptions(inform, ack);
appendRequestedVendorOptions(inform, ack);
adjustIfaceData(inform, ack);
// There are cases for the DHCPINFORM that the server receives it via
// relay but will send the response to the client's unicast address
// carried in the ciaddr. In this case, the giaddr and hops field should
// be cleared (these fields were copied by the copyDefaultFields function).
// Also Relay Agent Options should be removed if present.
if (ack->getRemoteAddr() != inform->getGiaddr()) {
ack->setHops(0);
ack->setGiaddr(IOAddress("0.0.0.0"));
ack->delOption(DHO_DHCP_AGENT_OPTIONS);
}
// The DHCPACK must contain server id.
appendServerID(ack);
return (ack);
}
const char*
......@@ -1493,6 +1543,12 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& question) const {
bool
Dhcpv4Srv::accept(const Pkt4Ptr& query) const {
// Check that the message type is accepted by the server. We rely on the
// function called to log a message if needed.
if (!acceptMessageType(query)) {
return (false);
}
// Check if the message from directly connected client (if directly
// connected) should be dropped or processed.
if (!acceptDirectRequest(query)) {
......@@ -1511,12 +1567,6 @@ Dhcpv4Srv::accept(const Pkt4Ptr& query) const {
return (false);
}
// Check that the message type is accepted by the server. We rely on the
// function called to log a message if needed.
if (!acceptMessageType(query)) {
return (false);
}
return (true);
}
......@@ -1529,6 +1579,23 @@ Dhcpv4Srv::acceptDirectRequest(const Pkt4Ptr& pkt) const {
} catch (const Exception& ex) {
return (false);
}
// The source address must not be zero for the DHCPINFORM message from
// the directly connected client because the server will not know where
// to respond if the ciaddr was not present.
static const IOAddress zero_addr("0.0.0.0");
try {
if (pkt->getType() == DHCPINFORM) {
if ((pkt->getRemoteAddr() == zero_addr) &&
(pkt->getCiaddr() == zero_addr)) {
return (false);
}
}
} catch (...) {
// If we got here, it is probably because the message type hasn't
// been set. But, this should not really happen assuming that
// we validate the message type prior to calling this function.
return (false);
}
static const IOAddress bcast("255.255.255.255");
return ((pkt->getLocalAddr() != bcast || selectSubnet(pkt)));
}
......
......@@ -239,8 +239,9 @@ protected:
/// This function accepts the following messages:
/// - all valid relayed messages,
/// - all unicast messages,
/// - all broadcast messages received on the interface for which the
/// suitable subnet exists (is configured).
/// - all broadcast messages except DHCPINFORM received on the interface
/// for which the suitable subnet exists (is configured).
/// - all DHCPINFORM messages with source address or ciaddr set.
///
/// @param query Message sent by a client.
///
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment