Browse Source

[5306] Use match-client-id defined on shared network level.

Marcin Siodelski 7 years ago
parent
commit
521afdb269

+ 4 - 6
src/bin/dhcp4/dhcp4_messages.mes

@@ -66,12 +66,10 @@ renewing existing lease. The server is explicitly configured to not use
 client identifier to lookup existing leases for the client and will not
 client identifier to lookup existing leases for the client and will not
 record client identifier in the lease database. This mode of operation
 record client identifier in the lease database. This mode of operation
 is useful when clients don't use stable client identifiers, e.g. multi
 is useful when clients don't use stable client identifiers, e.g. multi
-stage booting. Note that the client identifier may be used for other
-operations than lease allocation, e.g. identifying host reservations
-for the client using client identifier. The first argument includes the
-client and transaction identification information. The second argument
-specifies the identifier of the subnet where the client is connected
-and for which this mode of operation is configured on the server.
+stage booting. The first argument includes the client and transaction
+identification information. The second argument specifies the identifier
+of the subnet where the client is connected and for which this mode of
+operation is configured on the server.
 
 
 % DHCP4_CLIENT_FQDN_DATA %1: Client sent FQDN option: %2
 % DHCP4_CLIENT_FQDN_DATA %1: Client sent FQDN option: %2
 This debug message includes the detailed information extracted from the
 This debug message includes the detailed information extracted from the

+ 16 - 13
src/bin/dhcp4/dhcp4_srv.cc

@@ -132,20 +132,13 @@ Dhcpv4Exchange::Dhcpv4Exchange(const AllocEnginePtr& alloc_engine,
     // Pointer to client's query.
     // Pointer to client's query.
     context_->query_ = query;
     context_->query_ = query;
 
 
-    // Set client identifier if the match-client-id flag is enabled (default).
-    // If the subnet wasn't found it doesn't matter because we will not be
-    // able to allocate a lease anyway so this context will not be used.
+    // If subnet found, retrieve client identifier which will be needed
+    // for allocations and search for reservations associated with a
+    // subnet/shared network.
     if (subnet) {
     if (subnet) {
-        if (subnet->getMatchClientId()) {
-            OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
-            if (opt_clientid) {
-                context_->clientid_.reset(new ClientId(opt_clientid->getData()));
-            }
-        } else {
-            /// @todo When merging with #3806 use different logger.
-            LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_CLIENTID_IGNORED_FOR_LEASES)
-                .arg(query->getLabel())
-                .arg(subnet->getID());
+        OptionPtr opt_clientid = query->getOption(DHO_DHCP_CLIENT_IDENTIFIER);
+        if (opt_clientid) {
+            context_->clientid_.reset(new ClientId(opt_clientid->getData()));
         }
         }
 
 
         // Find static reservations if not disabled for our subnet.
         // Find static reservations if not disabled for our subnet.
@@ -1847,6 +1840,16 @@ Dhcpv4Srv::assignLease(Dhcpv4Exchange& ex) {
             .arg(query->getLabel())
             .arg(query->getLabel())
             .arg(lease->addr_.toText());
             .arg(lease->addr_.toText());
 
 
+        // We're logging this here, because this is the place where we know
+        // which subnet has been actually used for allocation. If the
+        // client identifier matching is disabled, we want to make sure that
+        // the user is notified.
+        if (!ctx->subnet_->getMatchClientId()) {
+            LOG_DEBUG(dhcp4_logger, DBG_DHCP4_DETAIL, DHCP4_CLIENTID_IGNORED_FOR_LEASES)
+                .arg(ctx->query_->getLabel())
+                .arg(ctx->subnet_->getID());
+        }
+
         resp->setYiaddr(lease->addr_);
         resp->setYiaddr(lease->addr_);
 
 
         /// @todo The server should check what ciaddr the client has supplied
         /// @todo The server should check what ciaddr the client has supplied

+ 101 - 0
src/bin/dhcp4/tests/shared_network_unittest.cc

@@ -596,6 +596,70 @@ const char* NETWORKS_CONFIG[] = {
     "            ]"
     "            ]"
     "        }"
     "        }"
     "    ]"
     "    ]"
+    "}",
+
+    // Configuration #11.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"valid-lifetime\": 600,"
+    "    \"match-client-id\": false,"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"match-client-id\": true,"
+    "            \"subnet4\": ["
+    "                {"
+    "                    \"subnet\": \"192.0.2.0/26\","
+    "                    \"id\": 10,"
+    "                    \"match-client-id\": false"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"192.0.2.64/26\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"192.0.2.65 - 192.0.2.127\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
+    "}",
+
+    // Configuration #12.
+    "{"
+    "    \"interfaces-config\": {"
+    "        \"interfaces\": [ \"*\" ]"
+    "    },"
+    "    \"valid-lifetime\": 600,"
+    "    \"match-client-id\": false,"
+    "    \"shared-networks\": ["
+    "        {"
+    "            \"name\": \"frog\","
+    "            \"interface\": \"eth1\","
+    "            \"match-client-id\": false,"
+    "            \"subnet4\": ["
+    "                {"
+    "                    \"subnet\": \"192.0.2.0/26\","
+    "                    \"id\": 10,"
+    "                    \"match-client-id\": false"
+    "                },"
+    "                {"
+    "                    \"subnet\": \"192.0.2.64/26\","
+    "                    \"id\": 100,"
+    "                    \"pools\": ["
+    "                        {"
+    "                            \"pool\": \"192.0.2.65 - 192.0.2.127\""
+    "                        }"
+    "                    ]"
+    "                }"
+    "            ]"
+    "        }"
+    "    ]"
     "}"
     "}"
 };
 };
 
 
@@ -1196,4 +1260,41 @@ TEST_F(Dhcpv4SharedNetworkTest, sharedNetworkSelectionByRelay) {
     EXPECT_EQ("10.0.0", resp2->getYiaddr().toText().substr(0, 6));
     EXPECT_EQ("10.0.0", resp2->getYiaddr().toText().substr(0, 6));
 }
 }
 
 
+// Client id matching gets disabled on the shared network level.
+TEST_F(Dhcpv4SharedNetworkTest, matchClientId) {
+    // Create client using client identifier besides MAC address.
+    Dhcp4Client client(Dhcp4Client::SELECTING);
+    client.includeClientId("01:02:03:04");
+    client.setIfaceName("eth1");
+
+    // Create server configuration with match-client-id value initially
+    // set to true. The client should be allocated a lease and the
+    // client identifier should be included in this lease.
+    configure(NETWORKS_CONFIG[11], *client.getServer());
+
+    // Perform 4-way exchange.
+    ASSERT_NO_THROW(client.doDORA());
+    Pkt4Ptr resp1 = client.getContext().response_;
+    ASSERT_TRUE(resp1);
+    ASSERT_EQ(DHCPACK, resp1->getType());
+
+    // Reconfigure the server and turn off client identifier matching
+    // on the shared network level. The subnet from which the client
+    // is allocated an address should derive the match-client-id value
+    // and ignore the fact that the client identifier is not matching.
+    configure(NETWORKS_CONFIG[12], *client.getServer());
+
+    client.includeClientId("01:01:01:01");
+    client.setState(Dhcp4Client::RENEWING);
+
+    // Try to renew the lease with modified MAC address.
+    ASSERT_NO_THROW(client.doRequest());
+    Pkt4Ptr resp2 = client.getContext().response_;
+    ASSERT_TRUE(resp2);
+    ASSERT_EQ(DHCPACK, resp2->getType());
+
+    // The lease should get rewnewed.
+    EXPECT_EQ(resp2->getYiaddr().toText(), resp1->getYiaddr().toText());
+}
+
 } // end of anonymous namespace
 } // end of anonymous namespace

