diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java index 0b0d27a90..8bb7e3d2b 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/NacosDiscoveryProperties.java @@ -17,6 +17,8 @@ package com.alibaba.cloud.nacos; import java.net.Inet4Address; + +import java.net.Inet6Address; import java.net.InetAddress; import java.net.NetworkInterface; import java.util.Enumeration; @@ -30,6 +32,7 @@ import java.util.regex.Pattern; import javax.annotation.PostConstruct; import com.alibaba.cloud.nacos.event.NacosDiscoveryInfoChangedEvent; +import com.alibaba.cloud.nacos.intetuntil.InetIPv6Utils; import com.alibaba.nacos.api.naming.NamingService; import com.alibaba.nacos.api.naming.PreservedMetadataKeys; import com.alibaba.nacos.client.naming.utils.UtilAndComs; @@ -60,6 +63,7 @@ import static com.alibaba.nacos.api.PropertyKeyConst.USERNAME; /** * @author dungu.zpf * @author xiaojing + * @author HH * @author Mercy * @author lyuzb * @author eshun @@ -161,6 +165,11 @@ public class NacosDiscoveryProperties { */ private String networkInterface = ""; + /** + * choose IPV4 or IPV6,if you don't set it will choose IPV4 + */ + private String ipType = "IPv4" ; + /** * The port your want to register for your service instance, needn't to set it if the * auto detect port works well. @@ -213,6 +222,9 @@ public class NacosDiscoveryProperties { */ private boolean failFast = true; + @Autowired + private InetIPv6Utils inetIPUtils; + @Autowired private InetUtils inetUtils; @@ -244,7 +256,17 @@ public class NacosDiscoveryProperties { if (StringUtils.isEmpty(ip)) { // traversing network interfaces if didn't specify a interface if (StringUtils.isEmpty(networkInterface)) { - ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + if (ipType.equalsIgnoreCase("IPv4")){ + ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + }else if (ipType.equalsIgnoreCase("IPv6")){ + ip = inetIPUtils.findFirstNonLoopbackHostInfo().getIpAddress(); + int index = ip.indexOf('%'); + ip = index > 0 ? ip.substring(0, index) : ip; + ip = "["+ip+"]"; + }else { + throw new IllegalArgumentException( + "please checking the type of IP " + ipType); + } } else { NetworkInterface netInterface = NetworkInterface @@ -258,6 +280,7 @@ public class NacosDiscoveryProperties { while (inetAddress.hasMoreElements()) { InetAddress currentAddress = inetAddress.nextElement(); if (currentAddress instanceof Inet4Address + || currentAddress instanceof Inet6Address && !currentAddress.isLoopbackAddress()) { ip = currentAddress.getHostAddress(); break; @@ -312,6 +335,10 @@ public class NacosDiscoveryProperties { this.logName = logName; } + public void setInetIPUtils(InetIPv6Utils inetIPUtils){ + this.inetIPUtils = inetIPUtils; + } + public void setInetUtils(InetUtils inetUtils) { this.inetUtils = inetUtils; } @@ -372,6 +399,14 @@ public class NacosDiscoveryProperties { this.port = port; } + public String getIpType() { + return ipType; + } + + public void setIpType(String ipType) { + this.ipType = ipType; + } + public boolean isSecure() { return secure; } diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/InetIPv6Utils.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/InetIPv6Utils.java new file mode 100644 index 000000000..3a596d7e2 --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/InetIPv6Utils.java @@ -0,0 +1,158 @@ +package com.alibaba.cloud.nacos.intetuntil; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.cloud.commons.util.InetUtils; +import org.springframework.cloud.commons.util.InetUtilsProperties; + +import java.io.Closeable; +import java.io.IOException; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.UnknownHostException; +import java.util.Enumeration; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * @author HH + */ +public class InetIPv6Utils implements Closeable { + private final ExecutorService executorService; + + private final Log log = LogFactory.getLog(InetIPv6Utils.class); + + private final InetUtilsProperties properties; + + public InetIPv6Utils(final InetUtilsProperties properties) { + this.properties = properties; + this.executorService = Executors.newSingleThreadExecutor((r) -> { + Thread thread = new Thread(r); + thread.setName("spring.cloud.alibaba.inetutilsIPV6"); + thread.setDaemon(true); + return thread; + }); + } + + public void close() { + this.executorService.shutdown(); + } + + public InetUtils.HostInfo findFirstNonLoopbackHostInfo() { + InetAddress address = this.findFirstNonLoopbackIPv6Address(); + if (address != null) { + return this.convertAddress(address); + } else { + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + this.properties.setDefaultIpAddress("0:0:0:0:0:0:0:1"); + hostInfo.setHostname(this.properties.getDefaultHostname()); + hostInfo.setIpAddress(this.properties.getDefaultIpAddress()); + return hostInfo; + } + } + + public InetAddress findFirstNonLoopbackIPv6Address() { + InetAddress address = null; + + try { + int lowest = Integer.MAX_VALUE; + for (Enumeration nics = NetworkInterface.getNetworkInterfaces(); + nics.hasMoreElements();) { + NetworkInterface ifc = nics.nextElement(); + if (ifc.isUp()) { + log.trace("Testing interface:" + ifc.getDisplayName()); + if (ifc.getIndex() < lowest || address == null) { + lowest = ifc.getIndex(); + } + else if (address != null) { + continue; + } + + if (!ignoreInterface(ifc.getDisplayName())) { + for (Enumeration addrs = ifc + .getInetAddresses(); addrs.hasMoreElements();) { + InetAddress inetAddress = addrs.nextElement(); + if (inetAddress instanceof Inet6Address + && !inetAddress.isLoopbackAddress() + && isPreferredAddress(inetAddress)) { + log.trace("Found non-loopback interface: " + + ifc.getDisplayName()); + address = inetAddress; + } + } + } + } + } + } + catch (IOException e) { + log.error("Cannot get first non-loopback address", e); + } + + if (address != null) { + return address; + } + + try { + return InetAddress.getLocalHost(); + } + catch (UnknownHostException e) { + log.warn("Unable to retrieve localhost"); + } + + return null; + } + + boolean isPreferredAddress(InetAddress address) { + if (this.properties.isUseOnlySiteLocalInterfaces()) { + final boolean siteLocalAddress = address.isSiteLocalAddress(); + if (!siteLocalAddress) { + log.trace("Ignoring address"+address.getHostAddress()); + } + return siteLocalAddress; + } + final List preferredNetworks = this.properties.getPreferredNetworks(); + if (preferredNetworks.isEmpty()) { + return true; + } + for (String regex : preferredNetworks) { + final String hostAddress = address.getHostAddress(); + if (hostAddress.matches(regex) || hostAddress.startsWith(regex)) { + return true; + } + } + log.trace("Ignoring address: " + address.getHostAddress()); + return false; + } + + boolean ignoreInterface(String interfaceName) { + for (String regex : this.properties.getIgnoredInterfaces()) { + if (interfaceName.matches(regex)) { + log.trace("Ignoring interface: " + interfaceName); + return true; + } + } + return false; + } + + public InetUtils.HostInfo convertAddress(final InetAddress address) { + InetUtils.HostInfo hostInfo = new InetUtils.HostInfo(); + Future result = this.executorService.submit(address::getHostName); + + String hostname; + try { + hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS); + } + catch (Exception e) { + log.info("Cannot determine local hostname"); + hostname = "localhost"; + } + hostInfo.setHostname(hostname); + hostInfo.setIpAddress(address.getHostAddress()); + return hostInfo; + } +} diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/UtilIPv6AutoConfiguration.java b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/UtilIPv6AutoConfiguration.java new file mode 100644 index 000000000..f7588ec9e --- /dev/null +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/java/com/alibaba/cloud/nacos/intetuntil/UtilIPv6AutoConfiguration.java @@ -0,0 +1,28 @@ +package com.alibaba.cloud.nacos.intetuntil; + +import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled; +import org.springframework.cloud.commons.util.InetUtilsProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +/** + * @author HH + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnDiscoveryEnabled +@ConditionalOnNacosDiscoveryEnabled +public class UtilIPv6AutoConfiguration { + public UtilIPv6AutoConfiguration() { + } + + @Bean + @ConditionalOnMissingBean + public InetIPv6Utils inetUtils(InetUtilsProperties properties) { + return new InetIPv6Utils(properties); + } +} + diff --git a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories index dad08529a..92f91f592 100644 --- a/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-alibaba-starters/spring-cloud-starter-alibaba-nacos-discovery/src/main/resources/META-INF/spring.factories @@ -6,7 +6,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\ com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration,\ com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\ - com.alibaba.cloud.nacos.NacosServiceAutoConfiguration + com.alibaba.cloud.nacos.NacosServiceAutoConfiguration,\ + com.alibaba.cloud.nacos.intetuntil.InetIPv6Utils org.springframework.cloud.bootstrap.BootstrapConfiguration=\ com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration org.springframework.context.ApplicationListener=\