From cf2f46a72dff57a94d7e5ba6e13d2f065cb5813b Mon Sep 17 00:00:00 2001 From: Martin Furmanski Date: Thu, 29 Jun 2017 14:11:24 +0200 Subject: [PATCH] Support ipv6 in network receiver uri creation --- .../neo4j/cluster/com/NetworkReceiver.java | 33 +++-- .../kernel/ha/HaIPv6ConfigurationTest.java | 115 ++++++++++++++++++ 2 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java diff --git a/enterprise/cluster/src/main/java/org/neo4j/cluster/com/NetworkReceiver.java b/enterprise/cluster/src/main/java/org/neo4j/cluster/com/NetworkReceiver.java index f18993a75cc85..b48385dbfd07e 100644 --- a/enterprise/cluster/src/main/java/org/neo4j/cluster/com/NetworkReceiver.java +++ b/enterprise/cluster/src/main/java/org/neo4j/cluster/com/NetworkReceiver.java @@ -38,6 +38,9 @@ import org.jboss.netty.util.ThreadRenamingRunnable; import java.net.ConnectException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; @@ -240,23 +243,30 @@ public void receive( Message message ) } } - URI getURI( InetSocketAddress address ) + URI getURI( InetSocketAddress socketAddress ) { String uri; - // Socket.toString() already prepends a / - if ( address.getAddress().getHostAddress().startsWith( "0" ) ) + InetAddress address = socketAddress.getAddress(); + + if ( address instanceof Inet6Address ) + { + uri = CLUSTER_SCHEME + "://" + wrapAddressForIPv6Uri( address.getHostAddress() ) + ":" + socketAddress.getPort(); + } + else if ( address instanceof Inet4Address ) { - uri = CLUSTER_SCHEME + "://0.0.0.0:" + address.getPort(); + uri = CLUSTER_SCHEME + "://" + address.getHostAddress() + ":" + socketAddress.getPort(); } else { - uri = CLUSTER_SCHEME + "://" + address.getAddress().getHostAddress() + ":" + address.getPort(); + throw new IllegalArgumentException( "Address type unknown" ); } // Add name if given - if (config.name() != null) - uri += "/?name="+config.name(); + if ( config.name() != null ) + { + uri += "/?name=" + config.name(); + } return URI.create( uri ); } @@ -329,6 +339,10 @@ public void messageReceived( ChannelHandlerContext ctx, MessageEvent event ) thr InetSocketAddress remote = (InetSocketAddress) ctx.getChannel().getRemoteAddress(); String remoteAddress = remote.getAddress().getHostAddress(); URI fromHeader = URI.create( message.getHeader( Message.FROM ) ); + if ( remote.getAddress() instanceof Inet6Address ) + { + remoteAddress = wrapAddressForIPv6Uri( remoteAddress ); + } fromHeader = URI.create(fromHeader.getScheme()+"://"+remoteAddress + ":" + fromHeader.getPort()); message.setHeader( Message.FROM, fromHeader.toASCIIString() ); @@ -359,4 +373,9 @@ public void exceptionCaught( ChannelHandlerContext ctx, ExceptionEvent e ) throw } } } + + private static String wrapAddressForIPv6Uri( String address ) + { + return "[" + address + "]"; + } } diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java new file mode 100644 index 0000000000000..34fe0b5e502a8 --- /dev/null +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package org.neo4j.kernel.ha; + +import org.junit.Rule; +import org.junit.Test; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.Enumeration; + +import org.neo4j.cluster.ClusterSettings; +import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.factory.HighlyAvailableGraphDatabaseFactory; +import org.neo4j.test.rule.TestDirectory; + +import static org.junit.Assume.assumeTrue; + +public class HaIPv6ConfigurationTest +{ + @Rule + public TestDirectory dir = TestDirectory.testDirectory(); + + @Test + public void testClusterWithLocalhostAddresses() throws Throwable + { + GraphDatabaseService db = new HighlyAvailableGraphDatabaseFactory() + .newEmbeddedDatabaseBuilder( dir.makeGraphDbDir() ) + .setConfig( ClusterSettings.cluster_server, ipv6HostPortSetting( "::1", 5000 ) ) + .setConfig( ClusterSettings.initial_hosts, ipv6HostPortSetting( "::1", 5000 ) ) + .setConfig( HaSettings.ha_server, ipv6HostPortSetting( "::", 6000 ) ) + .setConfig( ClusterSettings.server_id, "1" ) + .newGraphDatabase(); + + try ( Transaction tx = db.beginTx() ) + { + db.createNode(); + tx.success(); + } + + db.shutdown(); + } + + @Test + public void testClusterWithLinkLocalAddress() throws Throwable + { + boolean foundAnIpv6LinkLocalAddress = false; + InetAddress inetAddress = null; + + Enumeration nics = NetworkInterface.getNetworkInterfaces(); + while ( nics.hasMoreElements() ) + { + NetworkInterface nic = nics.nextElement(); + Enumeration inetAddresses = nic.getInetAddresses(); + while ( inetAddresses.hasMoreElements() ) + { + inetAddress = inetAddresses.nextElement(); + if ( inetAddress instanceof Inet6Address && inetAddress.isLinkLocalAddress() ) + { + foundAnIpv6LinkLocalAddress = true; + break; + } + } + } + + assumeTrue( foundAnIpv6LinkLocalAddress ); + + GraphDatabaseService db = new HighlyAvailableGraphDatabaseFactory() + .newEmbeddedDatabaseBuilder( dir.makeGraphDbDir() ) + .setConfig( ClusterSettings.cluster_server, ipv6HostPortSetting( inetAddress.getHostAddress(), 5000 ) ) + .setConfig( ClusterSettings.initial_hosts, ipv6HostPortSetting( inetAddress.getHostAddress(), 5000 ) ) + .setConfig( HaSettings.ha_server, ipv6HostPortSetting( "::", 6000 ) ) + .setConfig( ClusterSettings.server_id, "1" ) + .newGraphDatabase(); + + db.shutdown(); + } + + @Test + public void testClusterWithWildcardAddresses() throws Throwable + { + GraphDatabaseService db = new HighlyAvailableGraphDatabaseFactory() + .newEmbeddedDatabaseBuilder( dir.makeGraphDbDir() ) + .setConfig( ClusterSettings.cluster_server, ipv6HostPortSetting( "::", 5000 ) ) + .setConfig( ClusterSettings.initial_hosts, ipv6HostPortSetting( "::1", 5000 ) ) + .setConfig( HaSettings.ha_server, ipv6HostPortSetting( "::", 6000 ) ) + .setConfig( ClusterSettings.server_id, "1" ) + .newGraphDatabase(); + + db.shutdown(); + } + + private String ipv6HostPortSetting( String address, int port ) + { + return "[" + address + "]:" + port; + } +}