diff --git a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java index 13c5ef5..4837580 100644 --- a/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java +++ b/src/main/java/com/tongran/agent/client/core/config/GlobalConfig.java @@ -16,6 +16,7 @@ import java.util.concurrent.ConcurrentHashMap; public class GlobalConfig { + public static String NETNAME = ""; /** * 服务启动时间 */ diff --git a/src/main/java/com/tongran/agent/client/core/vo/NetVO.java b/src/main/java/com/tongran/agent/client/core/vo/NetVO.java index f7eb9dd..4a33f5b 100644 --- a/src/main/java/com/tongran/agent/client/core/vo/NetVO.java +++ b/src/main/java/com/tongran/agent/client/core/vo/NetVO.java @@ -31,6 +31,9 @@ public class NetVO implements Serializable { @Schema(description = "IPv4") private String ipV4; + @Schema(description = "IPv6") + private String ipV6; + @Schema(description = "入站丢包") private long inDropped; @@ -43,6 +46,18 @@ public class NetVO implements Serializable { @Schema(description = "接收流量(接收总字节)") private long inSpeed; + @Schema(description = "IPv4接收流量") + private Long ipv4InSpeed; + + @Schema(description = "IPv4发送流量") + private Long ipv4OutSpeed; + + @Schema(description = "IPv6接收流量") + private Long ipv6InSpeed; + + @Schema(description = "IPv6发送流量") + private Long ipv6OutSpeed; + @Schema(description = "协商速度") private String speed; @@ -52,4 +67,4 @@ public class NetVO implements Serializable { @Schema(description = "时间戳") private long timestamp; -} +} \ No newline at end of file diff --git a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java index 087c926..b9e72e2 100644 --- a/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java +++ b/src/main/java/com/tongran/agent/client/netty/enpoint/AgentEndpoint.java @@ -75,6 +75,14 @@ public class AgentEndpoint { } } } + if(object.containsKey("netName")){ + String netName = object.getString("netName");; + AssertLog.info("注册成功,业务网卡={}",netName); + if(StringUtils.isNotBlank(netName)){ + // 添加ipv4 ipv6防火墙策略 + agentService.addFirewall(netName); + } + } //检查外置目录是否存在 if(AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())){ String[] lines = { diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java index 2031546..4ab873a 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/AppInitializer.java @@ -92,6 +92,12 @@ public class AppInitializer implements CommandLineRunner { // 检测监控策略配置 AssertLog.info("检测监控策略配置"); agentService.checkMonitor(); + // 检测防火墙策略配置 + AssertLog.info("检测防火墙策略配置"); + agentService.checkFirewall(); + AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000); + dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000); + }else{ //未注册,发送注册 try { diff --git a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java index 5398ac0..362032e 100644 --- a/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java +++ b/src/main/java/com/tongran/agent/client/scheduler/service/BusinessTasks.java @@ -59,6 +59,7 @@ public class BusinessTasks { private final AtomicInteger registerTask = new AtomicInteger(0); private final AtomicInteger connectionTask = new AtomicInteger(0); private final AtomicInteger networkDetectTask = new AtomicInteger(0); + private final AtomicInteger checkFirewallTask = new AtomicInteger(0); @@ -846,6 +847,11 @@ public class BusinessTasks { // 检测监控策略配置 AssertLog.info("检测监控策略配置Retry"); agentService.checkMonitor(); + // 检测防火墙策略配置 + AssertLog.info("检测防火墙策略配置"); + agentService.checkFirewall(); + AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000); + dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000); }else{ //未注册,发送注册 try { @@ -906,6 +912,21 @@ public class BusinessTasks { } AssertLog.info("发送多网IP探测定时任务执行 - task #{} completed", count); } + /** + * 任务30:监测防火墙策略 + */ + @Async("taskExecutor") + public void checkFirewallTask() { + int count = checkFirewallTask.incrementAndGet(); + AssertLog.info("监测防火墙策略定时任务执行 - 时间: {},task #{}", LocalDateTime.now(), count); + // 判定客户端与服务端是否连接 + if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) { + // 检测防火墙策略是否存在 + agentService.checkAndAddFirewallPeriodically(); + }else{ + AssertLog.info("断开连接--监测防火墙策略定时任务执行 - task #{} completed", count); + } + } diff --git a/src/main/java/com/tongran/agent/client/service/AgentService.java b/src/main/java/com/tongran/agent/client/service/AgentService.java index 92be1de..964bb66 100644 --- a/src/main/java/com/tongran/agent/client/service/AgentService.java +++ b/src/main/java/com/tongran/agent/client/service/AgentService.java @@ -30,4 +30,10 @@ public interface AgentService { String getLogicalNode(); void checkMonitor(); + + void addFirewall(String netName); + + void checkFirewall(); + + void checkAndAddFirewallPeriodically(); } diff --git a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java index 1ddf808..6f1822c 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/AgentServiceImpl.java @@ -31,6 +31,7 @@ import javax.annotation.Resource; import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.*; +import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.*; import java.util.concurrent.CompletableFuture; @@ -282,6 +283,11 @@ public class AgentServiceImpl implements AgentService { // 检测监控策略配置 AssertLog.info("检测监控策略配置"); checkMonitor(); + // 检测防火墙策略配置 + AssertLog.info("检测防火墙策略配置"); + checkFirewall(); + AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000); + dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000); } @Override @@ -825,7 +831,11 @@ public class AgentServiceImpl implements AgentService { } } } - + } + if(jsonObject.containsKey("netName")){ + String netName = jsonObject.getString("netName"); + // 添加防火墙策略 + addFirewall(netName); } } @@ -1428,8 +1438,228 @@ public class AgentServiceImpl implements AgentService { } + @Override + public void addFirewall(String netName) { + String[] netNames = netName.split(";"); + + if (!netName.equals(GlobalConfig.NETNAME)) { + try { + // 1. 将网卡名称写入配置文件 + String[] lines = { + "# 业务网卡防火墙策略配置文件", + "# 生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), + "# 业务网卡名称列表", + "businessNetNames=" + netName, + "", + "# 配置元信息", + "lastUpdateTime=" + System.currentTimeMillis(), + "totalInterfaces=" + netNames.length + }; + + // 检查目录并写入配置文件 + if (AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())) { + AgentUtil.bufferedWriter(properties.getConfPath() + "/businessnetname.conf", lines); + } + // 更新全局变量 + GlobalConfig.NETNAME = netName; + // 2. 为每个业务网卡执行iptables命令 + for (String interfaceName : netNames) { + String iface = interfaceName.trim(); + if (!iface.isEmpty()) { + // 执行IPv4防火墙命令 + executeIptablesCommand("iptables", "-I", "INPUT", "1", "-i", iface, "-j", "ACCEPT"); + executeIptablesCommand("iptables", "-I", "OUTPUT", "1", "-o", iface, "-j", "ACCEPT"); + + // 执行IPv6防火墙命令 + executeIptablesCommand("ip6tables", "-I", "INPUT", "1", "-i", iface, "-j", "ACCEPT"); + executeIptablesCommand("ip6tables", "-I", "OUTPUT", "1", "-o", iface, "-j", "ACCEPT"); + } + } + + AssertLog.debug("防火墙策略配置完成,网卡列表: {}", netName); + } catch (Exception e) { + AssertLog.error("配置防火墙策略时发生错误: {}", e.getMessage()); + } + } + } + + /** + * 执行iptables命令 + */ + private void executeIptablesCommand(String... command) { + Process process = null; + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + processBuilder.redirectErrorStream(true); + process = processBuilder.start(); + + // 等待命令执行完成 + int exitCode = process.waitFor(); + if (exitCode != 0) { + AssertLog.debug("命令执行失败: {} , 退出码: {}", String.join(" ", command), exitCode); + } else { + AssertLog.debug("命令执行成功: {}", String.join(" ", command)); + } + + } catch (Exception e) { + AssertLog.error("执行命令异常: {} , 错误: {}", String.join(" ", command), e.getMessage()); + } finally { + if (process != null) { + process.destroy(); + } + } + } + @Override + public void checkFirewall() { + File businessNetFile = new File(properties.getConfPath() + "/businessnetname.conf"); + if (businessNetFile.exists()) { + Properties props = new Properties(); + try (InputStream input = Files.newInputStream(businessNetFile.toPath())) { + props.load(input); + + String businessNetNames = props.getProperty("businessNetNames"); + if (StringUtils.isNotBlank(businessNetNames)) { + // 直接调用 addFirewall 方法,传入配置文件中读取的 netName + addFirewall(businessNetNames); + AssertLog.info("应用启动时加载业务网卡配置成功: {}", businessNetNames); + } + + } catch (Exception e) { + AssertLog.error("应用启动时加载业务网卡配置异常", e); + } + } else { + AssertLog.debug("业务网卡配置文件不存在: {}", businessNetFile.getPath()); + } + } + public void caseTypeBySystem(String type, int interval, boolean collect){ } + /** + * 检查业务端口防火墙策略,不存在则添加 + */ + @Override + public void checkAndAddFirewallPeriodically() { + try { + String netName = getBusinessNetNames(); + if (StringUtils.isBlank(netName)) { + AssertLog.debug("没有配置业务网卡,跳过防火墙检查"); + return; + } + + String[] netNames = netName.split(";"); + StringBuilder missingNetNames = new StringBuilder(); + + for (String interfaceName : netNames) { + String iface = interfaceName.trim(); + if (iface.isEmpty()) { + continue; + } + + // 检查该网卡是否缺少任何规则 + if (!checkRuleExists("iptables", "INPUT", "-i", iface, "-j", "ACCEPT") || + !checkRuleExists("iptables", "OUTPUT", "-o", iface, "-j", "ACCEPT") || + !checkRuleExists("ip6tables", "INPUT", "-i", iface, "-j", "ACCEPT") || + !checkRuleExists("ip6tables", "OUTPUT", "-o", iface, "-j", "ACCEPT")) { + + if (missingNetNames.length() > 0) { + missingNetNames.append(";"); + } + missingNetNames.append(iface); + } + } + + if (missingNetNames.length() > 0) { + AssertLog.info("检测到以下网卡防火墙策略缺失: {}", missingNetNames.toString()); + // 只对缺失规则的网卡调用addFirewall + addFirewall(missingNetNames.toString()); + } else { + AssertLog.debug("所有业务网卡防火墙策略检查正常,无需添加"); + } + + } catch (Exception e) { + AssertLog.error("检查防火墙策略时发生错误: {}", e.getMessage()); + } + } + + /** + * 使用 iptables -S [chain] 检查特定链中的规则是否存在 + */ + private boolean checkRuleExists(String command, String chain, String... ruleParts) { + Process process = null; + try { + // 执行 iptables -S [chain] 命令,只查看特定链 + ProcessBuilder processBuilder = new ProcessBuilder(command, "-S", chain); + processBuilder.redirectErrorStream(true); + process = processBuilder.start(); + + // 构建目标规则关键词(排除-A和链名) + List targetKeywords = new ArrayList<>(); + for (String part : ruleParts) { + if (!part.equals("-A") && !part.equals(chain)) { + targetKeywords.add(part); + } + } + + // 读取命令输出 + try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + // 检查行是否包含所有关键词 + boolean containsAll = true; + for (String keyword : targetKeywords) { + if (!line.contains(keyword)) { + containsAll = false; + break; + } + } + if (containsAll) { + return true; + } + } + } + + int exitCode = process.waitFor(); + if (exitCode != 0) { + AssertLog.debug("命令执行失败: {} -S {}, 退出码: {}", command, chain, exitCode); + } + + return false; + + } catch (Exception e) { + AssertLog.debug("检查规则是否存在时发生异常: {}", e.getMessage()); + return false; + } finally { + if (process != null) { + process.destroy(); + } + } + } + + /** + * 从配置文件或全局变量获取业务网卡名称 + */ + private String getBusinessNetNames() { + if (StringUtils.isNotBlank(GlobalConfig.NETNAME)) { + return GlobalConfig.NETNAME; + } + + File businessNetFile = new File(properties.getConfPath() + "/businessnetname.conf"); + if (businessNetFile.exists()) { + Properties props = new Properties(); + try (InputStream input = Files.newInputStream(businessNetFile.toPath())) { + props.load(input); + String businessNetNames = props.getProperty("businessNetNames"); + if (StringUtils.isNotBlank(businessNetNames)) { + GlobalConfig.NETNAME = businessNetNames; + return businessNetNames; + } + } catch (Exception e) { + AssertLog.error("读取业务网卡配置文件异常", e); + } + } + + return null; + } } diff --git a/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java b/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java index e9e60e6..2000fbf 100644 --- a/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java +++ b/src/main/java/com/tongran/agent/client/service/impl/NetServiceImpl.java @@ -1,5 +1,6 @@ package com.tongran.agent.client.service.impl; +import com.tongran.agent.client.core.config.GlobalConfig; import com.tongran.agent.client.core.vo.NetVO; import com.tongran.agent.client.service.NetService; import com.tongran.agent.client.utils.AgentUtil; @@ -12,78 +13,112 @@ import oshi.util.FormatUtil; import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.*; -import java.util.concurrent.TimeUnit; @Service public class NetServiceImpl implements NetService { + + @Override public List netList(long timestamp) { List list = new ArrayList<>(); try { SystemInfo si = new SystemInfo(); HardwareAbstractionLayer hal = si.getHardware(); - // 获取所有网络接口 List networkIFs = hal.getNetworkIFs(); + System.out.println("========================================================="); - System.out.println("===== 网卡流量统计 ====="); - List temp = new ArrayList<>(); + System.out.println("===== 网卡流量统计(基于iptables统计) ====="); + + // 第一次采样 - 获取基本数据 for (NetworkIF net : networkIFs) { - System.out.println("接口名称: " + net.getName()+"("+net.getDisplayName()+")"); + net.updateAttributes(); + } + + // 等待1秒进行第二次采样 + Thread.sleep(1000); + + // 获取iptables统计信息 + Map> iptablesStats = getIptablesStatistics(); + + // 第二次采样并计算流量 + for (NetworkIF net : networkIFs) { + net.updateAttributes(); + + String interfaceName = net.getName(); + boolean isBusinessInterface = GlobalConfig.NETNAME.contains(interfaceName); + + System.out.println("接口名称: " + interfaceName + "(" + net.getDisplayName() + ")"); System.out.println("MAC地址: " + net.getMacaddr()); - System.out.print("运行状态: "); - System.out.println(net.isConnectorPresent() ? "已连接" : "未连接"); + System.out.println("运行状态: " + (net.isConnectorPresent() ? "已连接" : "未连接")); System.out.println("接口类型: " + AgentUtil.getInterfaceType(net)); System.out.println("IPv4地址: " + String.join(", ", net.getIPv4addr())); + System.out.println("IPv6地址: " + String.join(", ", net.getIPv6addr())); + System.out.println("业务网卡: " + (isBusinessInterface ? "是" : "否")); - NetVO netVO = NetVO.builder().build(); - netVO.setName(net.getName()+"("+net.getDisplayName()+")");//网卡名称 - netVO.setMac(net.getMacaddr());//MAC - netVO.setStatus(net.isConnectorPresent() ? "已连接" : "未连接");//运行状态 - netVO.setType(AgentUtil.getInterfaceType(net));//接口类型 - netVO.setIpV4(String.join(", ", net.getIPv4addr()));//IPv4 - Map map = getNetworkMode(net.getName()); - if (map != null && !map.isEmpty()) { - netVO.setSpeed(map.get("speed")); - netVO.setDuplex(map.get("duplex")); + // 获取总流量 + long totalBytesRecv = net.getBytesRecv(); + long totalBytesSent = net.getBytesSent(); + + Long ipv4BytesRecv = null, ipv4BytesSent = null; + Long ipv6BytesRecv = null, ipv6BytesSent = null; + + if (isBusinessInterface) { + // 业务网卡:使用iptables统计区分IPv4/IPv6流量 + Map interfaceStats = iptablesStats.get(interfaceName); + if (interfaceStats != null) { + ipv4BytesRecv = interfaceStats.get("ipv4Recv"); + ipv4BytesSent = interfaceStats.get("ipv4Sent"); + ipv6BytesRecv = interfaceStats.get("ipv6Recv"); + ipv6BytesSent = interfaceStats.get("ipv6Sent"); + + System.out.println("iptables统计 - IPv4接收: " + (ipv4BytesRecv != null ? FormatUtil.formatBytes(ipv4BytesRecv) : "null") + + ", IPv4发送: " + (ipv4BytesSent != null ? FormatUtil.formatBytes(ipv4BytesSent) : "null") + + ", IPv6接收: " + (ipv6BytesRecv != null ? FormatUtil.formatBytes(ipv6BytesRecv) : "null") + + ", IPv6发送: " + (ipv6BytesSent != null ? FormatUtil.formatBytes(ipv6BytesSent) : "null")); + } else { + System.out.println("警告: 未找到网卡 " + interfaceName + " 的iptables统计信息"); + } + } else { + // 非业务网卡:IPv4/IPv6流量设为null + System.out.println("非业务网卡,IPv4/IPv6流量统计为null"); } - temp.add(netVO); - } - // 2. 实时带宽监控(需要两次采样) - System.out.println("\n=== 实时带宽监控 ==="); - // 第一次采样 - for (NetworkIF net : networkIFs) { - net.updateAttributes(); - } - // 等待1秒 - TimeUnit.SECONDS.sleep(1); - // 第二次采样并计算速率 - for (NetworkIF net : networkIFs) { - long prevBytesRecv = net.getBytesRecv(); - long prevBytesSent = net.getBytesSent(); - net.updateAttributes(); - long bytesRecv = net.getBytesRecv(); - long bytesSent = net.getBytesSent(); -// long bytesRecv = net.getBytesRecv() - prevBytesRecv; -// long bytesSent = net.getBytesSent() - prevBytesSent; - System.out.println("接口: " + net.getName()); + System.out.println("总接收流量: " + FormatUtil.formatBytes(totalBytesRecv)); + System.out.println("总发送流量: " + FormatUtil.formatBytes(totalBytesSent)); + System.out.println("IPv4接收流量: " + (ipv4BytesRecv != null ? FormatUtil.formatBytes(ipv4BytesRecv) : "null")); + System.out.println("IPv4发送流量: " + (ipv4BytesSent != null ? FormatUtil.formatBytes(ipv4BytesSent) : "null")); + System.out.println("IPv6接收流量: " + (ipv6BytesRecv != null ? FormatUtil.formatBytes(ipv6BytesRecv) : "null")); + System.out.println("IPv6发送流量: " + (ipv6BytesSent != null ? FormatUtil.formatBytes(ipv6BytesSent) : "null")); System.out.println("入站丢包: " + net.getInDrops()); System.out.println("出站丢包: " + net.getCollisions()); - System.out.println("接收带宽: " + FormatUtil.formatBytes(bytesRecv) + "/s (" + - bytesToMbps(bytesRecv) + " Mbps)"); - System.out.println("发送带宽: " + FormatUtil.formatBytes(bytesSent) + "/s (" + - bytesToMbps(bytesSent) + " Mbps)"); - NetVO netVO = temp.stream().filter(n -> n.getIpV4().equals(String.join(", ", net.getIPv4addr())) - && n.getMac().equals(net.getMacaddr())).findFirst().orElse(null); - if(Objects.nonNull(netVO)){ - netVO.setInDropped(net.getInDrops());//入站丢包 - netVO.setOutDropped(net.getCollisions());//出站丢包 - netVO.setInSpeed(bytesRecv);//接收流量 - netVO.setOutSpeed(bytesSent);//发送流量 - netVO.setTimestamp(timestamp); - list.add(netVO); + NetVO netVO = NetVO.builder() + .name(net.getName() + "(" + net.getDisplayName() + ")") + .mac(net.getMacaddr()) + .status(net.isConnectorPresent() ? "已连接" : "未连接") + .type(AgentUtil.getInterfaceType(net)) + .ipV4(String.join(", ", net.getIPv4addr())) + .ipV6(String.join(", ", net.getIPv6addr())) + .inDropped(net.getInDrops()) + .outDropped(net.getCollisions()) + .inSpeed(totalBytesRecv) + .outSpeed(totalBytesSent) + .ipv4InSpeed(ipv4BytesRecv) + .ipv4OutSpeed(ipv4BytesSent) + .ipv6InSpeed(ipv6BytesRecv) + .ipv6OutSpeed(ipv6BytesSent) + .timestamp(timestamp) + .build(); + + // 设置协商速度和工作模式 + Map ethtoolMap = getNetworkMode(net.getName()); + if (ethtoolMap != null && !ethtoolMap.isEmpty()) { + netVO.setSpeed(ethtoolMap.get("speed")); + netVO.setDuplex(ethtoolMap.get("duplex")); } + + list.add(netVO); + System.out.println("-----------------------------------------"); } } catch (Exception e) { e.printStackTrace(); @@ -91,8 +126,128 @@ public class NetServiceImpl implements NetService { return list; } - private static double bytesToMbps(long bytes) { - return bytes * 8.0 / 1_000_000; // bytes to megabits + /** + * 获取iptables统计信息 + */ + private Map> getIptablesStatistics() { + Map> stats = new HashMap<>(); + + try { + System.out.println("开始获取iptables统计信息..."); + + // 获取IPv4 INPUT统计 + System.out.println("获取IPv4 INPUT统计..."); + ProcessBuilder pb = new ProcessBuilder("iptables", "-v", "-n", "-x", "-L", "INPUT"); + Process process = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + parseIptablesLine(line, stats, "ipv4Recv"); + } + process.waitFor(); + + // 获取IPv4 OUTPUT统计 + System.out.println("获取IPv4 OUTPUT统计..."); + pb = new ProcessBuilder("iptables", "-v", "-n", "-x", "-L", "OUTPUT"); + process = pb.start(); + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + while ((line = reader.readLine()) != null) { + parseIptablesLine(line, stats, "ipv4Sent"); + } + process.waitFor(); + + // 获取IPv6 INPUT统计 + System.out.println("获取IPv6 INPUT统计..."); + pb = new ProcessBuilder("ip6tables", "-v", "-n", "-x", "-L", "INPUT"); + process = pb.start(); + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + while ((line = reader.readLine()) != null) { + parseIptablesLine(line, stats, "ipv6Recv"); + } + process.waitFor(); + + // 获取IPv6 OUTPUT统计 + System.out.println("获取IPv6 OUTPUT统计..."); + pb = new ProcessBuilder("ip6tables", "-v", "-n", "-x", "-L", "OUTPUT"); + process = pb.start(); + reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + + while ((line = reader.readLine()) != null) { + parseIptablesLine(line, stats, "ipv6Sent"); + } + process.waitFor(); + + System.out.println("最终iptables统计信息: " + stats); + + } catch (Exception e) { + System.err.println("获取iptables统计失败: " + e.getMessage()); + e.printStackTrace(); + } + + return stats; + } + + /** + * 解析iptables输出行 - 根据实际输出格式修复 + */ + private void parseIptablesLine(String line, Map> stats, String statType) { + line = line.trim(); + + if (line.isEmpty() || line.startsWith("Chain") || line.startsWith("pkts") || line.startsWith("target")) { + return; + } + + // 使用空格分割,处理多个连续空格 + String[] parts = line.split("\\s+"); + System.out.println("解析行: " + line); + System.out.println("分割部分数量: " + parts.length + ", 内容: " + Arrays.toString(parts)); + + if (parts.length >= 7) { + try { + // 字节数在第二列(索引1) + long bytes = Long.parseLong(parts[1]); + String interfaceName = null; + + // 根据statType确定是输入接口还是输出接口 + if ("ipv4Recv".equals(statType) || "ipv6Recv".equals(statType)) { + // 接收流量:查看输入接口(第6列,索引5) + if (parts.length > 5 && !parts[5].equals("*")) { + interfaceName = parts[5]; + System.out.println("接收流量 - 输入接口: " + interfaceName); + } + } else if ("ipv4Sent".equals(statType) || "ipv6Sent".equals(statType)) { + // 发送流量:查看输出接口(第7列,索引6) + if (parts.length > 6 && !parts[6].equals("*")) { + interfaceName = parts[6]; + System.out.println("发送流量 - 输出接口: " + interfaceName); + } + } + + if (interfaceName != null && GlobalConfig.NETNAME.contains(interfaceName)) { + Map interfaceStats = stats.getOrDefault(interfaceName, new HashMap<>()); + + // 累加相同接口的流量(处理多条规则匹配同一接口的情况) + long currentBytes = interfaceStats.getOrDefault(statType, 0L); + interfaceStats.put(statType, currentBytes + bytes); + stats.put(interfaceName, interfaceStats); + + System.out.println("成功记录iptables统计: " + interfaceName + " - " + statType + " = " + bytes + " bytes (累计: " + (currentBytes + bytes) + ")"); + } else if (interfaceName != null) { + System.out.println("接口 " + interfaceName + " 不是业务网卡,跳过"); + } else { + System.out.println("未找到有效的接口名(可能是通配符*)"); + } + + } catch (NumberFormatException e) { + System.err.println("解析iptables行失败,无法解析数字: " + line); + System.err.println("错误部分: " + parts[1]); + } + } else { + System.out.println("行格式不符合预期,跳过: " + line); + } } public static Map getNetworkMode(String interfaceName) { @@ -109,17 +264,12 @@ public class NetServiceImpl implements NetService { result.put("speed", line.split(":")[1].trim()); } else if (line.contains("Duplex:")) { result.put("duplex", line.split(":")[1].trim()); - } else if (line.contains("Auto-negotiation:")) { - result.put("auto-negotiation", line.split(":")[1].trim()); } } - int exitCode = process.waitFor(); - if (exitCode != 0) { - result.put("error", "ethtool command failed with exit code " + exitCode); - } + process.waitFor(); } catch (Exception e) { result.put("error", e.getMessage()); } return result; } -} +} \ No newline at end of file