Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 185 additions & 24 deletions shenyu-common/src/main/java/org/apache/shenyu/common/utils/IpUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,19 @@

package org.apache.shenyu.common.utils;

import java.io.Serializable;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.SocketException;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;
import java.util.Comparator;

/**
* The type Ip utils.
Expand All @@ -32,6 +41,11 @@ public final class IpUtils {
*/
private static final Pattern IP_PATTERN = Pattern.compile("^((25[0-5]|2[0-4]\\d|[01]?\\d\\d?)($|(?!\\.$)\\.)){4}$");

/**
* net card pattern.
*/
private static final Pattern NET_CARD_PATTERN = Pattern.compile("(\\d+)$");

private IpUtils() {
}

Expand All @@ -51,43 +65,103 @@ public static String getHost() {
* @return the host
*/
public static String getHost(final String filterHost) {
String firstHostIp = null;
String hostIp = null;
String pattern = filterHost;
// I think this function is only support ipv4.
if (filterHost != null && !filterHost.contains("*") && !isCompleteHost(filterHost)) {
// filter matching ip
if ("*".equals(filterHost) || "".equals(filterHost)) {
pattern = null;
} else if (filterHost != null && !filterHost.contains("*") && !isCompleteHost(filterHost)) {
pattern = filterHost + "*";
}

// if the progress works under docker environment
// return the host ip about this docker located from environment value
String dockerHostIp = System.getenv("docker_host_ip");
if (dockerHostIp != null && !"".equals(dockerHostIp)) {
return dockerHostIp;
}

// Traversal Network interface to scan all network interface
List<NetCard> ipv4Result = new ArrayList<>();
List<NetCard> ipv6Result = new ArrayList<>();
NetCard netCard;
try {
Enumeration<?> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
NetworkInterface network = (NetworkInterface) networkInterfaces.nextElement();
Enumeration<?> addresses = network.getInetAddresses();
Enumeration<NetworkInterface> enumeration = NetworkInterface.getNetworkInterfaces();
while (enumeration.hasMoreElements()) {
final NetworkInterface networkInterface = enumeration.nextElement();
Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
while (addresses.hasMoreElements()) {
InetAddress inetAddress = (InetAddress) addresses.nextElement();
String hostAddress = inetAddress.getHostAddress();
if (hostAddress.contains(".") && !inetAddress.isLoopbackAddress()) {
if (firstHostIp == null) {
firstHostIp = hostAddress;
if (filterHost == null) {
break;
}
}
if (pattern != null && ipMatch(hostAddress, pattern)) {
hostIp = hostAddress;
InetAddress inetAddress = addresses.nextElement();
if (inetAddress != null && !inetAddress.isLoopbackAddress()) {
if (inetAddress instanceof Inet4Address && isCompleteHost(inetAddress.getHostAddress())) {
netCard = new NetCard(inetAddress.getHostAddress(),
getName(networkInterface.getName()),
getNamePostfix(networkInterface.getName()),
Integer.parseInt(inetAddress.getHostAddress().split("\\.")[3]));
ipv4Result.add(netCard);
} else {
netCard = new NetCard(inetAddress.getHostAddress(),
getName(networkInterface.getName()),
getNamePostfix(networkInterface.getName()));
ipv6Result.add(netCard);
}
}
}
}

if (hostIp == null && firstHostIp != null) {
hostIp = firstHostIp;
// priority of networkInterface when generating client ip
String priority = System.getProperty("networkInterface.priority", "enp<eth<bond");
List<String> preferList = new ArrayList<>(Arrays.asList(priority.split("<")));
// sort ip
Comparator<NetCard> byName = new Comparator<NetCard>() {
@Override
public int compare(final NetCard card1, final NetCard card2) {
int card1Score = -1;
int card2Score = -1;
for (String pre : preferList) {
if (card1.getName().contains(pre)) {
card1Score = preferList.indexOf(pre);
break;
}
}
for (String pre : preferList) {
if (card2.getName().contains(pre)) {
card2Score = preferList.indexOf(pre);
break;
}
}
return card2Score - card1Score;
}
};
Comparator<NetCard> byNamePostfix = Comparator.comparing(NetCard::getNamePostfix);
Comparator<NetCard> byIpv4Postfix = new Comparator<NetCard>() {
@Override
public int compare(final NetCard card1, final NetCard card2) {
return card2.getIpv4Postfix() - card1.getIpv4Postfix();
}
};
ipv4Result.sort(byName.thenComparing(byNamePostfix).thenComparing(byIpv4Postfix));
ipv6Result.sort(byName.thenComparing(byNamePostfix));
// prefer ipv4
if (!ipv4Result.isEmpty()) {
if (pattern != null) {
for (NetCard card : ipv4Result) {
if (ipMatch(card.getIp(), pattern)) {
hostIp = card.getIp();
break;
}
}
} else {
hostIp = ipv4Result.get(0).getIp();
}
} else if (!ipv6Result.isEmpty()) {
hostIp = ipv6Result.get(0).getIp();
}

// If failed to find,fall back to localhost
if (hostIp == null) {
hostIp = InetAddress.getLocalHost().getHostAddress();
}
} catch (Exception ignore) {
} catch (SocketException | UnknownHostException ignore) {
hostIp = "127.0.0.1";
}
return hostIp;
Expand All @@ -109,7 +183,7 @@ public static boolean isCompleteHost(final String host) {
/**
* do ip match.
*
* @param ip network ip
* @param ip network ip
* @param pattern match pattern
* @return boolean
*/
Expand All @@ -136,4 +210,91 @@ private static boolean ipMatch(final String ip, final String pattern) {
}
return dp[m][n];
}

/**
* To obtain a prefix.
*
* @param name network interface name
* @return the name
*/
private static String getName(final String name) {
Matcher matcher = NET_CARD_PATTERN.matcher(name);
if (matcher.find()) {
return name.replace(matcher.group(), "");
}
return name;
}

/**
* Get the last number.
*
* @param name network interface name
* @return the name postfix
*/
private static Integer getNamePostfix(final String name) {
Matcher matcher = NET_CARD_PATTERN.matcher(name);
if (matcher.find()) {
return Integer.parseInt(matcher.group());
}
return -1;
}

private static class NetCard implements Serializable {

private String ip;

private String name;

private Integer namePostfix;

private Integer ipv4Postfix;

NetCard() {
}

NetCard(final String ip, final String name, final Integer namePostfix) {
this.ip = ip;
this.name = name;
this.namePostfix = namePostfix;
}

NetCard(final String ip, final String name, final Integer namePostfix, final Integer postfix) {
this.ip = ip;
this.name = name;
this.namePostfix = namePostfix;
this.ipv4Postfix = postfix;
}

public String getIp() {
return ip;
}

public void setIp(final String ip) {
this.ip = ip;
}

public String getName() {
return name;
}

public void setName(final String name) {
this.name = name;
}

public Integer getIpv4Postfix() {
return ipv4Postfix;
}

public Integer getNamePostfix() {
return namePostfix;
}

public void setNamePostfix(final Integer namePostfix) {
this.namePostfix = namePostfix;
}

public void setIpv4Postfix(final Integer ipv4Postfix) {
this.ipv4Postfix = ipv4Postfix;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,63 @@ public void close() {

@Test
public void testGetHost() throws Exception {
Vector<InetAddress> addresses = new Vector<>();
addresses.add(InetAddress.getByAddress("local", new byte[]{(byte) 192, (byte) 168, (byte) 50, (byte) 66}));
addresses.add(InetAddress.getByAddress("eth0", new byte[]{(byte) 172, (byte) 168, (byte) 166, (byte) 12}));
addresses.add(InetAddress.getByAddress("eth1", new byte[]{(byte) 10, (byte) 150, (byte) 111, (byte) 66}));
NetworkInterface nic = mock(NetworkInterface.class);
when(nic.getInetAddresses()).thenReturn(addresses.elements());
// first net card
Vector<InetAddress> addresses1 = new Vector<>();
addresses1.add(InetAddress.getByAddress("local-host", new byte[]{(byte) 192, (byte) 168, (byte) 50, (byte) 66}));
NetworkInterface nic1 = mock(NetworkInterface.class);
when(nic1.getInetAddresses()).thenReturn(addresses1.elements());
when(nic1.getName()).thenReturn("local");
// second net card
Vector<InetAddress> addresses2 = new Vector<>();
addresses2.add(InetAddress.getByAddress("eth0-host", new byte[]{(byte) 172, (byte) 168, (byte) 166, (byte) 12}));
NetworkInterface nic2 = mock(NetworkInterface.class);
when(nic2.getInetAddresses()).thenReturn(addresses2.elements());
when(nic2.getName()).thenReturn("eth0");
// third net card
Vector<InetAddress> addresses3 = new Vector<>();
addresses3.add(InetAddress.getByAddress("eth1-host", new byte[]{(byte) 10, (byte) 150, (byte) 111, (byte) 66}));
NetworkInterface nic3 = mock(NetworkInterface.class);
when(nic3.getInetAddresses()).thenReturn(addresses3.elements());
when(nic3.getName()).thenReturn("eth1");
// add all
Vector<NetworkInterface> nics = new Vector<>();
nics.add(nic);
nics.add(nic1);
nics.add(nic2);
nics.add(nic3);
networkInterfaceMockedStatic.when((MockedStatic.Verification) NetworkInterface.getNetworkInterfaces()).thenReturn(nics.elements());
String prefix1 = "172.168";
assertEquals("172.168.166.12", IpUtils.getHost(prefix1));
}

@Test
public void testGetHostHasNotMatchPrefix() throws Exception {
// first net card
Vector<InetAddress> addresses1 = new Vector<>();
addresses1.add(InetAddress.getByAddress("local-host", new byte[]{(byte) 192, (byte) 168, (byte) 50, (byte) 66}));
NetworkInterface nic1 = mock(NetworkInterface.class);
when(nic1.getInetAddresses()).thenReturn(addresses1.elements());
when(nic1.getName()).thenReturn("local");
// second net card
Vector<InetAddress> addresses2 = new Vector<>();
addresses2.add(InetAddress.getByAddress("eth0-host", new byte[]{(byte) 172, (byte) 168, (byte) 166, (byte) 12}));
NetworkInterface nic2 = mock(NetworkInterface.class);
when(nic2.getInetAddresses()).thenReturn(addresses2.elements());
when(nic2.getName()).thenReturn("eth0");
// third net card
Vector<InetAddress> addresses3 = new Vector<>();
addresses3.add(InetAddress.getByAddress("eth1-host", new byte[]{(byte) 10, (byte) 150, (byte) 111, (byte) 66}));
NetworkInterface nic3 = mock(NetworkInterface.class);
when(nic3.getInetAddresses()).thenReturn(addresses3.elements());
when(nic3.getName()).thenReturn("eth1");
// add all
Vector<NetworkInterface> nics = new Vector<>();
nics.add(nic1);
nics.add(nic2);
nics.add(nic3);
networkInterfaceMockedStatic.when((MockedStatic.Verification) NetworkInterface.getNetworkInterfaces()).thenReturn(nics.elements());
assertEquals("172.168.166.12", IpUtils.getHost());
}

@Test
public void testIsCompleteHost() {
assertTrue(IpUtils.isCompleteHost("192.168.1.166"));
Expand Down