This is an automated email from the ASF dual-hosted git repository.

manikumar pushed a commit to branch 2.7
in repository https://gitbox.apache.org/repos/asf/kafka.git


The following commit(s) were added to refs/heads/2.7 by this push:
     new 45abdc2  KAFKA-8562; SaslChannelBuilder - Avoid (reverse) DNS lookup 
while building SslTransportLayer (#10059)
45abdc2 is described below

commit 45abdc2db8de25783eeed3b786e5c6b30071981c
Author: Davor Poldrugo <[email protected]>
AuthorDate: Fri Feb 26 02:02:40 2021 +0100

    KAFKA-8562; SaslChannelBuilder - Avoid (reverse) DNS lookup while building 
SslTransportLayer (#10059)
    
    This patch moves the `peerHost` helper defined in `SslChannelBuilder` into 
`SslFactor`. `SaslChannelBuilder` is then updated to use a new 
`createSslEngine` overload which relies on `peerHost` when building its 
`SslEngine`. The purpose is to avoid the reverse DNS in `getHostName`.
    
    Reviewers: Ismael Juma <[email protected]>, Manikumar Reddy 
<[email protected]>, Jason Gustafson <[email protected]>
---
 .../kafka/common/network/SaslChannelBuilder.java   |  3 +-
 .../kafka/common/network/SslChannelBuilder.java    | 48 ++--------------------
 .../kafka/common/security/ssl/SslFactory.java      | 48 ++++++++++++++++++++++
 .../kafka/common/network/SslSelectorTest.java      |  4 +-
 .../common/network/SslTransportLayerTest.java      |  4 +-
 .../SaslAuthenticatorFailureDelayTest.java         |  2 +-
 .../authenticator/SaslAuthenticatorTest.java       | 10 ++---
 7 files changed, 62 insertions(+), 57 deletions(-)

diff --git 
a/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java 
b/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
index f01c4ef..25b04c9 100644
--- 
a/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
+++ 
b/clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java
@@ -244,8 +244,7 @@ public class SaslChannelBuilder implements ChannelBuilder, 
ListenerReconfigurabl
                                                  ChannelMetadataRegistry 
metadataRegistry) throws IOException {
         if (this.securityProtocol == SecurityProtocol.SASL_SSL) {
             return SslTransportLayer.create(id, key,
-                
sslFactory.createSslEngine(socketChannel.socket().getInetAddress().getHostName(),
-                    socketChannel.socket().getPort()),
+                sslFactory.createSslEngine(socketChannel.socket()),
                 metadataRegistry);
         } else {
             return new PlaintextTransportLayer(key);
diff --git 
a/clients/src/main/java/org/apache/kafka/common/network/SslChannelBuilder.java 
b/clients/src/main/java/org/apache/kafka/common/network/SslChannelBuilder.java
index 327fff8..a093ebe 100644
--- 
a/clients/src/main/java/org/apache/kafka/common/network/SslChannelBuilder.java
+++ 
b/clients/src/main/java/org/apache/kafka/common/network/SslChannelBuilder.java
@@ -32,7 +32,6 @@ import org.slf4j.Logger;
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.InetAddress;
-import java.net.InetSocketAddress;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.Map;
@@ -101,8 +100,7 @@ public class SslChannelBuilder implements ChannelBuilder, 
ListenerReconfigurable
     public KafkaChannel buildChannel(String id, SelectionKey key, int 
maxReceiveSize,
                                      MemoryPool memoryPool, 
ChannelMetadataRegistry metadataRegistry) throws KafkaException {
         try {
-            SslTransportLayer transportLayer = buildTransportLayer(sslFactory, 
id, key,
-                peerHost(key), metadataRegistry);
+            SslTransportLayer transportLayer = buildTransportLayer(sslFactory, 
id, key, metadataRegistry);
             Supplier<Authenticator> authenticatorCreator = () ->
                 new SslAuthenticator(configs, transportLayer, listenerName, 
sslPrincipalMapper);
             return new KafkaChannel(id, transportLayer, authenticatorCreator, 
maxReceiveSize,
@@ -118,53 +116,13 @@ public class SslChannelBuilder implements ChannelBuilder, 
ListenerReconfigurable
         if (sslFactory != null) sslFactory.close();
     }
 
-    protected SslTransportLayer buildTransportLayer(SslFactory sslFactory, 
String id, SelectionKey key,
-                                                    String host, 
ChannelMetadataRegistry metadataRegistry) throws IOException {
+    protected SslTransportLayer buildTransportLayer(SslFactory sslFactory, 
String id, SelectionKey key, ChannelMetadataRegistry metadataRegistry) throws 
IOException {
         SocketChannel socketChannel = (SocketChannel) key.channel();
-        return SslTransportLayer.create(id, key, 
sslFactory.createSslEngine(host, socketChannel.socket().getPort()),
+        return SslTransportLayer.create(id, key, 
sslFactory.createSslEngine(socketChannel.socket()),
             metadataRegistry);
     }
 
     /**
-     * Returns host/IP address of remote host without reverse DNS lookup to be 
used as the host
-     * for creating SSL engine. This is used as a hint for session reuse 
strategy and also for
-     * hostname verification of server hostnames.
-     * <p>
-     * Scenarios:
-     * <ul>
-     *   <li>Server-side
-     *   <ul>
-     *     <li>Server accepts connection from a client. Server knows only 
client IP
-     *     address. We want to avoid reverse DNS lookup of the client IP 
address since the server
-     *     does not verify or use client hostname. The IP address can be used 
directly.</li>
-     *   </ul>
-     *   </li>
-     *   <li>Client-side
-     *   <ul>
-     *     <li>Client connects to server using hostname. No lookup is necessary
-     *     and the hostname should be used to create the SSL engine. This 
hostname is validated
-     *     against the hostname in SubjectAltName (dns) or CommonName in the 
certificate if
-     *     hostname verification is enabled. Authentication fails if hostname 
does not match.</li>
-     *     <li>Client connects to server using IP address, but certificate 
contains only
-     *     SubjectAltName (dns). Use of reverse DNS lookup to determine 
hostname introduces
-     *     a security vulnerability since authentication would be reliant on a 
secure DNS.
-     *     Hence hostname verification should fail in this case.</li>
-     *     <li>Client connects to server using IP address and certificate 
contains
-     *     SubjectAltName (ipaddress). This could be used when Kafka is on a 
private network.
-     *     If reverse DNS lookup is used, authentication would succeed using 
IP address if lookup
-     *     fails and IP address is used, but authentication would fail if 
lookup succeeds and
-     *     dns name is used. For consistency and to avoid dependency on a 
potentially insecure
-     *     DNS, reverse DNS lookup should be avoided and the IP address 
specified by the client for
-     *     connection should be used to create the SSL engine.</li>
-     *   </ul></li>
-     * </ul>
-     */
-    private String peerHost(SelectionKey key) {
-        SocketChannel socketChannel = (SocketChannel) key.channel();
-        return new InetSocketAddress(socketChannel.socket().getInetAddress(), 
0).getHostString();
-    }
-
-    /**
      * Note that client SSL authentication is handled in {@link 
SslTransportLayer}. This class is only used
      * to transform the derived principal using a {@link 
KafkaPrincipalBuilder} configured by the user.
      */
diff --git 
a/clients/src/main/java/org/apache/kafka/common/security/ssl/SslFactory.java 
b/clients/src/main/java/org/apache/kafka/common/security/ssl/SslFactory.java
index 9b305db..e1372bf 100644
--- a/clients/src/main/java/org/apache/kafka/common/security/ssl/SslFactory.java
+++ b/clients/src/main/java/org/apache/kafka/common/security/ssl/SslFactory.java
@@ -31,6 +31,8 @@ import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLException;
 import java.io.Closeable;
+import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.nio.ByteBuffer;
 import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
@@ -181,6 +183,14 @@ public class SslFactory implements Reconfigurable, 
Closeable {
         }
     }
 
+    public SSLEngine createSslEngine(Socket socket) {
+        return createSslEngine(peerHost(socket), socket.getPort());
+    }
+
+    /**
+     * Prefer `createSslEngine(Socket)` if a `Socket` instance is available. 
If using this overload,
+     * avoid reverse DNS resolution in the computation of `peerHost`.
+     */
     public SSLEngine createSslEngine(String peerHost, int peerPort) {
         if (sslEngineFactory == null) {
             throw new IllegalStateException("SslFactory has not been 
configured.");
@@ -192,6 +202,44 @@ public class SslFactory implements Reconfigurable, 
Closeable {
         }
     }
 
+    /**
+     * Returns host/IP address of remote host without reverse DNS lookup to be 
used as the host
+     * for creating SSL engine. This is used as a hint for session reuse 
strategy and also for
+     * hostname verification of server hostnames.
+     * <p>
+     * Scenarios:
+     * <ul>
+     *   <li>Server-side
+     *   <ul>
+     *     <li>Server accepts connection from a client. Server knows only 
client IP
+     *     address. We want to avoid reverse DNS lookup of the client IP 
address since the server
+     *     does not verify or use client hostname. The IP address can be used 
directly.</li>
+     *   </ul>
+     *   </li>
+     *   <li>Client-side
+     *   <ul>
+     *     <li>Client connects to server using hostname. No lookup is necessary
+     *     and the hostname should be used to create the SSL engine. This 
hostname is validated
+     *     against the hostname in SubjectAltName (dns) or CommonName in the 
certificate if
+     *     hostname verification is enabled. Authentication fails if hostname 
does not match.</li>
+     *     <li>Client connects to server using IP address, but certificate 
contains only
+     *     SubjectAltName (dns). Use of reverse DNS lookup to determine 
hostname introduces
+     *     a security vulnerability since authentication would be reliant on a 
secure DNS.
+     *     Hence hostname verification should fail in this case.</li>
+     *     <li>Client connects to server using IP address and certificate 
contains
+     *     SubjectAltName (ipaddress). This could be used when Kafka is on a 
private network.
+     *     If reverse DNS lookup is used, authentication would succeed using 
IP address if lookup
+     *     fails and IP address is used, but authentication would fail if 
lookup succeeds and
+     *     dns name is used. For consistency and to avoid dependency on a 
potentially insecure
+     *     DNS, reverse DNS lookup should be avoided and the IP address 
specified by the client for
+     *     connection should be used to create the SSL engine.</li>
+     *   </ul></li>
+     * </ul>
+     */
+    private String peerHost(Socket socket) {
+        return new InetSocketAddress(socket.getInetAddress(), 
0).getHostString();
+    }
+
     public SslEngineFactory sslEngineFactory() {
         return sslEngineFactory;
     }
diff --git 
a/clients/src/test/java/org/apache/kafka/common/network/SslSelectorTest.java 
b/clients/src/test/java/org/apache/kafka/common/network/SslSelectorTest.java
index 8a36fbf..7c48d09 100644
--- a/clients/src/test/java/org/apache/kafka/common/network/SslSelectorTest.java
+++ b/clients/src/test/java/org/apache/kafka/common/network/SslSelectorTest.java
@@ -382,9 +382,9 @@ public class SslSelectorTest extends SelectorTest {
 
         @Override
         protected SslTransportLayer buildTransportLayer(SslFactory sslFactory, 
String id, SelectionKey key,
-                                                        String host, 
ChannelMetadataRegistry metadataRegistry) throws IOException {
+                                                        
ChannelMetadataRegistry metadataRegistry) throws IOException {
             SocketChannel socketChannel = (SocketChannel) key.channel();
-            SSLEngine sslEngine = sslFactory.createSslEngine(host, 
socketChannel.socket().getPort());
+            SSLEngine sslEngine = 
sslFactory.createSslEngine(socketChannel.socket());
             TestSslTransportLayer transportLayer = new 
TestSslTransportLayer(id, key, sslEngine, metadataRegistry);
             return transportLayer;
         }
diff --git 
a/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
 
b/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
index ccfb2a9..9b659ec 100644
--- 
a/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
+++ 
b/clients/src/test/java/org/apache/kafka/common/network/SslTransportLayerTest.java
@@ -1319,9 +1319,9 @@ public class SslTransportLayerTest {
 
         @Override
         protected SslTransportLayer buildTransportLayer(SslFactory sslFactory, 
String id, SelectionKey key,
-                                                        String host, 
ChannelMetadataRegistry metadataRegistry) throws IOException {
+                                                        
ChannelMetadataRegistry metadataRegistry) throws IOException {
             SocketChannel socketChannel = (SocketChannel) key.channel();
-            SSLEngine sslEngine = sslFactory.createSslEngine(host, 
socketChannel.socket().getPort());
+            SSLEngine sslEngine = 
sslFactory.createSslEngine(socketChannel.socket());
             return newTransportLayer(id, key, sslEngine);
         }
 
diff --git 
a/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorFailureDelayTest.java
 
b/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorFailureDelayTest.java
index 19003ed..df4e041 100644
--- 
a/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorFailureDelayTest.java
+++ 
b/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorFailureDelayTest.java
@@ -238,7 +238,7 @@ public class SaslAuthenticatorFailureDelayTest {
 
     private void createClientConnection(SecurityProtocol securityProtocol, 
String node) throws Exception {
         createSelector(securityProtocol, saslClientConfigs);
-        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 
server.port());
+        InetSocketAddress addr = new InetSocketAddress("localhost", 
server.port());
         selector.connect(node, addr, BUFFER_SIZE, BUFFER_SIZE);
     }
 
diff --git 
a/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorTest.java
 
b/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorTest.java
index 5c1ce3c..d6f80fd 100644
--- 
a/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorTest.java
+++ 
b/clients/src/test/java/org/apache/kafka/common/security/authenticator/SaslAuthenticatorTest.java
@@ -248,7 +248,7 @@ public class SaslAuthenticatorTest {
         SecurityProtocol securityProtocol = SecurityProtocol.SASL_SSL;
         server = createEchoServer(securityProtocol);
         createSelector(securityProtocol, saslClientConfigs);
-        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 
server.port());
+        InetSocketAddress addr = new InetSocketAddress("localhost", 
server.port());
         try {
             selector.connect(node, addr, BUFFER_SIZE, BUFFER_SIZE);
             fail("SASL/PLAIN channel created without username");
@@ -272,7 +272,7 @@ public class SaslAuthenticatorTest {
         SecurityProtocol securityProtocol = SecurityProtocol.SASL_SSL;
         server = createEchoServer(securityProtocol);
         createSelector(securityProtocol, saslClientConfigs);
-        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 
server.port());
+        InetSocketAddress addr = new InetSocketAddress("localhost", 
server.port());
         try {
             selector.connect(node, addr, BUFFER_SIZE, BUFFER_SIZE);
             fail("SASL/PLAIN channel created without password");
@@ -389,7 +389,7 @@ public class SaslAuthenticatorTest {
             saslClientConfigs.put(SaslConfigs.SASL_MECHANISM, "DIGEST-MD5");
             createSelector(securityProtocol, saslClientConfigs);
             selector2 = selector;
-            InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 
server.port());
+            InetSocketAddress addr = new InetSocketAddress("localhost", 
server.port());
             selector.connect(node2, addr, BUFFER_SIZE, BUFFER_SIZE);
             NetworkTestUtils.checkClientConnection(selector, node2, 100, 10);
             selector = null; // keeps it from being closed when next one is 
created
@@ -399,7 +399,7 @@ public class SaslAuthenticatorTest {
             saslClientConfigs.put(SaslConfigs.SASL_MECHANISM, "SCRAM-SHA-256");
             createSelector(securityProtocol, saslClientConfigs);
             selector3 = selector;
-            selector.connect(node3, new InetSocketAddress("127.0.0.1", 
server.port()), BUFFER_SIZE, BUFFER_SIZE);
+            selector.connect(node3, new InetSocketAddress("localhost", 
server.port()), BUFFER_SIZE, BUFFER_SIZE);
             NetworkTestUtils.checkClientConnection(selector, node3, 100, 10);
             server.verifyAuthenticationMetrics(3, 0);
             
@@ -1970,7 +1970,7 @@ public class SaslAuthenticatorTest {
         };
         clientChannelBuilder.configure(saslClientConfigs);
         this.selector = NetworkTestUtils.createSelector(clientChannelBuilder, 
time);
-        InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 
server.port());
+        InetSocketAddress addr = new InetSocketAddress("localhost", 
server.port());
         selector.connect(node, addr, BUFFER_SIZE, BUFFER_SIZE);
     }
 

Reply via email to