agent定时更新优化、脚本策略定时执行优化
优化ipv4、ipv6采集
This commit is contained in:
@@ -225,9 +225,9 @@ public class AgentEndpoint {
|
||||
if(StringUtils.isNotBlank(md5) && StringUtils.isNotBlank(versionUpdateEO.getFileMd5())
|
||||
&& StringUtils.equals(md5,versionUpdateEO.getFileMd5())){
|
||||
//更改全局变量
|
||||
GlobalConfig.isCollect = false;
|
||||
// GlobalConfig.isCollect = false;
|
||||
//调用采集任务
|
||||
agentService.cancelCollect();
|
||||
// agentService.cancelCollect();
|
||||
//所有文件下载完成,执行脚本命令
|
||||
agentService.command(policy, clientId,MsgEnum.Agent版本更新应答.getValue());
|
||||
}else{
|
||||
|
||||
@@ -97,6 +97,8 @@ public class AppInitializer implements CommandLineRunner {
|
||||
agentService.checkFirewall();
|
||||
AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000);
|
||||
dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000);
|
||||
AssertLog.info("检测agent更新配置");
|
||||
agentService.checkAgentUpdate();
|
||||
|
||||
}else{
|
||||
//未注册,发送注册
|
||||
|
||||
@@ -852,6 +852,8 @@ public class BusinessTasks {
|
||||
agentService.checkFirewall();
|
||||
AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000);
|
||||
dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000);
|
||||
AssertLog.info("检测agent更新配置");
|
||||
agentService.checkAgentUpdate();
|
||||
}else{
|
||||
//未注册,发送注册
|
||||
try {
|
||||
|
||||
@@ -2,12 +2,15 @@ package com.tongran.agent.client.scheduler.task;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.tongran.agent.client.core.config.ApplicationProperties;
|
||||
import com.tongran.agent.client.core.config.GlobalConfig;
|
||||
import com.tongran.agent.client.core.enums.MsgEnum;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
import com.tongran.agent.client.scheduler.service.AsyncCommandExecutor;
|
||||
import com.tongran.agent.client.service.AgentService;
|
||||
import com.tongran.agent.client.utils.AgentDataUtil;
|
||||
import com.tongran.agent.client.utils.AgentUtil;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -27,7 +30,9 @@ public class SpecificTimeTaskService {
|
||||
|
||||
@Resource
|
||||
private ApplicationProperties properties;
|
||||
|
||||
@Resource
|
||||
private AgentService agentService;
|
||||
|
||||
@Resource
|
||||
private SpecificTimeTaskConfig taskConfig;
|
||||
|
||||
@@ -81,6 +86,11 @@ public class SpecificTimeTaskService {
|
||||
String key = request.getTaskName()+"-"+System.currentTimeMillis();
|
||||
if(StringUtils.equals(request.getDataType(), MsgEnum.Agent版本更新应答.getValue())){
|
||||
try {
|
||||
AssertLog.info("定时更新启动...暂停心跳和采集任务");
|
||||
//更改全局变量
|
||||
GlobalConfig.isCollect = false;
|
||||
//调用采集任务
|
||||
agentService.cancelCollect();
|
||||
//设置检查回滚任务
|
||||
String SCRIPT_PATH = properties.getScriptPath()+"/rollback-tragent.sh";
|
||||
AgentDataUtil.chmod(SCRIPT_PATH,"775");
|
||||
@@ -113,7 +123,7 @@ public class SpecificTimeTaskService {
|
||||
json.put("resMsg", "");
|
||||
json.put("result", jsonObject.toJSONString());
|
||||
json.put("timestamp",timestamps);
|
||||
Message message = Message.builder().clientId(request.getClientId()).dataType(request.getDataType()).data(jsonObject.toJSONString()).build();
|
||||
Message message = Message.builder().clientId(request.getClientId()).dataType(request.getDataType()).data(json.toJSONString()).build();
|
||||
if (Objects.nonNull(sessionManager.getSessionById(request.getClientId()))) {
|
||||
System.out.println("发送执行结果: " + json.toJSONString()); // 注意:toJSONString()
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(request.getClientId()).getChannel(), message);
|
||||
|
||||
@@ -36,4 +36,6 @@ public interface AgentService {
|
||||
void checkFirewall();
|
||||
|
||||
void checkAndAddFirewallPeriodically();
|
||||
|
||||
void checkAgentUpdate();
|
||||
}
|
||||
|
||||
@@ -166,35 +166,24 @@ public class AgentServiceImpl implements AgentService {
|
||||
.clientId(clientId)
|
||||
.dataType(dataType)
|
||||
.build();
|
||||
try {
|
||||
taskService.createSpecificTimeTask(request);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存成功");
|
||||
json.put("timestamp",timestamp);
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue())
|
||||
.data(json.toString()).build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存失败");
|
||||
json.put("timestamp",timestamp);
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue())
|
||||
.data(json.toString()).build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message));
|
||||
if(StringUtils.equals(dataType, MsgEnum.Agent版本更新应答.getValue())){
|
||||
// 将request对象转换为JSON字符串
|
||||
String jsonContent = "updateMsg=" + JSONObject.toJSONString(request);
|
||||
// 检查并创建外置目录
|
||||
if (AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())) {
|
||||
// 将JSON字符串写入文件
|
||||
AgentUtil.bufferedWriter(properties.getConfPath() + "/agentupdate.conf",
|
||||
new String[]{jsonContent});
|
||||
}
|
||||
}
|
||||
processCommand(request, timestamp);
|
||||
}else{
|
||||
if(StringUtils.equals(dataType, MsgEnum.Agent版本更新应答.getValue())){
|
||||
try {
|
||||
//更改全局变量
|
||||
GlobalConfig.isCollect = false;
|
||||
//关闭采集任务
|
||||
cancelCollect();
|
||||
//设置检查回滚任务
|
||||
String SCRIPT_PATH = properties.getScriptPath()+"/rollback-tragent.sh";
|
||||
AgentDataUtil.chmod(SCRIPT_PATH,"775");
|
||||
@@ -265,6 +254,40 @@ public class AgentServiceImpl implements AgentService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 辅助方法:持久化定时更新
|
||||
* @param request
|
||||
* @param timestamp
|
||||
*/
|
||||
public void processCommand(SpecificTimeRequest request, long timestamp){
|
||||
try {
|
||||
taskService.createSpecificTimeTask(request);
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",1);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存成功");
|
||||
json.put("timestamp",timestamp);
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue())
|
||||
.data(json.toString()).build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
JSONObject json = new JSONObject();
|
||||
json.put("resCode",0);
|
||||
json.put("resMsg", "执行脚本策略定时任务保存失败");
|
||||
json.put("timestamp",timestamp);
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.执行脚本策略应答.getValue())
|
||||
.data(json.toString()).build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送执行脚本策略应答={}",JSON.toJSONString(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(String taskId) {
|
||||
dynamicTaskService.cancelTask(taskId);
|
||||
@@ -288,6 +311,8 @@ public class AgentServiceImpl implements AgentService {
|
||||
checkFirewall();
|
||||
AssertLog.info("启动检查防火墙策略定时任务 - 延迟: {}ms, 间隔: {}ms", milli, 600000);
|
||||
dynamicTaskService.scheduleTask("checkFirewall", businessTasks::checkFirewallTask, 15000, 600000);
|
||||
AssertLog.info("检测agent更新配置");
|
||||
checkAgentUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -741,9 +766,9 @@ public class AgentServiceImpl implements AgentService {
|
||||
if(StringUtils.isNotBlank(md5) && StringUtils.isNotBlank(versionUpdateEO.getFileMd5())
|
||||
&& StringUtils.equals(md5,versionUpdateEO.getFileMd5())){
|
||||
//更改全局变量
|
||||
GlobalConfig.isCollect = false;
|
||||
// GlobalConfig.isCollect = false;
|
||||
//关闭采集任务
|
||||
cancelCollect();
|
||||
// cancelCollect();
|
||||
//所有文件下载完成,执行脚本命令
|
||||
AssertLog.info("版本策略MD5验证成功");
|
||||
command(policy, GlobalConfig.CLIENT_ID,MsgEnum.Agent版本更新应答.getValue());
|
||||
@@ -1444,7 +1469,7 @@ public class AgentServiceImpl implements AgentService {
|
||||
|
||||
if (!netName.equals(GlobalConfig.NETNAME)) {
|
||||
try {
|
||||
// 1. 将网卡名称写入配置文件
|
||||
// 1. 将网卡名称写入配置文件
|
||||
String[] lines = {
|
||||
"# 业务网卡防火墙策略配置文件",
|
||||
"# 生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),
|
||||
@@ -1460,18 +1485,34 @@ public class AgentServiceImpl implements AgentService {
|
||||
if (AdvancedAsyncDownloader.createSingleDirectoryIfNotExists(properties.getConfPath())) {
|
||||
AgentUtil.bufferedWriter(properties.getConfPath() + "/businessnetname.conf", lines);
|
||||
}
|
||||
|
||||
// 更新全局变量
|
||||
GlobalConfig.NETNAME = netName;
|
||||
// 2. 为每个业务网卡执行iptables命令
|
||||
|
||||
// 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");
|
||||
if (iface.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 执行IPv6防火墙命令
|
||||
// 检查IPv4 INPUT规则是否存在
|
||||
if (!checkRuleExists("iptables", "INPUT", "-i", iface, "-j", "ACCEPT")) {
|
||||
executeIptablesCommand("iptables", "-I", "INPUT", "1", "-i", iface, "-j", "ACCEPT");
|
||||
}
|
||||
|
||||
// 检查IPv4 OUTPUT规则是否存在
|
||||
if (!checkRuleExists("iptables", "OUTPUT", "-o", iface, "-j", "ACCEPT")) {
|
||||
executeIptablesCommand("iptables", "-I", "OUTPUT", "1", "-o", iface, "-j", "ACCEPT");
|
||||
}
|
||||
|
||||
// 检查IPv6 INPUT规则是否存在
|
||||
if (!checkRuleExists("ip6tables", "INPUT", "-i", iface, "-j", "ACCEPT")) {
|
||||
executeIptablesCommand("ip6tables", "-I", "INPUT", "1", "-i", iface, "-j", "ACCEPT");
|
||||
}
|
||||
|
||||
// 检查IPv6 OUTPUT规则是否存在
|
||||
if (!checkRuleExists("ip6tables", "OUTPUT", "-o", iface, "-j", "ACCEPT")) {
|
||||
executeIptablesCommand("ip6tables", "-I", "OUTPUT", "1", "-o", iface, "-j", "ACCEPT");
|
||||
}
|
||||
}
|
||||
@@ -1483,6 +1524,7 @@ public class AgentServiceImpl implements AgentService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行iptables命令
|
||||
*/
|
||||
@@ -1547,37 +1589,7 @@ public class AgentServiceImpl implements AgentService {
|
||||
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("所有业务网卡防火墙策略检查正常,无需添加");
|
||||
}
|
||||
|
||||
addFirewall(netName);
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("检查防火墙策略时发生错误: {}", e.getMessage());
|
||||
}
|
||||
@@ -1662,4 +1674,29 @@ public class AgentServiceImpl implements AgentService {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkAgentUpdate() {
|
||||
File agentUpdateFile = new File(properties.getConfPath() + "/agentupdate.conf");
|
||||
if (agentUpdateFile.exists()) {
|
||||
Properties props = new Properties();
|
||||
try (InputStream input = Files.newInputStream(agentUpdateFile.toPath())) {
|
||||
props.load(input);
|
||||
|
||||
String updateMsg = props.getProperty("updateMsg");
|
||||
if (StringUtils.isNotBlank(updateMsg)) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
SpecificTimeRequest request = JSON.parseObject(updateMsg, SpecificTimeRequest.class);
|
||||
processCommand(request, timestamp);
|
||||
AssertLog.info("应用启动时加载agent更新配置成功: {}", updateMsg);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("应用启动时加载agent更新配置异常", e);
|
||||
}
|
||||
} else {
|
||||
AssertLog.debug("agent更新配置文件不存在: {}", agentUpdateFile.getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import java.util.*;
|
||||
@Service
|
||||
public class NetServiceImpl implements NetService {
|
||||
|
||||
|
||||
@Override
|
||||
public List<NetVO> netList(long timestamp) {
|
||||
List<NetVO> list = new ArrayList<>();
|
||||
@@ -46,13 +45,21 @@ public class NetServiceImpl implements NetService {
|
||||
|
||||
String interfaceName = net.getName();
|
||||
boolean isBusinessInterface = GlobalConfig.NETNAME.contains(interfaceName);
|
||||
String[] ipv6Arr = net.getIPv6addr();
|
||||
String publicIpv6 = "";
|
||||
for (String ipv6 : ipv6Arr) {
|
||||
if(AgentUtil.isPublicIPv6(ipv6)){
|
||||
publicIpv6 = ipv6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println("接口名称: " + interfaceName + "(" + net.getDisplayName() + ")");
|
||||
System.out.println("MAC地址: " + net.getMacaddr());
|
||||
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("公网IPv6地址: " + publicIpv6);
|
||||
System.out.println("业务网卡: " + (isBusinessInterface ? "是" : "否"));
|
||||
|
||||
// 获取总流量
|
||||
@@ -98,7 +105,7 @@ public class NetServiceImpl implements NetService {
|
||||
.status(net.isConnectorPresent() ? "已连接" : "未连接")
|
||||
.type(AgentUtil.getInterfaceType(net))
|
||||
.ipV4(String.join(", ", net.getIPv4addr()))
|
||||
.ipV6(String.join(", ", net.getIPv6addr()))
|
||||
.ipV6(publicIpv6)
|
||||
.inDropped(net.getInDrops())
|
||||
.outDropped(net.getCollisions())
|
||||
.inSpeed(totalBytesRecv)
|
||||
@@ -127,58 +134,51 @@ public class NetServiceImpl implements NetService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取iptables统计信息
|
||||
* 获取iptables统计信息 - 使用命令过滤模式优化
|
||||
*/
|
||||
private Map<String, Map<String, Long>> getIptablesStatistics() {
|
||||
Map<String, Map<String, Long>> stats = new HashMap<>();
|
||||
|
||||
try {
|
||||
System.out.println("开始获取iptables统计信息...");
|
||||
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()));
|
||||
// 遍历所有业务网卡,为每个网卡分别获取统计信息
|
||||
for (String interfaceName : GlobalConfig.NETNAME.split(";")) {
|
||||
System.out.println("处理业务网卡: " + interfaceName);
|
||||
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
parseIptablesLine(line, stats, "ipv4Recv");
|
||||
Map<String, Long> interfaceStats = new HashMap<>();
|
||||
|
||||
// 获取IPv4 INPUT统计
|
||||
Long ipv4Recv = getIptablesStatForInterface("iptables", "INPUT", interfaceName);
|
||||
if (ipv4Recv != null) {
|
||||
interfaceStats.put("ipv4Recv", ipv4Recv);
|
||||
}
|
||||
|
||||
// 获取IPv4 OUTPUT统计
|
||||
Long ipv4Sent = getIptablesStatForInterface("iptables", "OUTPUT", interfaceName);
|
||||
if (ipv4Sent != null) {
|
||||
interfaceStats.put("ipv4Sent", ipv4Sent);
|
||||
}
|
||||
|
||||
// 获取IPv6 INPUT统计
|
||||
Long ipv6Recv = getIptablesStatForInterface("ip6tables", "INPUT", interfaceName);
|
||||
if (ipv6Recv != null) {
|
||||
interfaceStats.put("ipv6Recv", ipv6Recv);
|
||||
}
|
||||
|
||||
// 获取IPv6 OUTPUT统计
|
||||
Long ipv6Sent = getIptablesStatForInterface("ip6tables", "OUTPUT", interfaceName);
|
||||
if (ipv6Sent != null) {
|
||||
interfaceStats.put("ipv6Sent", ipv6Sent);
|
||||
}
|
||||
|
||||
if (!interfaceStats.isEmpty()) {
|
||||
stats.put(interfaceName, interfaceStats);
|
||||
System.out.println("网卡 " + interfaceName + " 的统计信息: " + interfaceStats);
|
||||
} else {
|
||||
System.out.println("警告: 未找到网卡 " + interfaceName + " 的iptables统计信息");
|
||||
}
|
||||
}
|
||||
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);
|
||||
|
||||
@@ -191,63 +191,79 @@ public class NetServiceImpl implements NetService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析iptables输出行 - 根据实际输出格式修复
|
||||
* 获取指定网卡的iptables统计信息
|
||||
* @param iptablesCmd iptables或ip6tables
|
||||
* @param chain 链名(INPUT/OUTPUT)
|
||||
* @param interfaceName 网卡名
|
||||
* @return 字节数,如果没有找到返回null
|
||||
*/
|
||||
private void parseIptablesLine(String line, Map<String, Map<String, Long>> stats, String statType) {
|
||||
private Long getIptablesStatForInterface(String iptablesCmd, String chain, String interfaceName) {
|
||||
try {
|
||||
// 构建命令:iptables -v -n -x -L INPUT | grep eth0
|
||||
ProcessBuilder pb = new ProcessBuilder("sh", "-c",
|
||||
iptablesCmd + " -v -n -x -L " + chain + " | grep " + interfaceName);
|
||||
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
long totalBytes = 0;
|
||||
String line;
|
||||
boolean found = false;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
System.out.println("解析 " + iptablesCmd + " " + chain + " 行: " + line);
|
||||
Long bytes = parseIptablesLineForInterface(line);
|
||||
if (bytes != null) {
|
||||
totalBytes += bytes;
|
||||
found = true;
|
||||
System.out.println("找到匹配的规则: " + bytes + " bytes");
|
||||
}
|
||||
}
|
||||
|
||||
process.waitFor();
|
||||
|
||||
if (found) {
|
||||
System.out.println(iptablesCmd + " " + chain + " 接口 " + interfaceName + " 总流量: " + totalBytes + " bytes");
|
||||
return totalBytes;
|
||||
} else {
|
||||
System.out.println("未找到 " + iptablesCmd + " " + chain + " 接口 " + interfaceName + " 的统计信息");
|
||||
return null;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
System.err.println("获取 " + iptablesCmd + " " + chain + " 统计失败: " + e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析iptables输出行
|
||||
*/
|
||||
private Long parseIptablesLineForInterface(String line) {
|
||||
line = line.trim();
|
||||
|
||||
if (line.isEmpty() || line.startsWith("Chain") || line.startsWith("pkts") || line.startsWith("target")) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用空格分割,处理多个连续空格
|
||||
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<String, Long> 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("未找到有效的接口名(可能是通配符*)");
|
||||
}
|
||||
// 由于已经用grep过滤了,直接返回字节数
|
||||
System.out.println("找到匹配的规则: " + bytes + " bytes");
|
||||
return bytes;
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
System.err.println("解析iptables行失败,无法解析数字: " + line);
|
||||
System.err.println("错误部分: " + parts[1]);
|
||||
}
|
||||
} else {
|
||||
System.out.println("行格式不符合预期,跳过: " + line);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, String> getNetworkMode(String interfaceName) {
|
||||
|
||||
@@ -814,7 +814,140 @@ public class AgentUtil {
|
||||
int hz = getSystemHz();
|
||||
return (double) ticks / hz;
|
||||
}
|
||||
/**
|
||||
* 判断IPv6地址是否为公网地址
|
||||
* @param ipv6 IPv6地址字符串
|
||||
* @return true-公网地址, false-私网地址或无效地址
|
||||
*/
|
||||
public static boolean isPublicIPv6(String ipv6) {
|
||||
if (ipv6 == null || ipv6.trim().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// 规范化IPv6地址(处理缩写形式)
|
||||
String normalized = normalizeIPv6(ipv6);
|
||||
if (normalized == null) {
|
||||
return false; // 无效的IPv6地址
|
||||
}
|
||||
|
||||
// 私网地址范围:
|
||||
// 1. fc00::/7 - 唯一本地地址 (ULA)
|
||||
// 2. fe80::/10 - 链路本地地址
|
||||
// 3. ::1/128 - 环回地址
|
||||
// 4. ::/128 - 未指定地址
|
||||
|
||||
if (normalized.startsWith("fc") || normalized.startsWith("fd")) {
|
||||
return false; // fc00::/7 (ULA)
|
||||
}
|
||||
|
||||
if (normalized.startsWith("fe8") || normalized.startsWith("fe9") ||
|
||||
normalized.startsWith("fea") || normalized.startsWith("feb")) {
|
||||
return false; // fe80::/10 (链路本地)
|
||||
}
|
||||
|
||||
if (normalized.equals("00000000000000000000000000000001") ||
|
||||
normalized.equals("00000000000000000000000000000000")) {
|
||||
return false; // ::1 和 ::
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
return false; // 解析异常,视为无效地址
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 规范化IPv6地址为完整的32字符十六进制形式(无冒号)
|
||||
*/
|
||||
private static String normalizeIPv6(String ipv6) {
|
||||
// 处理环回和未指定地址的特殊情况
|
||||
if ("::1".equals(ipv6) || "::".equals(ipv6)) {
|
||||
return ipv6.equals("::1") ?
|
||||
"00000000000000000000000000000001" :
|
||||
"00000000000000000000000000000000";
|
||||
}
|
||||
|
||||
// 分离可能的IPv6字面量(如[::1]形式)
|
||||
ipv6 = ipv6.replaceAll("[\\[\\]]", "");
|
||||
|
||||
// 分离地址和端口(如果有)
|
||||
String[] parts = ipv6.split("%", 2); // 处理区域标识符
|
||||
String address = parts[0];
|
||||
|
||||
// 分离IPv4映射的IPv6地址(如::ffff:192.168.1.1)
|
||||
if (address.contains(".")) {
|
||||
if (address.startsWith("::ffff:")) {
|
||||
// IPv4映射地址,暂时按公网处理或根据需求调整
|
||||
return "00000000000000000000000000000000"; // 这里可根据需要调整
|
||||
}
|
||||
return null; // 无效的混合格式
|
||||
}
|
||||
|
||||
// 检查是否为缩写形式并扩展
|
||||
if (address.contains("::")) {
|
||||
address = expandDoubleColon(address);
|
||||
}
|
||||
|
||||
// 分割成8个16位块
|
||||
String[] blocks = address.split(":");
|
||||
if (blocks.length != 8) {
|
||||
return null; // 无效的IPv6格式
|
||||
}
|
||||
|
||||
// 将每个块扩展为4个十六进制字符
|
||||
StringBuilder normalized = new StringBuilder(32);
|
||||
for (String block : blocks) {
|
||||
if (block.length() > 4) {
|
||||
return null; // 无效的块长度
|
||||
}
|
||||
// 左侧补零到4位
|
||||
String padded = "0000" + block;
|
||||
normalized.append(padded.substring(padded.length() - 4));
|
||||
}
|
||||
|
||||
return normalized.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 扩展双冒号缩写
|
||||
*/
|
||||
private static String expandDoubleColon(String ipv6) {
|
||||
int doubleColonIndex = ipv6.indexOf("::");
|
||||
String[] parts = ipv6.split("::", -1);
|
||||
|
||||
if (parts.length != 2) {
|
||||
return ipv6; // 无效的双冒号格式
|
||||
}
|
||||
|
||||
String leftPart = parts[0];
|
||||
String rightPart = parts[1];
|
||||
|
||||
int leftCount = leftPart.isEmpty() ? 0 : leftPart.split(":").length;
|
||||
int rightCount = rightPart.isEmpty() ? 0 : rightPart.split(":").length;
|
||||
int zeroCount = 8 - (leftCount + rightCount);
|
||||
|
||||
if (zeroCount <= 0) {
|
||||
return ipv6; // 无效的缩写
|
||||
}
|
||||
|
||||
StringBuilder zeros = new StringBuilder();
|
||||
for (int i = 0; i < zeroCount; i++) {
|
||||
if (i > 0) zeros.append(":");
|
||||
zeros.append("0");
|
||||
}
|
||||
|
||||
if (leftPart.isEmpty() && rightPart.isEmpty()) {
|
||||
return zeros.toString();
|
||||
} else if (leftPart.isEmpty()) {
|
||||
return zeros + ":" + rightPart;
|
||||
} else if (rightPart.isEmpty()) {
|
||||
return leftPart + ":" + zeros;
|
||||
} else {
|
||||
return leftPart + ":" + zeros + ":" + rightPart;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user