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
 FQDN or Hostname option sent by a client. This is likely because the client's
 name was malformed or due to internal server error.
 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
 % DHCP4_COMMAND_RECEIVED received command %1, arguments: %2
 A debug message listing the command (and possible arguments) received
 A debug message listing the command (and possible arguments) received
 from the BIND 10 control system by the IPv4 DHCP server.
 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.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/option_int_array.h>
 #include <dhcp/option_vendor.h>
 #include <dhcp/option_vendor.h>
+#include <dhcp/option_string.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/pkt4.h>
 #include <dhcp/docsis3_option_defs.h>
 #include <dhcp/docsis3_option_defs.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_log.h>
@@ -333,6 +334,9 @@ Dhcpv4Srv::run() {
             callout_handle->getArgument("query4", query);
             callout_handle->getArgument("query4", query);
         }
         }
 
 
+        // Assign this packet to one or more classes if needed
+        classifyPacket(query);
+
         try {
         try {
             switch (query->getType()) {
             switch (query->getType()) {
             case DHCPDISCOVER:
             case DHCPDISCOVER:
@@ -391,7 +395,14 @@ Dhcpv4Srv::run() {
 
 
         adjustRemoteAddr(query, rsp);
         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);
             rsp->setRemotePort(DHCP4_CLIENT_PORT);
         } else {
         } else {
             rsp->setRemotePort(DHCP4_SERVER_PORT);
             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);
     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 dhcp
 }   // namespace isc
 }   // namespace isc

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

@@ -517,6 +517,19 @@ protected:
                          const std::string& option_space,
                          const std::string& option_space,
                          isc::dhcp::OptionCollection& options);
                          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:
 private:
 
 
     /// @brief Constructs netmask option based on subnet4
     /// @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_);
     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
     /// @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
     /// @return relayed DISCOVER
     Pkt4Ptr captureRelayedDiscover();
     Pkt4Ptr captureRelayedDiscover();
@@ -237,6 +238,14 @@ public:
     createPacketFromBuffer(const Pkt4Ptr& src_pkt,
     createPacketFromBuffer(const Pkt4Ptr& src_pkt,
                            Pkt4Ptr& dst_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
     /// @brief generates a DHCPv4 packet based on provided hex string
     ///
     ///
     /// @return created packet
     /// @return created packet
@@ -374,6 +383,7 @@ public:
     using Dhcpv4Srv::srvidToString;
     using Dhcpv4Srv::srvidToString;
     using Dhcpv4Srv::unpackOptions;
     using Dhcpv4Srv::unpackOptions;
     using Dhcpv4Srv::name_change_reqs_;
     using Dhcpv4Srv::name_change_reqs_;
+    using Dhcpv4Srv::classifyPacket;
 };
 };
 
 
 }; // end of isc::dhcp::test namespace
 }; // 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() {
 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)
 User Datagram Protocol, Src Port: bootps (67), Dst Port: bootps (67)
     Source port: bootps (67)
     Source port: bootps (67)
@@ -98,7 +101,7 @@ Bootstrap Protocol
     Magic cookie: DHCP
     Magic cookie: DHCP
     Option: (53) DHCP Message Type
     Option: (53) DHCP Message Type
     Option: (55) Parameter Request List
     Option: (55) Parameter Request List
-    Option: (60) Vendor class identifier
+    Option: (60) Vendor class identifier (docsis3.0)
     Option: (125) V-I Vendor-specific Information
     Option: (125) V-I Vendor-specific Information
       - suboption 1 (Option Request): requesting option 2
       - suboption 1 (Option Request): requesting option 2
       - suboption 5 (Modem Caps): 117 bytes
       - suboption 5 (Modem Caps): 117 bytes
@@ -129,6 +132,59 @@ Bootstrap Protocol
     return (packetFromCapture(hex_string));
     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::test namespace
 }; // end of isc::dhcp namespace
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 }; // end of isc namespace