Ipv6 Support (#10603)
This commit is contained in:
parent
84f837b76d
commit
cd7b7590ac
|
|
@ -392,6 +392,8 @@ public interface CommonConstants {
|
|||
|
||||
String PROTOCOL_SERVER = "server";
|
||||
|
||||
String IPV6_KEY = "ipv6";
|
||||
|
||||
/**
|
||||
* The parameter key for the class path of the ServiceNameMapping {@link Properties} file
|
||||
*
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ public class URLAddress implements Serializable {
|
|||
}
|
||||
|
||||
public URLAddress setHost(String host) {
|
||||
return new URLAddress(host, port, rawAddress);
|
||||
return new URLAddress(host, port, null);
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
|
|
@ -94,7 +94,7 @@ public class URLAddress implements Serializable {
|
|||
}
|
||||
|
||||
public URLAddress setPort(int port) {
|
||||
return new URLAddress(host, port, rawAddress);
|
||||
return new URLAddress(host, port, null);
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@ public final class NetUtils {
|
|||
|
||||
private static final Map<String, String> HOST_NAME_CACHE = new LRUCache<>(1000);
|
||||
private static volatile InetAddress LOCAL_ADDRESS = null;
|
||||
private static volatile Inet6Address LOCAL_ADDRESS_V6 = null;
|
||||
|
||||
private static final String SPLIT_IPV4_CHARACTER = "\\.";
|
||||
private static final String SPLIT_IPV6_CHARACTER = ":";
|
||||
|
|
@ -250,6 +251,8 @@ public final class NetUtils {
|
|||
|
||||
private static volatile String HOST_ADDRESS;
|
||||
|
||||
private static volatile String HOST_ADDRESS_V6;
|
||||
|
||||
public static String getLocalHost() {
|
||||
if (HOST_ADDRESS != null) {
|
||||
return HOST_ADDRESS;
|
||||
|
|
@ -257,6 +260,15 @@ public final class NetUtils {
|
|||
|
||||
InetAddress address = getLocalAddress();
|
||||
if (address != null) {
|
||||
if (address instanceof Inet6Address) {
|
||||
String ipv6AddressString = address.getHostAddress();
|
||||
if (ipv6AddressString.contains("%")) {
|
||||
ipv6AddressString = ipv6AddressString.substring(0, ipv6AddressString.indexOf("%"));
|
||||
}
|
||||
HOST_ADDRESS = ipv6AddressString;
|
||||
return HOST_ADDRESS;
|
||||
}
|
||||
|
||||
HOST_ADDRESS = address.getHostAddress();
|
||||
return HOST_ADDRESS;
|
||||
}
|
||||
|
|
@ -264,6 +276,29 @@ public final class NetUtils {
|
|||
return LOCALHOST_VALUE;
|
||||
}
|
||||
|
||||
public static String getLocalHostV6() {
|
||||
if (StringUtils.isNotEmpty(HOST_ADDRESS_V6)) {
|
||||
return HOST_ADDRESS_V6;
|
||||
}
|
||||
//avoid to search network interface card many times
|
||||
if("".equals(HOST_ADDRESS_V6)){
|
||||
return null;
|
||||
}
|
||||
|
||||
Inet6Address address = getLocalAddressV6();
|
||||
if (address != null) {
|
||||
String ipv6AddressString = address.getHostAddress();
|
||||
if (ipv6AddressString.contains("%")) {
|
||||
ipv6AddressString = ipv6AddressString.substring(0, ipv6AddressString.indexOf("%"));
|
||||
}
|
||||
|
||||
HOST_ADDRESS_V6 = ipv6AddressString;
|
||||
return HOST_ADDRESS_V6;
|
||||
}
|
||||
HOST_ADDRESS_V6 = "";
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String filterLocalHost(String host) {
|
||||
if (host == null || host.length() == 0) {
|
||||
return host;
|
||||
|
|
@ -309,6 +344,15 @@ public final class NetUtils {
|
|||
return localAddress;
|
||||
}
|
||||
|
||||
public static Inet6Address getLocalAddressV6() {
|
||||
if (LOCAL_ADDRESS_V6 != null) {
|
||||
return LOCAL_ADDRESS_V6;
|
||||
}
|
||||
Inet6Address localAddress = getLocalAddress0V6();
|
||||
LOCAL_ADDRESS_V6 = localAddress;
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
private static Optional<InetAddress> toValidAddress(InetAddress address) {
|
||||
if (address instanceof Inet6Address) {
|
||||
Inet6Address v6Address = (Inet6Address) address;
|
||||
|
|
@ -355,10 +399,34 @@ public final class NetUtils {
|
|||
logger.warn(e);
|
||||
}
|
||||
|
||||
localAddress = getLocalAddressV6();
|
||||
|
||||
return localAddress;
|
||||
}
|
||||
|
||||
private static Inet6Address getLocalAddress0V6() {
|
||||
// @since 2.7.6, choose the {@link NetworkInterface} first
|
||||
try {
|
||||
NetworkInterface networkInterface = findNetworkInterface();
|
||||
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address instanceof Inet6Address) {
|
||||
if (!address.isLoopbackAddress() //filter 127.x.x.x
|
||||
&& !address.isAnyLocalAddress() // filter 0.0.0.0
|
||||
&& !address.isLinkLocalAddress() //filter 169.254.0.0/16
|
||||
&& address.getHostAddress().contains(":")) {//filter IPv6
|
||||
return (Inet6Address) address;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
logger.warn(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the specified {@link NetworkInterface} should be ignored with the given conditions.
|
||||
*
|
||||
|
|
@ -380,7 +448,7 @@ public final class NetUtils {
|
|||
for (String ignoredInterface : ignoredInterfaces.split(",")) {
|
||||
String trimIgnoredInterface = ignoredInterface.trim();
|
||||
boolean matched = false;
|
||||
try {
|
||||
try {
|
||||
matched = networkInterfaceDisplayName.matches(trimIgnoredInterface);
|
||||
} catch (PatternSyntaxException e) {
|
||||
// if trimIgnoredInterface is an invalid regular expression, a PatternSyntaxException will be thrown out
|
||||
|
|
@ -744,4 +812,28 @@ public final class NetUtils {
|
|||
return Integer.parseInt(ipSegment, 16);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isIPV6URLStdFormat(String ip) {
|
||||
if ((ip.charAt(0) == '[' && ip.indexOf(']') > 2)) {
|
||||
return true;
|
||||
} else if (ip.indexOf(":") != ip.lastIndexOf(":")) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getLegalIP(String ip) {
|
||||
//ipv6 [::FFFF:129.144.52.38]:80
|
||||
int ind;
|
||||
if ((ip.charAt(0) == '[' && (ind = ip.indexOf(']')) > 2)) {
|
||||
String nhost = ip;
|
||||
ip = nhost.substring(0, ind + 1);
|
||||
ip = ip.substring(1, ind);
|
||||
return ip;
|
||||
} else {
|
||||
return ip;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ import java.lang.reflect.Modifier;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -364,7 +363,7 @@ public abstract class AbstractConfig implements Serializable {
|
|||
*/
|
||||
protected static Map<String, String> convert(Map<String, String> parameters, String prefix) {
|
||||
if (parameters == null || parameters.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
Map<String, String> result = new HashMap<>();
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ public class URLStrParserTest {
|
|||
testCases.add("dubbo://192.168.1.1/" + RandomString.make(10240));
|
||||
testCases.add("file:/path/to/file.txt");
|
||||
testCases.add("dubbo://fe80:0:0:0:894:aeec:f37d:23e1%en0/path?abc=abc");
|
||||
testCases.add("dubbo://[fe80:0:0:0:894:aeec:f37d:23e1]:20880/path?abc=abc");
|
||||
|
||||
errorDecodedCases.add("dubbo:192.168.1.1");
|
||||
errorDecodedCases.add("://192.168.1.1");
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.apache.dubbo.common;
|
|||
|
||||
import org.apache.dubbo.common.url.component.ServiceConfigURL;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
|
@ -1082,4 +1081,13 @@ public class URLTest {
|
|||
URL urlWithoutUserInformation = URL.valueOf("10.20.130.230:20880/context/path?version=1.0.0&application=app1");
|
||||
assertEquals("10.20.130.230:20880", urlWithoutUserInformation.getAuthority());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIPV6() {
|
||||
URL url = URL.valueOf("dubbo://[2408:4004:194:8896:3e8a:82ae:814a:398]:20881?name=apache");
|
||||
assertEquals("[2408:4004:194:8896:3e8a:82ae:814a:398]", url.getHost());
|
||||
assertEquals(20881, url.getPort());
|
||||
assertEquals("apache", url.getParameter("name"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import org.apache.dubbo.common.url.component.ServiceConfigURL;
|
|||
import org.apache.dubbo.common.utils.ClassUtils;
|
||||
import org.apache.dubbo.common.utils.CollectionUtils;
|
||||
import org.apache.dubbo.common.utils.ConfigUtils;
|
||||
import org.apache.dubbo.common.utils.NetUtils;
|
||||
import org.apache.dubbo.common.utils.StringUtils;
|
||||
import org.apache.dubbo.config.annotation.Service;
|
||||
import org.apache.dubbo.config.invoker.DelegateProviderMetaDataInvoker;
|
||||
|
|
@ -554,6 +555,15 @@ public class ServiceConfig<T> extends ServiceConfigBase<T> {
|
|||
|
||||
// export service
|
||||
String host = findConfiguredHosts(protocolConfig, provider, params);
|
||||
if (NetUtils.isIPV6URLStdFormat(host)) {
|
||||
if (!host.contains("[")) {
|
||||
host = "[" + host + "]";
|
||||
}
|
||||
} else if (NetUtils.getLocalHostV6() != null) {
|
||||
String ipv6Host = NetUtils.getLocalHostV6();
|
||||
params.put(CommonConstants.IPV6_KEY, ipv6Host);
|
||||
}
|
||||
|
||||
Integer port = findConfiguredPort(protocolConfig, provider, this.getExtensionLoader(Protocol.class), name, params);
|
||||
URL url = new ServiceConfigURL(name, null, null, host, port, getContextPath(protocolConfig).map(p -> p + "/" + path).orElse(path), params);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package org.apache.dubbo.metadata;
|
|||
|
||||
import org.apache.dubbo.common.extension.Activate;
|
||||
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.IPV6_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
|
||||
|
|
@ -37,9 +38,10 @@ public class DefaultMetadataParamsFilter implements MetadataParamsFilter {
|
|||
private final String[] includedInstanceParams;
|
||||
|
||||
public DefaultMetadataParamsFilter() {
|
||||
this.includedInstanceParams = new String[]{HEARTBEAT_TIMEOUT_KEY, TIMESTAMP_KEY};
|
||||
this.includedInstanceParams = new String[]{HEARTBEAT_TIMEOUT_KEY, TIMESTAMP_KEY, IPV6_KEY};
|
||||
this.excludedServiceParams = new String[]{MONITOR_KEY, BIND_IP_KEY, BIND_PORT_KEY, QOS_ENABLE,
|
||||
QOS_HOST, QOS_PORT, ACCEPT_FOREIGN_IP, VALIDATION_KEY, INTERFACES, PID_KEY, TIMESTAMP_KEY, HEARTBEAT_TIMEOUT_KEY};
|
||||
QOS_HOST, QOS_PORT, ACCEPT_FOREIGN_IP, VALIDATION_KEY, INTERFACES, PID_KEY, TIMESTAMP_KEY, HEARTBEAT_TIMEOUT_KEY,
|
||||
IPV6_KEY};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ import static org.apache.dubbo.common.constants.CommonConstants.EXTRA_KEYS_KEY;
|
|||
import static org.apache.dubbo.common.constants.CommonConstants.GROUP_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.HIDE_KEY_PREFIX;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.IPV6_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.LOADBALANCE_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
|
||||
import static org.apache.dubbo.common.constants.CommonConstants.MONITOR_KEY;
|
||||
|
|
@ -136,7 +137,7 @@ public class RegistryProtocol implements Protocol, ScopeModelAware {
|
|||
public static final String[] DEFAULT_REGISTER_PROVIDER_KEYS = {
|
||||
APPLICATION_KEY, CODEC_KEY, EXCHANGER_KEY, SERIALIZATION_KEY, CLUSTER_KEY, CONNECTIONS_KEY, DEPRECATED_KEY,
|
||||
GROUP_KEY, LOADBALANCE_KEY, MOCK_KEY, PATH_KEY, TIMEOUT_KEY, TOKEN_KEY, VERSION_KEY, WARMUP_KEY,
|
||||
WEIGHT_KEY, DUBBO_VERSION_KEY, RELEASE_KEY, SIDE_KEY
|
||||
WEIGHT_KEY, DUBBO_VERSION_KEY, RELEASE_KEY, SIDE_KEY, IPV6_KEY
|
||||
};
|
||||
|
||||
public static final String[] DEFAULT_REGISTER_CONSUMER_KEYS = {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package org.apache.dubbo.remoting.transport.netty4;
|
|||
import org.apache.dubbo.common.URL;
|
||||
import org.apache.dubbo.common.Version;
|
||||
import org.apache.dubbo.common.config.ConfigurationUtils;
|
||||
import org.apache.dubbo.common.constants.CommonConstants;
|
||||
import org.apache.dubbo.common.logger.ErrorTypeAwareLogger;
|
||||
import org.apache.dubbo.common.logger.LoggerFactory;
|
||||
import org.apache.dubbo.common.resource.GlobalResourceInitializer;
|
||||
|
|
@ -149,8 +150,33 @@ public class NettyClient extends AbstractClient {
|
|||
|
||||
@Override
|
||||
protected void doConnect() throws Throwable {
|
||||
try {
|
||||
String ipv6Address = NetUtils.getLocalHostV6();
|
||||
InetSocketAddress connectAddress;
|
||||
//first try ipv6 address
|
||||
if (ipv6Address != null && getUrl().getParameter(CommonConstants.IPV6_KEY) != null) {
|
||||
connectAddress = new InetSocketAddress(getUrl().getParameter(CommonConstants.IPV6_KEY), getUrl().getPort());
|
||||
try {
|
||||
doConnect(connectAddress);
|
||||
return;
|
||||
} catch (Throwable throwable) {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
|
||||
connectAddress = getConnectAddress();
|
||||
doConnect(connectAddress);
|
||||
} finally {
|
||||
// just add new valid channel to NettyChannel's cache
|
||||
if (!isConnected()) {
|
||||
//future.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void doConnect(InetSocketAddress serverAddress) throws RemotingException {
|
||||
long start = System.currentTimeMillis();
|
||||
ChannelFuture future = bootstrap.connect(getConnectAddress());
|
||||
ChannelFuture future = bootstrap.connect(serverAddress);
|
||||
try {
|
||||
boolean ret = future.awaitUninterruptibly(getConnectTimeout(), MILLISECONDS);
|
||||
|
||||
|
|
@ -192,7 +218,7 @@ public class NettyClient extends AbstractClient {
|
|||
// 6-1 Failed to connect to provider server by other reason.
|
||||
|
||||
RemotingException remotingException = new RemotingException(this, "client(url: " + getUrl() + ") failed to connect to server "
|
||||
+ getRemoteAddress() + ", error message is:" + cause.getMessage(), cause);
|
||||
+ serverAddress + ", error message is:" + cause.getMessage(), cause);
|
||||
|
||||
logger.error("6-1", "network disconnected", "",
|
||||
"Failed to connect to provider server by other reason.", cause);
|
||||
|
|
@ -204,7 +230,7 @@ public class NettyClient extends AbstractClient {
|
|||
// 6-2 Client-side timeout
|
||||
|
||||
RemotingException remotingException = new RemotingException(this, "client(url: " + getUrl() + ") failed to connect to server "
|
||||
+ getRemoteAddress() + " client-side timeout "
|
||||
+ serverAddress + " client-side timeout "
|
||||
+ getConnectTimeout() + "ms (elapsed: " + (System.currentTimeMillis() - start) + "ms) from netty client "
|
||||
+ NetUtils.getLocalHost() + " using dubbo version " + Version.getVersion());
|
||||
|
||||
|
|
|
|||
|
|
@ -97,7 +97,9 @@ public class ContextFilter implements Filter, Filter.Listener {
|
|||
|
||||
RpcContext context = RpcContext.getServerAttachment();
|
||||
// .setAttachments(attachments) // merged from dubbox
|
||||
context.setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
|
||||
if (context.getLocalAddress() == null) {
|
||||
context.setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
|
||||
}
|
||||
|
||||
String remoteApplication = invocation.getAttachment(REMOTE_APPLICATION_KEY);
|
||||
if (StringUtils.isNotEmpty(remoteApplication)) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue