feature: support dual stack address registry and discovery in SCL (#3207)

Support dual stack address registry and discovery in SCL  (#3207)
pull/3221/head
Steve Rao 2 years ago committed by GitHub
parent e29f81c0ac
commit d50b995a7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -312,6 +312,27 @@ spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
----
=== IPv4至IPv6地址迁移方案
==== IPv4和IPv6地址双注册
在配置完成以上Spring Cloud LoadBalancer作为负载均衡策略后应用启动后会默认将微服务的IPv4地址和IPv6地址注册到注册中心中其中IPv4地址会存放在Nacos服务列表中的IP字段下IPv6地址在Nacos的metadata字段中其对应的Key为IPv6。当服务消费者调用服务提供者时会根据自身的IP地址栈支持情况选择合适的IP地址类型发起服务调用。具体规则
1服务消费者本身支持IPv4和IPv6双地址栈或仅支持IPv6地址栈的情况下服务消费者会使用服务提供的IPv6地址发起服务调用IPv6地址调用失败如本身还同事支持IPv4地址栈时暂不支持切换到IPv4再发起重试调用
2服务消费者本身仅支持IPv4单地址栈的情况下服务消费者会使用服务提供的IPv4地址发起服务调用。
==== 仅注册IPv4
如果您只想使用IPv4地址进行注册可以在application.properties使用以下配置
[source,properties]
----
spring.cloud.nacos.discovery.ip-type=IPv4
----
==== 仅注册IPv6
如果您只想使用IPv6地址可以在application.properties使用以下配置
[source,properties]
----
spring.cloud.nacos.discovery.ip-type=IPv6
----
=== 关于 Nacos Discovery Starter 更多的配置项信息
更多关于 Nacos Discovery Starter 的配置项如下所示:

@ -296,7 +296,7 @@ The followings shows how a service instance accesses the Endpoint:
=== Weight Route
==== Spring Cloud Loadbalancer
==== Spring Cloud LoadBalancer
.pom.xml
[source,xml]
----
@ -315,6 +315,28 @@ spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
----
=== IPv4 to IPv6 address migration scheme
==== Both register IPv4 and IPv6 address
After configuring above Spring Cloud LoadBalancer as the load balancing policy, the IPv4 address and IPv6 address of the microservice will be registered with the registry by default after the application is started, where the IPv4 address will be stored in the IP field of the Nacos service list, the IPv6 address will be in the metadata field of Nacos, and its corresponding Key will be IPv6. When a service consumer calls a service provider, it selects the appropriate IP address type to initiate a service call based on its IP address stack support. Specific rules:
(1) If the service consumer itself supports IPv4 and IPv6 dual address stacks or only supports IPv6 address stacks, the service consumer will use the IPv6 address provided by the service to initiate a service call, and if the IPv6 address call fails, if it also supports the IPv4 address stack, it is temporarily not supported to switch to IPv4 and then initiate a retry call;
(2) If the service consumer itself only supports IPv4 single-address stack, the service consumer will use the IPv4 address provided by the service to initiate service calls.
==== Only Register IPv4 address
If you only want to register IPv4 address.Config in application.properties as follows:
[source,properties]
----
spring.cloud.nacos.discovery.ip-type=IPv4
----
==== Only Register IPv6 address
If you only want to register IPv6 address.Config in application.properties as follows:
[source,properties]
----
spring.cloud.nacos.discovery.ip-type=IPv6
----
=== More Information about Nacos Discovery Starter Configurations
The following shows the other configurations of the starter of Nacos Discovery:

@ -19,3 +19,4 @@ spring.cloud.sentinel.datasource.ds1.file.rule-type=flow
spring.cloud.sentinel.datasource.ds2.file.file=classpath: degraderule.json
spring.cloud.sentinel.datasource.ds2.file.data-type=json
spring.cloud.sentinel.datasource.ds2.file.rule-type=degrade
spring.cloud.loadbalancer.nacos.enabled=true

@ -1,9 +1,11 @@
server.port=18082
server.port=0
spring.application.name=service-provider
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.cloud.nacos.discovery.enabled=true
#spring.cloud.nacos.discovery.instance-enabled=true
#register IPv6
#only register IPv4 instance
#spring.cloud.nacos.discovery.ip-type=IPv4
#only register IPv6 instance
#spring.cloud.nacos.discovery.ip-type=IPv6
spring.cloud.nacos.username=nacos

@ -78,11 +78,39 @@
### 服务发现
#### 集成 Ribbon
为了便于使用NacosServerList 实现了 com.netflix.loadbalancer.ServerList<Server> 接口,并在 @ConditionOnMissingBean 的条件下进行自动注入。如果您有定制化的需求,可以自己实现自己的 ServerList。
Nacos Discovery Starter 默认集成了 Ribbon ,所以对于使用了 Ribbon 做负载均衡的组件,可以直接使用 Nacos 的服务发现。
#### 集成 Spring Cloud Loadbalancer
```xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
```
增加如下配置,使用 Spring Cloud Alibaba 社区针对 Spring Cloud Loadbalancer 负载均衡依赖提供的负载均衡策略,以便使用 Spring Cloud Alibaba 提供的所有的能力:
```properties
spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
```
#### IPv4至IPv6地址迁移方案
##### IPv4和IPv6地址双注册
在配置完成Spring Cloud Loadbalancer作为负载均衡策略后应用启动后会默认将微服务的IPv4地址和IPv6地址注册到注册中心中其中IPv4地址会存放在Nacos服务列表中的IP字段下IPv6地址在Nacos的metadata字段中其对应的Key为IPv6。当服务消费者调用服务提供者时会根据自身的IP地址栈支持情况选择合适的IP地址类型发起服务调用。具体规则
1服务消费者本身支持IPv4和IPv6双地址栈或仅支持IPv6地址栈的情况下服务消费者会使用服务提供的IPv6地址发起服务调用IPv6地址调用失败如本身还同事支持IPv4地址栈时暂不支持切换到IPv4再发起重试调用
2服务消费者本身仅支持IPv4单地址栈的情况下服务消费者会使用服务提供的IPv4地址发起服务调用。
##### 仅注册IPv4
如果您只想使用IPv4地址进行注册可以在application.properties使用以下配置
```
spring.cloud.nacos.discovery.ip-type=IPv4
```
##### 仅注册IPv6
如果您只想使用IPv6地址可以在application.properties使用以下配置
```
spring.cloud.nacos.discovery.ip-type=IPv6
```
#### 使用 RestTemplate 和 FeignClient
@ -158,11 +186,6 @@ Spring Cloud Nacos Discovery 遵循了 spring cloud common 标准,实现了 Au
### 服务发现
NacosServerList 实现了 com.netflix.loadbalancer.ServerList<Server> 接口,并在 @ConditionOnMissingBean 的条件下进行自动注入默认集成了Ribbon。
如果需要有更加自定义的可以使用 @Autowired 注入一个 NacosRegistration 实例,通过其持有的 NamingService 字段内容直接调用 Nacos API。
## Endpoint 信息查看
@ -191,7 +214,7 @@ Spring Boot 2.x 可以通过访问 http://127.0.0.1:18083/actuator/nacos-discove
权重|spring.cloud.nacos.discovery.weight|1|取值范围 1 到 100数值越大权重越大
网卡名|spring.cloud.nacos.discovery.network-interface||当IP未配置时注册的IP为此网卡所对应的IP地址如果此项也未配置则默认取第一块网卡的地址
注册的IP地址|spring.cloud.nacos.discovery.ip||优先级最高
注册的IP地址类型|spring.cloud.nacos.discovery.ip-type|IPv4|可以配置IPv4和IPv6两种类型如果网卡同类型IP地址存在多个希望制定特定网段地址可使用`spring.cloud.inetutils.preferred-networks`配置筛选地址
注册的IP地址类型|spring.cloud.nacos.discovery.ip-type|双栈地址|可以配置IPv4和IPv6两种类型如果网卡同类型IP地址存在多个希望制定特定网段地址可使用`spring.cloud.inetutils.preferred-networks`配置筛选地址
注册的端口|spring.cloud.nacos.discovery.port|-1|默认情况下不用配置,会自动探测
命名空间|spring.cloud.nacos.discovery.namespace||常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
AccessKey|spring.cloud.nacos.discovery.access-key||

@ -80,11 +80,41 @@ Enter `http://127.0.0.1:8848/nacos/#/serviceDetail?name=service-provider&groupNa
### Service Discovery
#### Integration Ribbon
For ease of use, NacosServerList implements the com.netflix.loadbalancer.ServerList<Server> interface and auto-injects under the @ConditionOnMissingBean condition. If you have customized requirements, you can implement your own ServerList yourself.
Nacos Discovery Starter integrates Ribbon by default, so for components that use Ribbon for load balancing, you can use Nacos Service discovery directly.
#### Integration Spring Cloud Loadbalancer
```xml
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
</dependencies>
```
Add the following configuration to use the load balancing strategy provided by the Spring Cloud Alibaba community for Spring Cloud Loadbalancer load balancing dependencies, so as to use all the capabilities provided by Spring Cloud Alibaba:
```properties
spring.cloud.loadbalancer.ribbon.enabled=false
spring.cloud.loadbalancer.nacos.enabled=true
```
#### IPv4 to IPv6 address migration scheme
##### Both register IPv4 and IPv6 address
After configuring above Spring Cloud Loadbalancer as the load balancing policy, the IPv4 address and IPv6 address of the microservice will be registered with the registry by default after the application is started, where the IPv4 address will be stored in the IP field of the Nacos service list, the IPv6 address will be in the metadata field of Nacos, and its corresponding Key will be IPv6. When a service consumer calls a service provider, it selects the appropriate IP address type to initiate a service call based on its IP address stack support. Specific rules:
(1) If the service consumer itself supports IPv4 and IPv6 dual address stacks or only supports IPv6 address stacks, the service consumer will use the IPv6 address provided by the service to initiate a service call, and if the IPv6 address call fails, if it also supports the IPv4 address stack, it is temporarily not supported to switch to IPv4 and then initiate a retry call;
(2) If the service consumer itself only supports IPv4 single-address stack, the service consumer will use the IPv4 address provided by the service to initiate service calls.
##### Only Register IPv4 address
If you only want to register IPv4 address.Config in application.properties as follows:
```
spring.cloud.nacos.discovery.ip-type=IPv4
```
##### Only Register IPv6 address
If you only want to register IPv6 address.Config in application.properties as follows:
```
spring.cloud.nacos.discovery.ip-type=IPv6
```
#### Use RestTemplate and FeignClient
@ -161,14 +191,6 @@ Spring Cloud Nacos Discovery follows the spring cloud common standard and implem
During the startup phase of the spring cloud application, the WebServerInitializedEvent event is watched. When the WebServerInitializedEvent event is received after the Web container is initialized, the registration action is triggered, and the ServiceRegistry register method is called to register the service to the Nacos Server.
### Service Discovery
NacosServerList implements the com.netflix.loadbalancer.ServerList <Server> interface and auto-injects it under @ConditionOnMissingBean. The ribbon is integrated by default.
If you need to be more customizable, you can use @Autowired to inject a NacosRegistration bean and call the Nacos API directly through the contents of the NamingService field it holds.
## Endpoint
Nacos Discovery Starter also supports the implementation of Spring Boot actuator endpoints.
@ -198,7 +220,7 @@ server address|spring.cloud.nacos.discovery.server-addr||
service|spring.cloud.nacos.discovery.service|${spring.application.name}|service id to registry
weight|spring.cloud.nacos.discovery.weight|1|value from 1 to 100, The larger the value, the larger the weight
ip|spring.cloud.nacos.discovery.ip||ip address to registry, Highest priority
ip type|spring.cloud.nacos.discovery.ip-type|IPv4|IPv4 and IPv6 can be configured, If there are multiple IP addresses of the same type of network card, and you want to specify a specific network segment address, you can use `spring.cloud.inetutils.preferred-networks` to configure the filter address.
ip type|spring.cloud.nacos.discovery.ip-type|Dual Stack Address|IPv4 and IPv6 can be configured, If there are multiple IP addresses of the same type of network card, and you want to specify a specific network segment address, you can use `spring.cloud.inetutils.preferred-networks` to configure the filter address.
network interface|spring.cloud.nacos.discovery.network-interface||When the IP is not configured, the registered IP address is the IP address corresponding to the network-interface. If this item is not configured, the address of the first network-interface is taken by default.
port|spring.cloud.nacos.discovery.port|-1|port to registry, Automatically detect without configuration
namesapce|spring.cloud.nacos.discovery.namespace||One of the common scenarios is the separation of the configuration of different environments, such as the development of the test environment and the resource isolation of the production environment.

@ -32,7 +32,7 @@ import javax.annotation.PostConstruct;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.event.NacosDiscoveryInfoChangedEvent;
import com.alibaba.cloud.nacos.utils.InetIPv6Util;
import com.alibaba.cloud.nacos.util.InetIPv6Utils;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.PreservedMetadataKeys;
import com.alibaba.nacos.client.naming.utils.UtilAndComs;
@ -80,6 +80,10 @@ public class NacosDiscoveryProperties {
private static final Pattern PATTERN = Pattern.compile("-(\\w)");
private static final String IPV4 = "IPv4";
private static final String IPV6 = "IPv6";
/**
* nacos discovery server address.
*/
@ -169,7 +173,7 @@ public class NacosDiscoveryProperties {
* When IPv6 is chosen but no IPv6 can be found, system will automatically find IPv4 to ensure there is an
* available service address.
*/
private String ipType = "IPv4";
private String ipType;
/**
* The port your want to register for your service instance, needn't to set it if the
@ -230,7 +234,7 @@ public class NacosDiscoveryProperties {
private boolean failFast = true;
@Autowired
private InetIPv6Util inetIPv6Util;
private InetIPv6Utils inetIPv6Utils;
@Autowired
private InetUtils inetUtils;
@ -261,13 +265,21 @@ public class NacosDiscoveryProperties {
logName = Objects.toString(logName, "");
if (StringUtils.isEmpty(ip)) {
// traversing network interfaces if didn't specify a interface
// traversing network interfaces if didn't specify an interface
if (StringUtils.isEmpty(networkInterface)) {
if ("IPv4".equalsIgnoreCase(ipType)) {
if (ipType == null) {
ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
String ipv6Addr = inetIPv6Utils.findIPv6Address();
metadata.put(IPV6, ipv6Addr);
if (ipv6Addr != null) {
metadata.put(IPV6, ipv6Addr);
}
}
else if (IPV4.equalsIgnoreCase(ipType)) {
ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
}
else if ("IPv6".equalsIgnoreCase(ipType)) {
ip = inetIPv6Util.findIPv6Address();
else if (IPV6.equalsIgnoreCase(ipType)) {
ip = inetIPv6Utils.findIPv6Address();
if (StringUtils.isEmpty(ip)) {
log.warn("There is no available IPv6 found. Spring Cloud Alibaba will automatically find IPv4.");
ip = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();

@ -19,8 +19,13 @@ package com.alibaba.cloud.nacos.balancer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosServiceInstance;
import com.alibaba.cloud.nacos.loadbalancer.NacosLoadBalancer;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.client.naming.core.Balancer;
@ -32,6 +37,10 @@ import org.springframework.cloud.client.ServiceInstance;
*/
public class NacosBalancer extends Balancer {
private static final String IPV4_REGEX = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";
private static final String IPV6_KEY = "IPv6";
/**
* Choose instance by weight.
* @param instances Instance List
@ -64,7 +73,25 @@ public class NacosBalancer extends Balancer {
}).collect(Collectors.toList());
Instance instance = getHostByRandomWeight2(nacosInstance);
return instanceMap.get(instance);
NacosServiceInstance nacosServiceInstance = (NacosServiceInstance) instanceMap.get(instance);
// When local support IPv6 address stack, referred to use IPv6 address.
if (StringUtils.isNotEmpty(NacosLoadBalancer.ipv6)) {
convertIPv4ToIPv6(nacosServiceInstance);
}
return nacosServiceInstance;
}
/**
* There is two type Ip,using IPv6 should use IPv6 in metadata to replace IPv4 in IP
* field.
*/
private static void convertIPv4ToIPv6(NacosServiceInstance instance) {
if (Pattern.matches(IPV4_REGEX, instance.getHost())) {
String ip = instance.getMetadata().get(IPV6_KEY);
if (StringUtils.isNotEmpty(ip)) {
instance.setHost(ip);
}
}
}
}

@ -16,18 +16,24 @@
package com.alibaba.cloud.nacos.loadbalancer;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.balancer.NacosBalancer;
import com.alibaba.cloud.nacos.util.InetIPv6Utils;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
@ -54,6 +60,57 @@ public class NacosLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private static final String IPV4_REGEX = "((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}";
private static final String IPV6_KEY = "IPv6";
/**
* Storage local valid IPv6 address, it's a flag whether local machine support IPv6 address stack.
*/
public static String ipv6;
@Autowired
private InetIPv6Utils inetIPv6Utils;
@PostConstruct
public void init() {
String ip = nacosDiscoveryProperties.getIp();
if (StringUtils.isNotEmpty(ip)) {
ipv6 = Pattern.matches(IPV4_REGEX, ip) ? nacosDiscoveryProperties.getMetadata().get(IPV6_KEY) : ip;
}
else {
ipv6 = inetIPv6Utils.findIPv6Address();
}
}
private List<ServiceInstance> filterInstanceByIpType(List<ServiceInstance> instances) {
if (StringUtils.isNotEmpty(ipv6)) {
List<ServiceInstance> ipv6InstanceList = new ArrayList<>();
for (ServiceInstance instance : instances) {
if (Pattern.matches(IPV4_REGEX, instance.getHost())) {
if (StringUtils.isNotEmpty(instance.getMetadata().get(IPV6_KEY))) {
ipv6InstanceList.add(instance);
}
}
else {
ipv6InstanceList.add(instance);
}
}
// Provider has no IPv6, should use IPv4.
if (ipv6InstanceList.size() == 0) {
return instances.stream()
.filter(instance -> Pattern.matches(IPV4_REGEX, instance.getHost()))
.collect(Collectors.toList());
}
else {
return ipv6InstanceList;
}
}
return instances.stream()
.filter(instance -> Pattern.matches(IPV4_REGEX, instance.getHost()))
.collect(Collectors.toList());
}
public NacosLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId, NacosDiscoveryProperties nacosDiscoveryProperties) {
@ -96,6 +153,7 @@ public class NacosLoadBalancer implements ReactorServiceInstanceLoadBalancer {
"A cross-cluster call occursname = {}, clusterName = {}, instance = {}",
serviceId, clusterName, serviceInstances);
}
instancesToChoose = this.filterInstanceByIpType(instancesToChoose);
ServiceInstance instance = NacosBalancer
.getHostByRandomWeight3(instancesToChoose);
@ -106,7 +164,6 @@ public class NacosLoadBalancer implements ReactorServiceInstanceLoadBalancer {
log.warn("NacosLoadBalancer error", e);
return null;
}
}
}

@ -14,20 +14,14 @@
* limitations under the License.
*/
package com.alibaba.cloud.nacos.utils;
package com.alibaba.cloud.nacos.util;
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;
import com.alibaba.cloud.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
@ -39,64 +33,55 @@ import org.springframework.cloud.commons.util.InetUtilsProperties;
/**
* @author HH
*/
public class InetIPv6Util implements Closeable {
public class InetIPv6Utils {
private final ExecutorService executorService;
private final Log log = LogFactory.getLog(InetIPv6Util.class);
private final static Log log = LogFactory.getLog(InetIPv6Utils.class);
private final InetUtilsProperties properties;
@Override
public void close() {
this.executorService.shutdown();
}
public InetIPv6Util(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.inetIPV6Util");
thread.setDaemon(true);
return thread;
});
}
public InetUtils.HostInfo findFirstNonLoopbackHostInfo() {
InetAddress address = this.findFirstNonLoopbackIPv6Address();
if (address != null) {
return this.convertAddress(address);
}
return null;
private InetUtils.HostInfo findFirstValidHostInfo() {
InetAddress address = this.findFirstValidIPv6Address();
return address != null ? this.getHostInfo(address) : null;
}
public InetAddress findFirstNonLoopbackIPv6Address() {
private InetAddress findFirstValidIPv6Address() {
InetAddress address = null;
try {
int lowest = Integer.MAX_VALUE;
for (Enumeration<NetworkInterface> nics = NetworkInterface
.getNetworkInterfaces(); nics.hasMoreElements();) {
.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 (ifc.isUp() || !ifc.isVirtual() || !ifc.isLoopback()) {
if (address != null) {
break;
}
if (!ignoreInterface(ifc.getDisplayName())) {
for (Enumeration<InetAddress> addrs = ifc
.getInetAddresses(); addrs.hasMoreElements();) {
.getInetAddresses(); addrs.hasMoreElements(); ) {
InetAddress inetAddress = addrs.nextElement();
if (inetAddress instanceof Inet6Address
// filter ::1
&& !inetAddress.isLoopbackAddress()
// filter fe80::/10
&& !inetAddress.isLinkLocalAddress()
// filter ::/128
&& !inetAddress.isAnyLocalAddress()
// filter fec0::/10,which was discarded, but some
// address may be deployed.
&& !inetAddress.isSiteLocalAddress()
// filter fd00::/8
&& !isUniqueLocalAddress(inetAddress)
&& isPreferredAddress(inetAddress)) {
log.trace("Found non-loopback interface: "
+ ifc.getDisplayName());
address = inetAddress;
break;
}
}
}
@ -106,40 +91,22 @@ public class InetIPv6Util implements Closeable {
catch (IOException e) {
log.error("Cannot get first non-loopback address", e);
}
if (address == null) {
try {
InetAddress localHost = InetAddress.getLocalHost();
if (localHost instanceof Inet6Address && !localHost.isLoopbackAddress()
&& isPreferredAddress(localHost)) {
address = localHost;
}
}
catch (UnknownHostException e) {
log.warn("Unable to retrieve localhost");
}
}
return address;
}
public String findIPv6Address() {
InetUtils.HostInfo hostInfo = findFirstNonLoopbackHostInfo();
String ip = hostInfo != null ? hostInfo.getIpAddress() : "";
if (!StringUtils.isEmpty(ip)) {
int index = ip.indexOf('%');
ip = index > 0 ? ip.substring(0, index) : ip;
return normalizeIPv6(ip);
}
return ip;
InetUtils.HostInfo hostInfo = findFirstValidHostInfo();
return hostInfo != null ? normalizeIPv6(hostInfo.getIpAddress()) : null;
}
public String normalizeIPv6(String ip) {
private String normalizeIPv6(String ip) {
// Remove the suffix of network card in IPv6 address, such as
// 2408:400a:8c:5400:6578:5c42:77b1:bc5d%eth0
int idx = ip.indexOf("%");
return idx != -1 ? "[" + ip.substring(0, idx) + "]" : "[" + ip + "]";
}
boolean isPreferredAddress(InetAddress address) {
private boolean isPreferredAddress(InetAddress address) {
if (this.properties.isUseOnlySiteLocalInterfaces()) {
final boolean siteLocalAddress = address.isSiteLocalAddress();
if (!siteLocalAddress) {
@ -157,35 +124,43 @@ public class InetIPv6Util implements Closeable {
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) {
private InetUtils.HostInfo getHostInfo(final InetAddress address) {
InetUtils.HostInfo hostInfo = new InetUtils.HostInfo();
Future<String> result = this.executorService.submit(address::getHostName);
String hostname;
try {
hostname = result.get(this.properties.getTimeoutSeconds(), TimeUnit.SECONDS);
String hostName = address.getHostName();
if (hostName == null) {
hostName = "localhost";
}
catch (Exception e) {
log.info("Cannot determine local hostname");
hostname = "localhost";
hostInfo.setHostname(hostName);
if (StringUtils.isNotEmpty(address.getHostAddress())) {
hostInfo.setIpAddress(address.getHostAddress());
}
else {
hostInfo.setIpAddress(StringUtils.EMPTY);
}
hostInfo.setHostname(hostname);
hostInfo.setIpAddress(address.getHostAddress());
return hostInfo;
}
/**
* If the address is Unique Local Address.
*
* @param inetAddress {@link InetAddress}
* @return {@code true} if the address is Unique Local Address, otherwise {@code false}
*/
private boolean isUniqueLocalAddress(InetAddress inetAddress) {
byte[] ip = inetAddress.getAddress();
return (ip[0] & 0xff) == 0xfd;
}
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.alibaba.cloud.nacos.utils;
package com.alibaba.cloud.nacos.util;
import com.alibaba.cloud.nacos.ConditionalOnNacosDiscoveryEnabled;
@ -37,8 +37,8 @@ public class UtilIPv6AutoConfiguration {
@Bean
@ConditionalOnMissingBean
public InetIPv6Util inetIPv6Util(InetUtilsProperties properties) {
return new InetIPv6Util(properties);
public InetIPv6Utils inetIPv6Utils(InetUtilsProperties properties) {
return new InetIPv6Utils(properties);
}
}

@ -7,7 +7,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfiguration,\
com.alibaba.cloud.nacos.loadbalancer.LoadBalancerNacosAutoConfiguration,\
com.alibaba.cloud.nacos.NacosServiceAutoConfiguration,\
com.alibaba.cloud.nacos.utils.UtilIPv6AutoConfiguration
com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration
org.springframework.boot.SpringApplicationRunListener=\

@ -18,7 +18,7 @@ package com.alibaba.cloud.nacos.discovery;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
import com.alibaba.cloud.nacos.utils.UtilIPv6AutoConfiguration;
import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;

@ -18,7 +18,7 @@ package com.alibaba.cloud.nacos.discovery;
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
import com.alibaba.cloud.nacos.registry.NacosServiceRegistryAutoConfiguration;
import com.alibaba.cloud.nacos.utils.UtilIPv6AutoConfiguration;
import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;

@ -18,7 +18,7 @@ package com.alibaba.cloud.nacos.discovery.reactive;
import com.alibaba.cloud.nacos.NacosServiceAutoConfiguration;
import com.alibaba.cloud.nacos.discovery.NacosDiscoveryAutoConfiguration;
import com.alibaba.cloud.nacos.utils.UtilIPv6AutoConfiguration;
import com.alibaba.cloud.nacos.util.UtilIPv6AutoConfiguration;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;

Loading…
Cancel
Save