|
@@ -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)));
|
|
|
}
|