Commit b0c84e76 authored by Tomek Mrugalski's avatar Tomek Mrugalski 🛰
Browse files

[3203] Client classification added in DHCPv4.

parent 8840cfe8
......@@ -32,6 +32,14 @@ This debug message is issued when the DHCP server was unable to process the
FQDN or Hostname option sent by a client. This is likely because the client's
name was malformed or due to internal server error.
% DHCP4_CLASS_PROCESSING_FAILED client class specific processing failed
This debug message means that the server processing that is unique for each
client class has reported a failure. The response packet will not be sent.
% DHCP4_CLASS_ASSIGNED client packet has been assigned to the following class(es): %1
This debug message informs that incoming packet has been assigned to specified
class or classes. This is a norma
% DHCP4_COMMAND_RECEIVED received command %1, arguments: %2
A debug message listing the command (and possible arguments) received
from the BIND 10 control system by the IPv4 DHCP server.
......
......@@ -21,6 +21,7 @@
#include <dhcp/option_int.h>
#include <dhcp/option_int_array.h>
#include <dhcp/option_vendor.h>
#include <dhcp/option_string.h>
#include <dhcp/pkt4.h>
#include <dhcp/docsis3_option_defs.h>
#include <dhcp4/dhcp4_log.h>
......@@ -333,6 +334,9 @@ Dhcpv4Srv::run() {
callout_handle->getArgument("query4", query);
}
// Assign this packet to one or more classes if needed
classifyPacket(query);
try {
switch (query->getType()) {
case DHCPDISCOVER:
......@@ -391,7 +395,14 @@ Dhcpv4Srv::run() {
adjustRemoteAddr(query, rsp);
if (!rsp->getHops()) {
if (!classSpecificProcessing(query, rsp)) {
/// @todo add more verbosity here
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_PROCESSING_FAILED);
continue;
}
if (query->getRemotePort() == DHCP4_CLIENT_PORT) {
rsp->setRemotePort(DHCP4_CLIENT_PORT);
} else {
rsp->setRemotePort(DHCP4_SERVER_PORT);
......@@ -1783,5 +1794,69 @@ Dhcpv4Srv::ifaceMgrSocket4ErrorHandler(const std::string& errmsg) {
LOG_WARN(dhcp4_logger, DHCP4_OPEN_SOCKET_FAIL).arg(errmsg);
}
void Dhcpv4Srv::classifyPacket(const Pkt4Ptr& pkt) {
boost::shared_ptr<OptionString> vendor_class =
boost::dynamic_pointer_cast<OptionString>(pkt->getOption(DHO_VENDOR_CLASS_IDENTIFIER));
string classes = "";
if (!vendor_class) {
return;
}
// DOCSIS specific section
if (vendor_class->getValue().find("docsis3.0") != std::string::npos) {
pkt->addClass("docsis3.0");
classes += "docsis3.0 ";
}
if (vendor_class->getValue().find("eRouter1.0") != std::string::npos) {
pkt->addClass("eRouter1.0");
classes += "eRouter1.0 ";
}
classes += vendor_class->getValue();
pkt->addClass(vendor_class->getValue());
if (!classes.empty()) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_BASIC, DHCP4_CLASS_ASSIGNED)
.arg(classes);
}
}
bool Dhcpv4Srv::classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp) {
Subnet4Ptr subnet = selectSubnet(query);
if (!subnet) {
return (true);
}
if (query->inClass("docsis3.0")) {
// set next-server
// @todo uncomment this once 3191 is merged
// rsp->setSiaddr(subnet->getSiaddr());
Subnet::OptionDescriptor desc =
subnet->getOptionDescriptor("dhcp4", DHO_BOOT_FILE_NAME);
if (desc.option) {
boost::shared_ptr<OptionString> boot =
boost::dynamic_pointer_cast<OptionString>(desc.option);
if (boot) {
std::string filename = boot->getValue();
rsp->setFile((const uint8_t*)filename.c_str(), filename.size());
}
}
}
if (query->inClass("eRouter1.0")) {
}
return (true);
}
} // namespace dhcp
} // namespace isc
......@@ -517,6 +517,19 @@ protected:
const std::string& option_space,
isc::dhcp::OptionCollection& options);
/// @brief Assigns incoming packet to a given class
/// @param pkt packet to be classified
void classifyPacket(const Pkt4Ptr& pkt);
/// @brief Performs packet processing specific to a class
///
/// This processing is a likely candidate to be pushed into hooks.
///
/// @param query incoming client's packet
/// @param rsp server's response
/// @return true if successful, false otherwise (will prevent sending response)
bool classSpecificProcessing(const Pkt4Ptr& query, const Pkt4Ptr& rsp);
private:
/// @brief Constructs netmask option based on subnet4
......
......@@ -2995,8 +2995,32 @@ TEST_F(Dhcpv4SrvTest, vendorOptionsDocsisDefinitions) {
ASSERT_EQ(0, rcode_);
}
// Checks if client packets are classified properly
TEST_F(Dhcpv4SrvTest, clientClassification) {
NakedDhcpv4Srv srv(0);
// Let's create a relayed DISCOVER. This particular relayed DISCOVER has
// vendor-class set to docsis3.0
Pkt4Ptr dis1;
ASSERT_NO_THROW(dis1 = captureRelayedDiscover());
ASSERT_NO_THROW(dis1->unpack());
srv.classifyPacket(dis1);
EXPECT_TRUE(dis1->inClass("docsis3.0"));
EXPECT_FALSE(dis1->inClass("eRouter1.0"));
// Let's create a relayed DISCOVER. This particular relayed DISCOVER has
// vendor-class set to eRouter1.0
Pkt4Ptr dis2;
ASSERT_NO_THROW(dis2 = captureRelayedDiscover2());
ASSERT_NO_THROW(dis2->unpack());
srv.classifyPacket(dis2);
EXPECT_TRUE(dis2->inClass("eRouter1.0"));
EXPECT_FALSE(dis2->inClass("docsis3.0"));
}
/*I}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace */
}; // end of anonymous namespace
......@@ -206,7 +206,8 @@ public:
/// @brief returns captured DISCOVER that went through a relay
///
/// See method code for a detailed explanation.
/// See method code for a detailed explanation. This is a discover from
/// docsis3.0 device (Cable Modem)
///
/// @return relayed DISCOVER
Pkt4Ptr captureRelayedDiscover();
......@@ -237,6 +238,14 @@ public:
createPacketFromBuffer(const Pkt4Ptr& src_pkt,
Pkt4Ptr& dst_pkt);
/// @brief returns captured DISCOVER that went through a relay
///
/// See method code for a detailed explanation. This is a discover from
/// eRouter1.0 device (CPE device integrated with cable modem)
///
/// @return relayed DISCOVER
Pkt4Ptr captureRelayedDiscover2();
/// @brief generates a DHCPv4 packet based on provided hex string
///
/// @return created packet
......@@ -374,6 +383,7 @@ public:
using Dhcpv4Srv::srvidToString;
using Dhcpv4Srv::unpackOptions;
using Dhcpv4Srv::name_change_reqs_;
using Dhcpv4Srv::classifyPacket;
};
}; // end of isc::dhcp::test namespace
......
......@@ -71,7 +71,10 @@ void Dhcpv4SrvTest::captureSetDefaultFields(const Pkt4Ptr& pkt) {
Pkt4Ptr Dhcpv4SrvTest::captureRelayedDiscover() {
/* string exported from Wireshark:
/* This is packet 1 from capture
dhcp-val/pcap/docsis-*-CG3000DCR-Registration-Filtered.cap
string exported from Wireshark:
User Datagram Protocol, Src Port: bootps (67), Dst Port: bootps (67)
Source port: bootps (67)
......@@ -98,7 +101,7 @@ Bootstrap Protocol
Magic cookie: DHCP
Option: (53) DHCP Message Type
Option: (55) Parameter Request List
Option: (60) Vendor class identifier
Option: (60) Vendor class identifier (docsis3.0)
Option: (125) V-I Vendor-specific Information
- suboption 1 (Option Request): requesting option 2
- suboption 5 (Modem Caps): 117 bytes
......@@ -129,6 +132,59 @@ Bootstrap Protocol
return (packetFromCapture(hex_string));
}
Pkt4Ptr Dhcpv4SrvTest::captureRelayedDiscover2() {
/* This is packet 5 from capture
dhcp-val/pcap/docsis-*-CG3000DCR-Registration-Filtered.cap
string exported from Wireshark:
User Datagram Protocol, Src Port: bootps (67), Dst Port: bootps (67)
Bootstrap Protocol
Message type: Boot Request (1)
Hardware type: Ethernet (0x01)
Hardware address length: 6
Hops: 1
Transaction ID: 0x5d05478f
Seconds elapsed: 5
Bootp flags: 0x0000 (Unicast)
Client IP address: 0.0.0.0 (0.0.0.0)
Your (client) IP address: 0.0.0.0 (0.0.0.0)
Next server IP address: 0.0.0.0 (0.0.0.0)
Relay agent IP address: 10.254.226.1 (10.254.226.1)
Client MAC address: Netgear_b8:15:15 (20:e5:2a:b8:15:15)
Client hardware address padding: 00000000000000000000
Server host name not given
Boot file name not given
Magic cookie: DHCP
Option: (53) DHCP Message Type
Option: (55) Parameter Request List
Option: (43) Vendor-Specific Information
Option: (60) Vendor class identifier (eRouter1.0)
Option: (15) Domain Name
Option: (61) Client identifier
Option: (57) Maximum DHCP Message Size
Option: (82) Agent Information Option
Option: (255) End */
string hex_string =
"010106015d05478f000500000000000000000000000000000afee20120e52ab8151500"
"0000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000000000"
"000000000000000000000000000000000000000000000000000063825363350101370e"
"480102030406070c0f171a36337a2b63020745524f55544552030b45434d3a45524f55"
"544552040d324252323239553430303434430504312e3034060856312e33332e303307"
"07322e332e305232080630303039354209094347333030304443520a074e6574676561"
"720f0745524f555445523c0a65526f75746572312e300f14687364312e70612e636f6d"
"636173742e6e65742e3d0fff2ab815150003000120e52ab81515390205dc5219010420"
"000002020620e52ab8151409090000118b0401020300ff";
return (packetFromCapture(hex_string));
}
}; // end of isc::dhcp::test namespace
}; // end of isc::dhcp namespace
}; // end of isc namespace
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