+ 20 - 8
src/lib/dhcpsrv/alloc_engine.cc

@@ -2224,13 +2224,18 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
 
 
     while (subnet) {
     while (subnet) {
 
 
+        ClientIdPtr client_id;
+        if (subnet->getMatchClientId()) {
+            client_id = ctx.clientid_;
+        }
+
         // If client identifier has been supplied, use it to lookup the lease. This
         // If client identifier has been supplied, use it to lookup the lease. This
         // search will return no lease if the client doesn't have any lease in the
         // search will return no lease if the client doesn't have any lease in the
         // database or if the client didn't use client identifier to allocate the
         // database or if the client didn't use client identifier to allocate the
         // existing lease (this include cases when the server was explicitly
         // existing lease (this include cases when the server was explicitly
         // configured to ignore client identifier).
         // configured to ignore client identifier).
-        if (ctx.clientid_) {
-            client_lease = lease_mgr.getLease4(*ctx.clientid_, subnet->getID());
+        if (client_id) {
+            client_lease = lease_mgr.getLease4(*client_id, subnet->getID());
         }
         }
 
 
         // If no lease found using the client identifier, try the lookup using
         // If no lease found using the client identifier, try the lookup using
@@ -2246,7 +2251,7 @@ void findClientLease(AllocEngine::ClientContext4& ctx, Lease4Ptr& client_lease)
                  client_lease_it != client_leases.end(); ++client_lease_it) {
                  client_lease_it != client_leases.end(); ++client_lease_it) {
                 Lease4Ptr existing_lease = *client_lease_it;
                 Lease4Ptr existing_lease = *client_lease_it;
                 if ((existing_lease->subnet_id_ == subnet->getID()) &&
                 if ((existing_lease->subnet_id_ == subnet->getID()) &&
-                    existing_lease->belongsToClient(ctx.hwaddr_, ctx.clientid_)) {
+                    existing_lease->belongsToClient(ctx.hwaddr_, client_id)) {
                     // Found the lease of this client, so return it.
                     // Found the lease of this client, so return it.
                     client_lease = existing_lease;
                     client_lease = existing_lease;
                     // We got a lease but the subnet it belongs to may differ from
                     // We got a lease but the subnet it belongs to may differ from
@@ -2551,7 +2556,8 @@ AllocEngine::requestLease4(AllocEngine::ClientContext4& ctx) {
         // If it is in use by another client, the address can't be
         // If it is in use by another client, the address can't be
         // allocated.
         // allocated.
         if (existing && !existing->expired() &&
         if (existing && !existing->expired() &&
-            !existing->belongsToClient(ctx.hwaddr_, ctx.clientid_)) {
+            !existing->belongsToClient(ctx.hwaddr_, ctx.subnet_->getMatchClientId() ?
+                                       ctx.clientid_ : ClientIdPtr())) {
 
 
             LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
             LOG_DEBUG(alloc_engine_logger, ALLOC_ENGINE_DBG_TRACE,
                       ALLOC_ENGINE_V4_REQUEST_IN_USE)
                       ALLOC_ENGINE_V4_REQUEST_IN_USE)
@@ -2689,7 +2695,7 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr) {
 
 
     // @todo: remove this kludge after ticket #2590 is implemented
     // @todo: remove this kludge after ticket #2590 is implemented
     std::vector<uint8_t> local_copy;
     std::vector<uint8_t> local_copy;
-    if (ctx.clientid_) {
+    if (ctx.clientid_ && ctx.subnet_->getMatchClientId()) {
         local_copy = ctx.clientid_->getDuid();
         local_copy = ctx.clientid_->getDuid();
     }
     }
     const uint8_t* local_copy0 = local_copy.empty() ? 0 : &local_copy[0];
     const uint8_t* local_copy0 = local_copy.empty() ? 0 : &local_copy[0];
@@ -2832,7 +2838,8 @@ AllocEngine::renewLease4(const Lease4Ptr& lease,
         // Pass the parameters
         // Pass the parameters
         ctx.callout_handle_->setArgument("query4", ctx.query_);
         ctx.callout_handle_->setArgument("query4", ctx.query_);
         ctx.callout_handle_->setArgument("subnet4", subnet4);
         ctx.callout_handle_->setArgument("subnet4", subnet4);
-        ctx.callout_handle_->setArgument("clientid", ctx.clientid_);
+        ctx.callout_handle_->setArgument("clientid", subnet4->getMatchClientId() ?
+                                         ctx.clientid_ : ClientIdPtr());
         ctx.callout_handle_->setArgument("hwaddr", ctx.hwaddr_);
         ctx.callout_handle_->setArgument("hwaddr", ctx.hwaddr_);
 
 
         // Pass the lease to be updated
         // Pass the lease to be updated
@@ -2999,10 +3006,15 @@ AllocEngine::allocateUnreservedLease4(ClientContext4& ctx) {
     uint64_t total_attempts = 0;
     uint64_t total_attempts = 0;
     while (subnet) {
     while (subnet) {
 
 
+        ClientIdPtr client_id;
+        if (subnet->getMatchClientId()) {
+            client_id = ctx.clientid_;
+        }
+
         const uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
         const uint64_t max_attempts = (attempts_ > 0 ? attempts_ :
                                        subnet->getPoolCapacity(Lease::TYPE_V4));
                                        subnet->getPoolCapacity(Lease::TYPE_V4));
         for (uint64_t i = 0; i < max_attempts; ++i) {
         for (uint64_t i = 0; i < max_attempts; ++i) {
-            IOAddress candidate = allocator->pickAddress(subnet, ctx.clientid_,
+            IOAddress candidate = allocator->pickAddress(subnet, client_id,
                                                          ctx.requested_address_);
                                                          ctx.requested_address_);
             // If address is not reserved for another client, try to allocate it.
             // If address is not reserved for another client, try to allocate it.
             if (!addressReserved(candidate, ctx)) {
             if (!addressReserved(candidate, ctx)) {
@@ -3046,7 +3058,7 @@ AllocEngine::updateLease4Information(const Lease4Ptr& lease,
                                      AllocEngine::ClientContext4& ctx) const {
                                      AllocEngine::ClientContext4& ctx) const {
     lease->subnet_id_ = ctx.subnet_->getID();
     lease->subnet_id_ = ctx.subnet_->getID();
     lease->hwaddr_ = ctx.hwaddr_;
     lease->hwaddr_ = ctx.hwaddr_;
-    lease->client_id_ = ctx.clientid_;
+    lease->client_id_ = ctx.subnet_->getMatchClientId() ? ctx.clientid_ : ClientIdPtr();
     lease->cltt_ = time(NULL);
     lease->cltt_ = time(NULL);
     lease->t1_ = ctx.subnet_->getT1();
     lease->t1_ = ctx.subnet_->getT1();
     lease->t2_ = ctx.subnet_->getT2();
     lease->t2_ = ctx.subnet_->getT2();