break;
case DHCPINFORM:
- processInform(query);
+ rsp = processInform(query);
break;
default:
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
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*
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)) {
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);
}
} 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)));
}