]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#464,!238] Prototype fix for Genexis clients
authorTomek Mrugalski <tomasz@isc.org>
Tue, 12 Feb 2019 19:05:57 +0000 (20:05 +0100)
committerTomek Mrugalski <tomasz@isc.org>
Tue, 19 Feb 2019 11:15:37 +0000 (12:15 +0100)
src/bin/dhcp4/dhcp4_srv.cc

index 79b207c83bb6384d20b435f92442bef9cf455904..de8710bb95f28051a968e76755198a56600a9b3c 100644 (file)
@@ -1470,21 +1470,41 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
         return;
     }
 
-    // Try to get the vendor option
+    uint32_t vendor_id = 0;
+
+    // Try to get the vendor option from the client packet. This is how it's supposed to be
+    // done. Client sends vivso, we look at the vendor-id and then send back the vendor
+    // options specific to that client.
     boost::shared_ptr<OptionVendor> vendor_req = boost::dynamic_pointer_cast<
         OptionVendor>(ex.getQuery()->getOption(DHO_VIVSO_SUBOPTIONS));
-    if (!vendor_req) {
+    if (vendor_req) {
+        vendor_id = vendor_req->getVendorId();
+    }
+
+    // Something is fishy. Client was supposed to send vivso, but didn't. Let's try an
+    // alternative. It's possible that the server already inserted vivso in the response
+    // message, (e.g. by using client classification or perhaps a hook inserted it).
+    boost::shared_ptr<OptionVendor> vendor_rsp = boost::dynamic_pointer_cast<OptionVendor>
+        (ex.getResponse()->getOption(DHO_VIVSO_SUBOPTIONS));
+    if (vendor_rsp) {
+        vendor_id = vendor_rsp->getVendorId();
+    }
+
+    if (!vendor_req && !vendor_rsp) {
+        // Ok, we're out of luck today. Neither client nor server packets have vivso.
+        // There is no way to figure out vendor-id here. We give up.
         return;
     }
 
-    uint32_t vendor_id = vendor_req->getVendorId();
     std::vector<uint8_t> requested_opts;
 
     // Let's try to get ORO within that vendor-option
     /// @todo This is very specific to vendor-id=4491 (Cable Labs). Other
     /// vendors may have different policies.
-    OptionUint8ArrayPtr oro =
-        boost::dynamic_pointer_cast<OptionUint8Array>(vendor_req->getOption(DOCSIS3_V4_ORO));
+    OptionUint8ArrayPtr oro;
+    if (vendor_req) {
+        oro = boost::dynamic_pointer_cast<OptionUint8Array>(vendor_req->getOption(DOCSIS3_V4_ORO));
+    }
     // Get the list of options that client requested.
     if (oro) {
         requested_opts = oro->getValues();
@@ -1496,6 +1516,7 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
         if (!opts) {
             continue;
         }
+
         // Get persistent options
         const OptionContainerPersistIndex& idx = opts->get<2>();
         const OptionContainerPersistRange& range = idx.equal_range(true);
@@ -1514,7 +1535,11 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
         return;
     }
 
-    boost::shared_ptr<OptionVendor> vendor_rsp(new OptionVendor(Option::V4, vendor_id));
+    if (!vendor_rsp) {
+        // It's possible that vivso was inserted already by client class or a hook. If that is so,
+        // let's use it.
+        vendor_rsp.reset(new OptionVendor(Option::V4, vendor_id));
+    }
 
     // Get the list of options that client requested.
     bool added = false;
@@ -1532,7 +1557,9 @@ Dhcpv4Srv::appendRequestedVendorOptions(Dhcpv4Exchange& ex) {
             }
         }
 
-        if (added) {
+        // If we added some sub-options and the vivso option is not in the response
+        // already, then add it.
+        if (added && !ex.getResponse()->getOption(DHO_VIVSO_SUBOPTIONS)) {
             ex.getResponse()->addOption(vendor_rsp);
         }
     }