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

aweisberg pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 3bdd2caa22a0413929188536b41d8117177574fa
Author: Andy Tolbert <6889771+tolber...@users.noreply.github.com>
AuthorDate: Thu Oct 6 14:04:38 2022 -0400

    Fix StorageService.getNativeaddress handling of IPv6 addresses
    
    StorageService.getNativeaddress does not currently correctly handle
    IPv6 addresses correctly when NATIVE_ADDRESS_AND_PORT are not present in
    that it simply concatenates the IP address with the default native port,
    e.g.:
    
    0:0:0:0:0:0:5a:3:9042
    
    This does not parse into an InetSocketAddress as the address and port
    can't be disambiguated.
    
    Such a case would usually be present when there are 3.x nodes present in a
    cluster with 4.0 nodes.
    
    Change updates RPC_ADDRESS and else case to create InetAddressAndPort 
instances
    with DatabaseDescriptor.getNativeTransportPort and returns the
    getHostAddress(withPort) which properly bracket encodes the address,
    e.g.:
    
    [0:0:0:0:0:0:5a:3]:9042
    
    which can be parsed as an InetSocketAddress.
    
    patch by Andy Tolbert; reviewed by Ariel Weisberg, Brandon Williams for 
CASSANDRA-17945
---
 CHANGES.txt                                        |  1 +
 .../apache/cassandra/service/StorageService.java   | 27 +++++++++++++++++++---
 .../service/StorageServiceServerTest.java          | 22 ++++++++++++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 15bc6413ad..d48edb9a4f 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 4.0.7
+ * Fix StorageService.getNativeaddress handling of IPv6 addresses 
(CASSANDRA-17945)
  * Mitigate direct buffer memory OOM on replacements (CASSANDRA-17895)
  * Fix repair failure on assertion if two peers have overlapping mismatching 
ranges (CASSANDRA-17900)
  * Better handle null state in Gossip schema migration to avoid NPE 
(CASSANDRA-17864)
diff --git a/src/java/org/apache/cassandra/service/StorageService.java 
b/src/java/org/apache/cassandra/service/StorageService.java
index 7e70e4ce20..b70347a301 100644
--- a/src/java/org/apache/cassandra/service/StorageService.java
+++ b/src/java/org/apache/cassandra/service/StorageService.java
@@ -1975,10 +1975,31 @@ public class StorageService extends 
NotificationBroadcasterSupport implements IE
                 throw new RuntimeException(e);
             }
         }
-        else if 
(Gossiper.instance.getEndpointStateForEndpoint(endpoint).getApplicationState(ApplicationState.RPC_ADDRESS)
 == null)
-            return endpoint.address.getHostAddress() + ":" + 
DatabaseDescriptor.getNativeTransportPort();
         else
-            return 
Gossiper.instance.getEndpointStateForEndpoint(endpoint).getApplicationState(ApplicationState.RPC_ADDRESS).value
 + ":" + DatabaseDescriptor.getNativeTransportPort();
+        {
+             final String ipAddress;
+             // If RPC_ADDRESS present in gossip for this endpoint use it.  
This is expected for 3.x nodes.
+             if 
(Gossiper.instance.getEndpointStateForEndpoint(endpoint).getApplicationState(ApplicationState.RPC_ADDRESS)
 != null)
+             {
+                 ipAddress = 
Gossiper.instance.getEndpointStateForEndpoint(endpoint).getApplicationState(ApplicationState.RPC_ADDRESS).value;
+             }
+             else
+             {
+                 // otherwise just use the IP of the endpoint itself.
+                 ipAddress = endpoint.getHostAddress(false);
+             }
+
+             // include the configured native_transport_port.
+             try
+             {
+                 InetAddressAndPort address = 
InetAddressAndPort.getByNameOverrideDefaults(ipAddress, 
DatabaseDescriptor.getNativeTransportPort());
+                 return address.getHostAddress(withPort);
+             }
+             catch (UnknownHostException e)
+             {
+                 throw new RuntimeException(e);
+             }
+         }
     }
 
     public Map<List<String>, List<String>> getRangeToRpcaddressMap(String 
keyspace)
diff --git 
a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java 
b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java
index b5ddd35514..60bed4c64d 100644
--- a/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java
+++ b/test/unit/org/apache/cassandra/service/StorageServiceServerTest.java
@@ -641,6 +641,28 @@ public class StorageServiceServerTest
         assertEquals("127.0.0.3:666", 
StorageService.instance.getNativeaddress(internalAddress, true));
     }
 
+    @Test
+    public void testGetNativeAddressIPV6() throws Exception
+    {
+        // Ensure IPv6 addresses are properly bracketed in RFC2732 
(https://datatracker.ietf.org/doc/html/rfc2732) format when including ports.
+        // See https://issues.apache.org/jira/browse/CASSANDRA-17945 for more 
context.
+        String internalAddressIPV6String = "[0:0:0:0:0:0:0:3]:666";
+        InetAddressAndPort internalAddressIPV6 = 
InetAddressAndPort.getByName(internalAddressIPV6String);
+        Gossiper.instance.addSavedEndpoint(internalAddressIPV6);
+
+        //Default to using the provided address with the configured port
+        assertEquals("[0:0:0:0:0:0:0:3]:" + 
DatabaseDescriptor.getNativeTransportPort(), 
StorageService.instance.getNativeaddress(internalAddressIPV6, true));
+
+        VersionedValue.VersionedValueFactory valueFactory =  new 
VersionedValue.VersionedValueFactory(Murmur3Partitioner.instance);
+        //If RPC_ADDRESS is present with an IPv6 address, we should properly 
bracket encode the IP with the configured port.
+        
Gossiper.instance.getEndpointStateForEndpoint(internalAddressIPV6).addApplicationState(ApplicationState.RPC_ADDRESS,
 valueFactory.rpcaddress(InetAddress.getByName("0:0:0:0:0:0:5a:3")));
+        assertEquals("[0:0:0:0:0:0:5a:3]:" + 
DatabaseDescriptor.getNativeTransportPort(), 
StorageService.instance.getNativeaddress(internalAddressIPV6, true));
+
+        //If we have the address and port in gossip use that
+        
Gossiper.instance.getEndpointStateForEndpoint(internalAddressIPV6).addApplicationState(ApplicationState.NATIVE_ADDRESS_AND_PORT,
 
valueFactory.nativeaddressAndPort(InetAddressAndPort.getByName("[0:0:0:0:0:0:5c:3]:8675")));
+        assertEquals("[0:0:0:0:0:0:5c:3]:8675", 
StorageService.instance.getNativeaddress(internalAddressIPV6, true));
+    }
+
     @Test
     public void testAuditLogEnableLoggerNotFound() throws Exception
     {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to