Browse Source

[3203] Client classification added in DHCPv4.

Tomek Mrugalski 11 years ago
parent
commit
b0c84e76de

+ 8 - 0
src/bin/dhcp4/dhcp4_messages.mes

@@ -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.

+ 76 - 1
src/bin/dhcp4/dhcp4_srv.cc

@@ -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

+ 13 - 0
src/bin/dhcp4/dhcp4_srv.h

@@ -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

+ 27 - 3
src/bin/dhcp4/tests/dhcp4_srv_unittest.cc

@@ -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

+ 11 - 1
src/bin/dhcp4/tests/dhcp4_test_utils.h

@@ -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

+ 58 - 2
src/bin/dhcp4/tests/wireshark.cc

@@ -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