diff options
| author | shizhendong <[email protected]> | 2022-04-02 15:15:17 +0800 |
|---|---|---|
| committer | shizhendong <[email protected]> | 2022-04-02 15:15:17 +0800 |
| commit | c5b0bfc33785617a801ebbf6292ecd6199363cdd (patch) | |
| tree | 927235f65e117021df796bdf904012f27ea1212b /src | |
| parent | b6f059255b8ac6c8200d15ab79697097f43fd7c0 (diff) | |
feat: NEZ-1746 agent 增加 ping,traceroute 命令执行接口
Diffstat (limited to 'src')
5 files changed, 713 insertions, 5 deletions
diff --git a/src/main/java/net/geedge/confagent/controller/PingController.java b/src/main/java/net/geedge/confagent/controller/PingController.java new file mode 100644 index 0000000..1960111 --- /dev/null +++ b/src/main/java/net/geedge/confagent/controller/PingController.java @@ -0,0 +1,176 @@ +package net.geedge.confagent.controller; + +import cn.hutool.core.lang.Pair; +import cn.hutool.core.thread.ThreadFactoryBuilder; +import cn.hutool.core.util.ReUtil; +import cn.hutool.log.Log; +import net.geedge.confagent.entity.PingEntity; +import net.geedge.confagent.util.CommonUtils; +import net.geedge.confagent.util.R; +import net.geedge.confagent.util.Tool; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.concurrent.*; +import java.util.regex.Pattern; + +@RestController +@RequestMapping("/cmd") +public class PingController { + + private final static Log log = Log.get(); + + static Integer defaultCorePoolSize = 10; + + static ThreadPoolExecutor execPingThreadPoolExecutor; + + // windows ipv4/6 匹配 最短 = 3ms,最长 = 6ms,平均 = 4ms + static Pattern WinPingStatRegex = Pattern.compile("(.{2} = \\d+ms)"); + // windows ipv4/6 匹配 25% 丢失 + static Pattern WinPingRateRegex = Pattern.compile("\\d+(\\.\\d+)?% 丢失"); + // linux ipv4/6 匹配 rtt min/avg/max/mdev = 0.788/1.296/1.627/0.319 ms + static Pattern LinuxPingStatRegex = Pattern.compile("(min/avg/max.*=.*ms)"); + // linux ipv4/6 匹配 25% packet loss + static Pattern LinuxPingRateRegex = Pattern.compile("\\d+(\\.\\d+)?% packet loss"); + + static { + execPingThreadPoolExecutor = new ThreadPoolExecutor(defaultCorePoolSize, Integer.MAX_VALUE, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), new ThreadFactoryBuilder().setNamePrefix("ping-pool-").build()); + } + + @PostMapping("/ping") + public R ping(@RequestBody PingEntity pingEntity) throws UnknownHostException { + Integer packetsize = Tool.ObjectUtil.defaultIfNull(pingEntity.getPacketsize(), 64); + Integer count = Tool.ObjectUtil.defaultIfNull(pingEntity.getCount(), 4); + Integer timeout = Tool.ObjectUtil.defaultIfNull(pingEntity.getTimeout(), 100); + Integer concurrent = Tool.ObjectUtil.defaultIfNull(pingEntity.getConcurrent(), 10); + + List<Callable<Map<String, Object>>> taskList = Tool.ListUtil.list(false); + + // 获取本地 IP 当作 source ip + String sourceIp = Tool.InetAddressUtil.getLocalHostLANAddress(); + List<String> ips = pingEntity.getIps(); + + for (String ip : ips) { + if (CommonUtils.isLinux()) { + String pingCmd = null; + if (CommonUtils.checkIpv4(ip)) { + pingCmd = String.format("ping -c %s -s %s -W %s %s", count, packetsize, (double) timeout / 1000, ip); + } else if (CommonUtils.checkIpv6(ip)) { + pingCmd = String.format("ping -6 -c %s -s %s -W %s %s", count, packetsize, (double) timeout / 1000, ip); + } else { + // 都没有匹配就执行IPV4 + pingCmd = String.format("ping -c %s -s %s -W %s %s", count, packetsize, (double) timeout / 1000, ip); + } + log.info("ping cmd : {}", pingCmd); + Callable<Map<String, Object>> callable = this.getLinuxPingCallable(ip, pingCmd, sourceIp); + taskList.add(callable); + } else if (CommonUtils.isWindows()) { + String pingCmd = null; + if (CommonUtils.checkIpv4(ip)) { + pingCmd = String.format("ping -n %s -l %s -w %s %s", count, packetsize, timeout, ip); + } else if (CommonUtils.checkIpv6(ip)) { + pingCmd = String.format("ping -6 -n %s -l %s -w %s %s", count, packetsize, timeout, ip); + } else { + // 都没有匹配就执行IPV4 + pingCmd = String.format("ping -n %s -l %s -w %s %s", count, packetsize, timeout, ip); + } + log.info("ping cmd : {}", pingCmd); + Callable<Map<String, Object>> callable = this.getWinPingCallable(ip, pingCmd, sourceIp); + taskList.add(callable); + } + } + + List<Map<String, Object>> result = Tool.ListUtil.list(false); + boolean b = false; + try { + if (concurrent > execPingThreadPoolExecutor.getCorePoolSize()) { + // 修改线程池核心线程数 + execPingThreadPoolExecutor.setCorePoolSize(concurrent); + b = true; + } + List<Future<Map<String, Object>>> futures = ((ExecutorService) execPingThreadPoolExecutor).invokeAll(taskList); + for (Future<Map<String, Object>> future : futures) { + if (!future.isCancelled()) { + Map<String, Object> map = future.get(); + result.add(map); + } + } + } catch (InterruptedException | ExecutionException e) { + log.error(e); + } finally { + // 如果修改了核心线程数 ,本次执行后恢复初始数量 + if (b) execPingThreadPoolExecutor.setCorePoolSize(defaultCorePoolSize); + } + + return R.ok().put("data", Tool.MapUtil.of(Pair.of("list", result))); + } + + private Callable<Map<String, Object>> getWinPingCallable(String ip, String pingCmd, String sourceIp) { + Callable<Map<String, Object>> callable = () -> { + Map<String, Object> stat = Tool.MapUtil.newHashMap(); + String forStr = Tool.RuntimeUtil.execForStr(pingCmd); + List<String> stringList = ReUtil.findAllGroup0(WinPingStatRegex, forStr); + if (Tool.CollectionUtil.isEmpty(stringList)) { + stat.put("min", 0); + stat.put("max", 0); + stat.put("avg", 0); + // 没有匹配到 min max avg 数据,证明百分百丢包 windows 如果ping 全部失败返回为 0 ,这里不取他返回的数据,全部失败丢包率为 100% + stat.put("rate", 100); + stat.put("state", 0); + } else { + stat.put("min", ReUtil.getFirstNumber(stringList.get(0))); + stat.put("max", ReUtil.getFirstNumber(stringList.get(1))); + stat.put("avg", ReUtil.getFirstNumber(stringList.get(2))); + String rateStr = ReUtil.getGroup0(WinPingRateRegex, forStr); + Double rateDoubleValue = Double.valueOf(rateStr.split("%")[0]); + stat.put("rate", rateDoubleValue); + // 丢包率为0,state = up 否则为 error + stat.put("state", rateDoubleValue == 0 ? 1 : 2); + } + stat.put("raw", forStr); + stat.put("ip", ip); + stat.put("source", sourceIp); + return stat; + }; + return callable; + } + + private Callable<Map<String, Object>> getLinuxPingCallable(String ip, String pingCmd, String sourceIp) { + Callable<Map<String, Object>> callable = () -> { + Map<String, Object> stat = Tool.MapUtil.newHashMap(); + String forStr = Tool.RuntimeUtil.execForStr(pingCmd); + String group0 = ReUtil.getGroup0(LinuxPingStatRegex, forStr); + if (Tool.StrUtil.isEmpty(group0)) { + stat.put("min", 0); + stat.put("max", 0); + stat.put("avg", 0); + stat.put("rate", 100); + stat.put("state", 0); + } else { + List<String> strings = Arrays.asList(group0.split("=")); + List<String> minAvgMaxList = Arrays.asList(strings.get(1).trim().split("/")); + stat.put("min", Double.valueOf(minAvgMaxList.get(0))); + stat.put("max", Double.valueOf(minAvgMaxList.get(2))); + stat.put("avg", Double.valueOf(minAvgMaxList.get(1))); + String rateStr = ReUtil.getGroup0(LinuxPingRateRegex, forStr); + Double rateDoubleValue = Double.valueOf(rateStr.split("%")[0]); + // 丢包率为0,state = up 否则为 error + stat.put("state", rateDoubleValue == 0 ? 1 : 2); + } + + stat.put("raw", forStr); + stat.put("ip", ip); + stat.put("source", sourceIp); + return stat; + }; + return callable; + } +} diff --git a/src/main/java/net/geedge/confagent/controller/TracerouteController.java b/src/main/java/net/geedge/confagent/controller/TracerouteController.java new file mode 100644 index 0000000..0b8a561 --- /dev/null +++ b/src/main/java/net/geedge/confagent/controller/TracerouteController.java @@ -0,0 +1,125 @@ +package net.geedge.confagent.controller; + +import cn.hutool.core.date.TimeInterval; +import cn.hutool.core.lang.Pair; +import cn.hutool.core.thread.ThreadFactoryBuilder; +import cn.hutool.log.Log; +import net.geedge.confagent.entity.PingEntity; +import net.geedge.confagent.util.CommonUtils; +import net.geedge.confagent.util.R; +import net.geedge.confagent.util.Tool; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.net.UnknownHostException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.*; + +@RestController +@RequestMapping("/cmd") +public class TracerouteController { + + private final static Log log = Log.get(); + + static Integer defaultCorePoolSize = 10; + + static ThreadPoolExecutor execTracerouteThreadPoolExecutor; + + static { + execTracerouteThreadPoolExecutor = new ThreadPoolExecutor(defaultCorePoolSize, Integer.MAX_VALUE, + 0L, TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<Runnable>(), new ThreadFactoryBuilder().setNamePrefix("traceroute-pool-").build()); + } + + @PostMapping("/traceroute") + public R traceroute(@RequestBody PingEntity pingEntity) throws UnknownHostException { + // Linux 可以指定 package size ,win 不行 + Integer packetsize = Tool.ObjectUtil.defaultIfNull(pingEntity.getPacketsize(), 64); + Integer maxHops = Tool.ObjectUtil.defaultIfNull(pingEntity.getMaxHops(), 10); + // win 单位 ms,,linux 单位 s,(支持浮点数) + Integer timeout = Tool.ObjectUtil.defaultIfNull(pingEntity.getTimeout(), 100); + Integer concurrent = Tool.ObjectUtil.defaultIfNull(pingEntity.getConcurrent(), 10); + + List<Callable<Map<String, Object>>> taskList = Tool.ListUtil.list(false); + + // 获取本地 IP 当作 source ip + String sourceIp = Tool.InetAddressUtil.getLocalHostLANAddress(); + + List<String> ips = pingEntity.getIps(); + for (String ip : ips) { + if (CommonUtils.isLinux()) { + String tracerouteCmd = null; + if (CommonUtils.checkIpv4(ip)) { + tracerouteCmd = String.format("traceroute -4 -m %s -w %s %s %s", maxHops, (double) timeout / 1000, ip, packetsize); + } else if (CommonUtils.checkIpv6(ip)) { + tracerouteCmd = String.format("traceroute -6 -m %s -w %s %s %s", maxHops, (double) timeout / 1000, ip, packetsize); + } else { + // 都没有匹配就执行IPV4 + tracerouteCmd = String.format("traceroute -4 -m %s -w %s %s %s", maxHops, (double) timeout / 1000, ip, packetsize); + } + log.info("traceroute cmd : {}", tracerouteCmd); + Callable<Map<String, Object>> callable = this.getTracerouteCallable(ip, tracerouteCmd, sourceIp); + taskList.add(callable); + } else if (CommonUtils.isWindows()) { + String tracerouteCmd = null; + if (CommonUtils.checkIpv4(ip)) { + tracerouteCmd = String.format("tracert -4 -h %s -w %s %s", maxHops, timeout, ip); + } else if (CommonUtils.checkIpv6(ip)) { + tracerouteCmd = String.format("tracert -6 -h %s -w %s %s", maxHops, timeout, ip); + } else { + // 都没有匹配就执行IPV4 + tracerouteCmd = String.format("tracert -4 -h %s -w %s %s", maxHops, timeout, ip); + } + log.info("traceroute cmd : {}", tracerouteCmd); + Callable<Map<String, Object>> callable = this.getTracerouteCallable(ip, tracerouteCmd, sourceIp); + taskList.add(callable); + } + } + + List<Map<String, Object>> result = Tool.ListUtil.list(false); + boolean b = false; + try { + if (concurrent > execTracerouteThreadPoolExecutor.getCorePoolSize()) { + // 修改线程池核心线程数 + execTracerouteThreadPoolExecutor.setCorePoolSize(concurrent); + b = true; + } + List<Future<Map<String, Object>>> futures = ((ExecutorService) execTracerouteThreadPoolExecutor).invokeAll(taskList); + for (Future<Map<String, Object>> future : futures) { + if (!future.isCancelled()) { + Map<String, Object> map = future.get(); + result.add(map); + } + } + } catch (InterruptedException | ExecutionException e) { + log.error(e); + } finally { + // 如果修改了核心线程数 ,本次执行后恢复初始数量 + if (b) execTracerouteThreadPoolExecutor.setCorePoolSize(defaultCorePoolSize); + } + + return R.ok().put("data", Tool.MapUtil.of(Pair.of("list", result))); + } + + private Callable<Map<String, Object>> getTracerouteCallable(String ip, String tracerouteCmd, String sourceIp) { + Callable<Map<String, Object>> callable = () -> { + Map<String, Object> stat = Tool.MapUtil.newHashMap(); + TimeInterval timer = Tool.DateUtil.timer(); + Process process = Tool.RuntimeUtil.exec(tracerouteCmd); + String result = Tool.RuntimeUtil.getResult(process); + stat.put("time", timer.interval()); + // {0} indicates normal termination. + int i = process.waitFor(); + stat.put("state", i == 0 ? 1 : 0); + stat.put("raw", result); + stat.put("ip", ip); + stat.put("source", sourceIp); + return stat; + }; + return callable; + } + +} diff --git a/src/main/java/net/geedge/confagent/entity/PingEntity.java b/src/main/java/net/geedge/confagent/entity/PingEntity.java new file mode 100644 index 0000000..5a105a4 --- /dev/null +++ b/src/main/java/net/geedge/confagent/entity/PingEntity.java @@ -0,0 +1,44 @@ +package net.geedge.confagent.entity; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +@Data +public class PingEntity implements Serializable { + + private static final long serialVersionUID = 1L; + /** + * ip地址 + */ + private List<String> ips; + + /** + * 包大小 + * 默认:64 + */ + private Integer packetsize; + + /** + * 执行次数 + * 默认:4 + */ + private Integer count; + + /** + * 超时时间 + * 默认:10s + */ + private Integer timeout; + + /** + * 并发线程数量,默认:10 + */ + private Integer concurrent; + + /** + * maxHops + */ + private Integer maxHops; +} diff --git a/src/main/java/net/geedge/confagent/util/CommonUtils.java b/src/main/java/net/geedge/confagent/util/CommonUtils.java new file mode 100644 index 0000000..65e2cef --- /dev/null +++ b/src/main/java/net/geedge/confagent/util/CommonUtils.java @@ -0,0 +1,320 @@ +package net.geedge.confagent.util; + +import cn.hutool.core.net.NetUtil; + +import java.io.File; +import java.net.URL; +import java.util.*; +import java.util.regex.Pattern; + +/** + * 公用方法工具类 + */ +public class CommonUtils { + private static String OS = System.getProperty("os.name").toLowerCase(); + + /** + * 非空判断 + * + * @param objs 要判断,处理的对象 + * @return Boolean + * @author <a href="mailto:[email protected]">Ben</a> + * @see <b>对象为Null返回true,集合的大小为0也返回true,迭代器没有下一个也返回true..</b> + * @since 1.0 + */ + public static Boolean isEmpty(Object... objs) { + + if (objs == null) { + return Boolean.TRUE; + } + + if (objs.length == 0) return Boolean.TRUE; + + for (Object obj : objs) { + if (obj == null) { + return true; + } + + // 字符序列集 + if ((obj instanceof CharSequence) && "".equals(obj.toString().trim())) { + return true; + } + // 单列集合 + if (obj instanceof Collection) { + if (((Collection<?>) obj).isEmpty()) { + return true; + } + } + // 双列集合 + if (obj instanceof Map) { + if (((Map<?, ?>) obj).isEmpty()) { + return true; + } + } + if (obj instanceof Iterable) { + if (((Iterable<?>) obj).iterator() == null || !((Iterable<?>) obj).iterator().hasNext()) { + return true; + } + } + // 迭代器 + if (obj instanceof Iterator) { + if (!((Iterator<?>) obj).hasNext()) { + return true; + } + } + // 文件类型 + if (obj instanceof File) { + if (!((File) obj).exists()) { + return true; + } + } + if ((obj instanceof Object[]) && ((Object[]) obj).length == 0) { + return true; + } + } + return false; + } + + /** + * 空判断 + * + * @param obj 要判断,处理的对象 + * @return Boolean + * @author <a href="mailto:[email protected]">Ben</a> + * @see <b>与非空相反</b> + * @since 1.0 + */ + public static Boolean notEmpty(Object... obj) { + return !isEmpty(obj); + } + + + public static <A, E extends A> A[] toArray(Enumeration<E> enumeration, A[] array) { + ArrayList<A> elements = new ArrayList<A>(); + while (enumeration.hasMoreElements()) { + elements.add(enumeration.nextElement()); + } + return elements.toArray(array); + } + + /** + * @Description 根据相对路径获取根目录下的文件 + * @Date 2021/4/23 + */ + public static File getResourceFile(String path) { + File file = Tool.FileUtil.newFile(path); + if (file.exists()) { + return file; + } else { + URL resource = CommonUtils.class.getClassLoader().getResource(path); + return resource == null ? null : Tool.FileUtil.newFile(resource.getFile()); + } + } + + public static boolean isLinux() { + return OS.indexOf("linux") >= 0; + } + + public static boolean isMacOS() { + return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") < 0; + } + + public static boolean isMacOSX() { + return OS.indexOf("mac") >= 0 && OS.indexOf("os") > 0 && OS.indexOf("x") > 0; + } + + public static boolean isWindows() { + return OS.indexOf("windows") >= 0; + } + + public static boolean isOS2() { + return OS.indexOf("os/2") >= 0; + } + + public static boolean isSolaris() { + return OS.indexOf("solaris") >= 0; + } + + public static boolean isSunOS() { + return OS.indexOf("sunos") >= 0; + } + + public static boolean isMPEiX() { + return OS.indexOf("mpe/ix") >= 0; + } + + public static boolean isHPUX() { + return OS.indexOf("hp-ux") >= 0; + } + + public static boolean isAix() { + return OS.indexOf("aix") >= 0; + } + + public static boolean isOS390() { + return OS.indexOf("os/390") >= 0; + } + + public static boolean isFreeBSD() { + return OS.indexOf("freebsd") >= 0; + } + + public static boolean isIrix() { + return OS.indexOf("irix") >= 0; + } + + public static boolean isDigitalUnix() { + return OS.indexOf("digital") >= 0 && OS.indexOf("unix") > 0; + } + + public static boolean isNetWare() { + return OS.indexOf("netware") >= 0; + } + + public static boolean isOSF1() { + return OS.indexOf("osf1") >= 0; + } + + public static boolean isOpenVMS() { + return OS.indexOf("openvms") >= 0; + } + + public static boolean isUnix() { + boolean isUnix = isLinux(); + if (!isUnix) { + isUnix = isMacOS(); + } + if (!isUnix) { + isUnix = isMacOSX(); + } + if (!isUnix) { + isUnix = isLinux(); + } + if (!isUnix) { + isUnix = isDigitalUnix(); + } + if (!isUnix) { + isUnix = isAix(); + } + if (!isUnix) { + isUnix = isFreeBSD(); + } + if (!isUnix) { + isUnix = isHPUX(); + } + if (!isUnix) { + isUnix = isIrix(); + } + if (!isUnix) { + isUnix = isMPEiX(); + } + if (!isUnix) { + isUnix = isNetWare(); + } + if (!isUnix) { + isUnix = isOpenVMS(); + } + if (!isUnix) { + isUnix = isOS2(); + } + if (!isUnix) { + isUnix = isOS390(); + } + if (!isUnix) { + isUnix = isOSF1(); + } + if (!isUnix) { + isUnix = isSunOS(); + } + if (!isUnix) { + isUnix = isSolaris(); + } + return isUnix; + } + + /** + * linux内核平台 1 + * window: 2 + * 其他平台 0 + */ + public static int getPlatform() { + int platform = 0; + if (CommonUtils.isUnix()) { + platform = 1; + } + if (CommonUtils.isWindows()) { + platform = 2; + } + return platform; + } + + public static String uuid() { + return UUID.randomUUID().toString().replaceAll("-", ""); + } + + /** + * 生成指定长度的uuid + * + * @param len + * @return + */ + public static String uuid(int len) { + StringBuffer sb = new StringBuffer(); + while (sb.length() < len) { + sb.append(uuid()); + } + return sb.toString().substring(0, len); + } + + /** + * 获取本机所有网卡IP + * + * @return + */ + public static Set<String> getInetIpAddress() { + return NetUtil.localIpv4s(); + } + + + /** + * 端口合法性校验 + * + * @param port + * @return + */ + public static boolean checkPort(String port) { + String regex = "^[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]{1}|6553[0-5]$"; + boolean flag = Pattern.matches(regex, port.toString()); + return flag; + } + + public static boolean checkIp(String ip) { + Pattern ipv6Check = Pattern.compile("^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:)|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}(:[0-9A-Fa-f]{1,4}){1,2})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){1,3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){1,4})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){1,5})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){1,6})|(:(:[0-9A-Fa-f]{1,4}){1,7})|(([0-9A-Fa-f]{1,4}:){6}(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){0,4}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(:(:[0-9A-Fa-f]{1,4}){0,5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}))$"); + Pattern ipv4Check = Pattern.compile("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$"); + boolean ipv6Result = ipv6Check.matcher(ip).matches(); + boolean ipv4Result = ipv4Check.matcher(ip).matches(); + if (!(ipv6Result || ipv4Result)) { + return false; + } + return true; + } + + public static boolean checkIpv4(String ip) { + Pattern ipv4Check = Pattern.compile("^(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}$"); + boolean ipv4Result = ipv4Check.matcher(ip).matches(); + if (!ipv4Result) { + return false; + } + return true; + } + + public static boolean checkIpv6(String ip) { + Pattern ipv6Check = Pattern.compile("^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:)|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}(:[0-9A-Fa-f]{1,4}){1,2})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){1,3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){1,4})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){1,5})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){1,6})|(:(:[0-9A-Fa-f]{1,4}){1,7})|(([0-9A-Fa-f]{1,4}:){6}(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4}){0,1}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){3}(:[0-9A-Fa-f]{1,4}){0,2}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|([0-9A-Fa-f]{1,4}:(:[0-9A-Fa-f]{1,4}){0,4}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3})|(:(:[0-9A-Fa-f]{1,4}){0,5}:(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}))$"); + boolean ipv6Result = ipv6Check.matcher(ip).matches(); + if (!ipv6Result) { + return false; + } + return true; + } + +} diff --git a/src/main/java/net/geedge/confagent/util/Tool.java b/src/main/java/net/geedge/confagent/util/Tool.java index 250b0c2..a89f174 100644 --- a/src/main/java/net/geedge/confagent/util/Tool.java +++ b/src/main/java/net/geedge/confagent/util/Tool.java @@ -14,15 +14,12 @@ import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.lang.reflect.Type; import java.math.BigDecimal; -import java.net.URLDecoder; +import java.net.*; import java.nio.ByteBuffer; import java.time.LocalDateTime; import java.time.temporal.Temporal; import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Collection; -import java.util.Iterator; -import java.util.Spliterator; +import java.util.*; import javax.tools.JavaCompiler; import javax.tools.JavaFileObject; @@ -1103,4 +1100,50 @@ public class Tool { } } + + public static class InetAddressUtil { + public static String getLocalHostLANAddress() throws UnknownHostException { + try { + List<InetAddress> inetAddressList = Tool.ListUtil.list(false); + // 遍历所有的网络接口 + for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) { + NetworkInterface iface = (NetworkInterface) ifaces.nextElement(); + // 在所有的接口下再遍历IP + for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) { + InetAddress inetAddr = (InetAddress) inetAddrs.nextElement(); + if (!inetAddr.isAnyLocalAddress() && !inetAddr.isLoopbackAddress() && !inetAddr.isLinkLocalAddress()) { + inetAddressList.add(inetAddr); + } + } + } + + InetAddress inet6Address = inetAddressList.stream().filter(inetAddress -> inetAddress instanceof Inet6Address).findFirst().orElse(null); + if (Optional.ofNullable(inet6Address).isPresent()) { + String ipAddr = inet6Address.getHostAddress(); + int index = ipAddr.indexOf('%'); + if (index > 0) { + ipAddr = ipAddr.substring(0, index); + } + return ipAddr; + } + + InetAddress inet4Address = inetAddressList.stream().findFirst().orElse(null); + if (Optional.ofNullable(inet4Address).isPresent()) { + return inet4Address.getHostAddress(); + } + + // 如果没有发现 non-loopback地址.只能用最次选的方案 + InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); + if (Optional.ofNullable(jdkSuppliedAddress).isPresent()) { + throw new UnknownHostException("The JDK InetAddress.getLocalHost() method unexpectedly returned null."); + } + return jdkSuppliedAddress.getHostAddress(); + } catch (Exception e) { + UnknownHostException unknownHostException = new UnknownHostException( + "Failed to determine LAN address: " + e); + unknownHostException.initCause(e); + throw unknownHostException; + } + } + } } |
