404 lines
19 KiB
Java
404 lines
19 KiB
Java
package com.realtime.protection.server.alertmessage;
|
||
|
||
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
|
||
import com.realtime.protection.configuration.entity.alert.AlertMessage;
|
||
import com.realtime.protection.configuration.entity.defense.template.ProtectLevel;
|
||
import com.realtime.protection.configuration.entity.task.FiveTupleWithMask;
|
||
import com.realtime.protection.configuration.entity.task.TaskCommandInfo;
|
||
import com.realtime.protection.configuration.utils.Counter;
|
||
import com.realtime.protection.configuration.utils.Subnet;
|
||
import com.realtime.protection.configuration.utils.enums.StateEnum;
|
||
import com.realtime.protection.configuration.utils.enums.TaskTypeEnum;
|
||
import com.realtime.protection.server.command.CommandService;
|
||
import com.realtime.protection.server.task.TaskService;
|
||
import com.realtime.protection.server.task.status.StateHandler;
|
||
import lombok.Data;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.springframework.stereotype.Service;
|
||
|
||
import java.net.UnknownHostException;
|
||
import java.time.Instant;
|
||
import java.time.LocalDateTime;
|
||
import java.time.ZoneId;
|
||
import java.time.format.DateTimeFormatter;
|
||
import java.util.ArrayList;
|
||
import java.util.Arrays;
|
||
import java.util.List;
|
||
import java.util.UUID;
|
||
|
||
// AlertMessage的UUID在mapper插入数据库时生成了,这里提前生成好像美神恶魔用
|
||
@Service
|
||
@Slf4j
|
||
public class AlertMessageService {
|
||
private final CommandService commandService;
|
||
private final AlertMessageMapper alertMessageMapper;
|
||
private final TaskService taskService;
|
||
private final Counter counter;
|
||
private final StateHandler stateHandler;
|
||
|
||
public AlertMessageService(CommandService commandService, AlertMessageMapper alertMessageMapper, TaskService taskService,
|
||
Counter counter, StateHandler stateHandler) {
|
||
this.commandService = commandService;
|
||
this.alertMessageMapper = alertMessageMapper;
|
||
this.taskService = taskService;
|
||
this.counter = counter;
|
||
this.stateHandler = stateHandler;
|
||
}
|
||
|
||
public Boolean updateAuditInfo(String id, String auditInfo) {
|
||
return alertMessageMapper.updateAuditInfo(id, auditInfo);
|
||
}
|
||
|
||
@DSTransactional
|
||
public void processAlertMessage(AlertMessage alertMessage) {
|
||
//将告警信息中的c_time转换为LocalDateTime,并写入ctime
|
||
Instant instant = Instant.ofEpochSecond(alertMessage.getC_time());
|
||
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
|
||
alertMessage.setCtime(localDateTime);
|
||
|
||
//根据告警信息——>生成指令
|
||
List<TaskCommandInfo> dynamicTaskCommandInfoList = generateDynamicCommand(alertMessage);
|
||
//可能isProtectSrcOrDst和isProtectSrcOrDst都为FALSE,说明没有生成指令
|
||
if(dynamicTaskCommandInfoList == null || dynamicTaskCommandInfoList.isEmpty()){
|
||
return;
|
||
}
|
||
//获取任务状态,设置指令的isValid字段,且是否生成指令入库(除了RUNING\PAUSED状态,其他都不入command库)。
|
||
Integer taskStatus = dynamicTaskCommandInfoList.get(0).getTaskStatus();
|
||
//获取任务类型,设置指令的isJudged字段。
|
||
Integer taskType = dynamicTaskCommandInfoList.get(0).getTaskType();
|
||
|
||
|
||
if (taskType == TaskTypeEnum.DYNAMIC.getTaskType())//实时
|
||
switch (StateEnum.getStateEnumByNum(taskStatus)) {
|
||
case RUNNING:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 1, alertMessage);
|
||
break;
|
||
case RUNNING_FAILED:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case RUNNING_PARTIAL_SUCCESS:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case RUNNING_SUCCESS:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case PAUSED:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, false, 1, alertMessage);
|
||
break;
|
||
default://主要是stop
|
||
//command不入库
|
||
//alertmessage入库
|
||
insertAlertMessageOnly(alertMessage);
|
||
break;
|
||
}
|
||
else if (taskType == TaskTypeEnum.JUDGED.getTaskType())//研判后
|
||
switch (StateEnum.getStateEnumByNum(taskStatus)) {
|
||
case RUNNING :
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case RUNNING_FAILED:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case RUNNING_PARTIAL_SUCCESS:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case RUNNING_SUCCESS:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, true, 0, alertMessage);
|
||
break;
|
||
case PAUSED:
|
||
insertCommandAndAlertMessage(dynamicTaskCommandInfoList, false, 0, alertMessage);
|
||
break;
|
||
default://主要是stop
|
||
//command不入库
|
||
//alertmessage入库
|
||
insertAlertMessageOnly(alertMessage);
|
||
}
|
||
}
|
||
|
||
|
||
private List<TaskCommandInfo> generateDynamicCommand(AlertMessage alertMessage){
|
||
Long taskId = alertMessage.getTaskId();
|
||
Integer DynamicRuleId = alertMessage.getDynamicRuleId();
|
||
// 查task信息
|
||
// (1)查询生成指令所需信息:和alertMessage中的fiveTuple信息 合并成 TaskCommandInfo;
|
||
// (2)额外信息:并额外查询templateId、protectLevel和taskStatus
|
||
TaskCommandInfo dynamicCommandInfo = alertMessageMapper.getDynamicTaskInfos(taskId, DynamicRuleId);
|
||
|
||
if (dynamicCommandInfo == null || dynamicCommandInfo.getTemplateId() == null){
|
||
throw new IllegalArgumentException("taskId: " + taskId + " DynamicRuleId: " + DynamicRuleId + " 不正确");
|
||
}
|
||
// 根据templateId、protectLevel获取策略模板
|
||
ProtectLevel templateProtectLevel = alertMessageMapper.queryTemplateProtectLevel(
|
||
dynamicCommandInfo.getTemplateId(),
|
||
dynamicCommandInfo.getProtectLevel());
|
||
|
||
//根据策略模板和alertMessage中的FiveTupleWithMask生成要下发五元组信息
|
||
//根据策略模板的is_full_flow字段,如果是双向流量会生成两个fiveTuple,所以返回List
|
||
List<FiveTupleWithMask> fiveTupleWithMaskNew = updateFiveTupleWithMask(alertMessage.getFiveTupleWithMask(),
|
||
alertMessage.getProtectIsSrcOrDst(), templateProtectLevel);
|
||
if(fiveTupleWithMaskNew.isEmpty()){
|
||
return null;
|
||
}
|
||
//根据fiveTuple生成动态指令信息
|
||
List<TaskCommandInfo> dynamicCommandInfoList = new ArrayList<>();
|
||
if (fiveTupleWithMaskNew.size() == 2){
|
||
TaskCommandInfo dynamicCommandInfo_bi = new TaskCommandInfo();
|
||
dynamicCommandInfo_bi.copyTaskCommandInfo(dynamicCommandInfo);
|
||
dynamicCommandInfo_bi.setFiveTupleWithMask(fiveTupleWithMaskNew.get(1));
|
||
dynamicCommandInfoList.add(dynamicCommandInfo_bi);
|
||
}
|
||
dynamicCommandInfo.setFiveTupleWithMask(fiveTupleWithMaskNew.get(0));
|
||
dynamicCommandInfoList.add(dynamicCommandInfo);
|
||
|
||
// //判断局点是否为多个,包含‘,’,多个的话,生成多个指令
|
||
// if (dynamicCommandInfo.getDistributePoint().contains(",")){
|
||
// List<TaskCommandInfo> dynamicCommandInfoList2 = new ArrayList<>();
|
||
// for (TaskCommandInfo dynamicCommandInfo1 : dynamicCommandInfoList){
|
||
// String[] distributePoints = dynamicCommandInfo1.getDistributePoint().split(",");
|
||
// for (String distributePoint : distributePoints){
|
||
// TaskCommandInfo dynamicCommandInfo2 = new TaskCommandInfo();
|
||
// dynamicCommandInfo2.copyTaskCommandInfo(dynamicCommandInfo1);
|
||
// dynamicCommandInfo2.setDistributePoint(distributePoint);
|
||
// dynamicCommandInfoList2.add(dynamicCommandInfo2);
|
||
// }
|
||
// }
|
||
// dynamicCommandInfoList = dynamicCommandInfoList2;
|
||
// }
|
||
//指令拆分局点,拆分后的指令放入staticTaskCommandInfosSplitDistributePoint
|
||
List<TaskCommandInfo> dynamicCommandInfoListSplitDistributePoint = new ArrayList<>();
|
||
for (TaskCommandInfo taskCommandInfo : dynamicCommandInfoList) {
|
||
//判断是否多局点
|
||
if (taskCommandInfo.getDistributePoint().contains(",")) {
|
||
String[] distributePointArray = taskCommandInfo.getDistributePoint().split(",");
|
||
for (String distributePoint : distributePointArray) {
|
||
TaskCommandInfo taskCommandInfoSplit = new TaskCommandInfo();
|
||
taskCommandInfoSplit.copyTaskCommandInfo(taskCommandInfo);
|
||
taskCommandInfoSplit.setDistributePoint(distributePoint);
|
||
dynamicCommandInfoListSplitDistributePoint.add(taskCommandInfoSplit);
|
||
}
|
||
}
|
||
else{
|
||
dynamicCommandInfoListSplitDistributePoint.add(taskCommandInfo);
|
||
}
|
||
}
|
||
|
||
|
||
|
||
return dynamicCommandInfoListSplitDistributePoint;
|
||
}
|
||
|
||
@DSTransactional
|
||
private void insertCommandAndAlertMessage(List<TaskCommandInfo> dynamicTaskCommandInfoList,
|
||
Boolean isValid,
|
||
Integer isJudged,
|
||
AlertMessage alertMessage){
|
||
|
||
List<String> commandUUIDs = new ArrayList<>();
|
||
List<Subnet> subnetList = new ArrayList<>();
|
||
|
||
|
||
//更新任务 影响ip数量字段,因为dynamicTaskCommandInfoList中的指令ip相同,所以只取一个指令计算
|
||
TaskCommandInfo dynamicTaskCommandInfo0 = dynamicTaskCommandInfoList.get(0);
|
||
try {
|
||
//抽取告警生成的指令没有掩码
|
||
String sip = dynamicTaskCommandInfo0.getFiveTupleWithMask().getSourceIP();
|
||
String msip = "255.255.255.255";
|
||
String dip = dynamicTaskCommandInfo0.getFiveTupleWithMask().getDestinationIP();
|
||
String mdip = "255.255.255.255";
|
||
|
||
if (sip != null) subnetList.add(new Subnet(sip,msip));
|
||
if (dip != null) subnetList.add(new Subnet(dip,mdip));
|
||
} catch (UnknownHostException e) {
|
||
throw new RuntimeException(e);
|
||
}
|
||
Long ipTotalNum = taskService.ipWithMaskToIpNums(subnetList);
|
||
taskService.updateTaskIpTotalNum(ipTotalNum, dynamicTaskCommandInfo0.getTaskId());
|
||
|
||
|
||
for (TaskCommandInfo dynamicTaskCommandInfo : dynamicTaskCommandInfoList ){
|
||
//command入库
|
||
dynamicTaskCommandInfo.setIsValid(isValid);
|
||
dynamicTaskCommandInfo.setIsJudged(isJudged);
|
||
String commandUUID = commandService.createCommand2(dynamicTaskCommandInfo, isJudged);
|
||
|
||
//alertmessage入库
|
||
|
||
alertMessage.setCommandUUID(commandUUID);
|
||
String alertMessageUUID = UUID.randomUUID().toString();
|
||
commandUUIDs.add(commandUUID);
|
||
alertMessage.setAlertMessageUUID(alertMessageUUID);
|
||
alertMessage.setDisplay_id(
|
||
"GJ-"
|
||
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
|
||
+ "-"
|
||
+ String.format("%06d", counter.generateId("alert_message"))
|
||
|
||
);
|
||
//t_alertMessage表目前唯一键导致覆盖了,加个uuid? 也存在多次插入问题
|
||
alertMessageMapper.insertAlertMessage(alertMessage);
|
||
}
|
||
|
||
|
||
}
|
||
private String insertAlertMessageOnly(AlertMessage alertMessage){
|
||
//alertmessage入库
|
||
alertMessage.setCommandUUID(null);
|
||
String alertMessageUUID = UUID.randomUUID().toString();
|
||
alertMessage.setAlertMessageUUID(alertMessageUUID);
|
||
alertMessage.setDisplay_id(
|
||
"GJ-"
|
||
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
|
||
+ "-"
|
||
+ String.format("%06d", counter.generateId("alert_message"))
|
||
|
||
);
|
||
alertMessageMapper.insertAlertMessage(alertMessage);
|
||
|
||
return alertMessageUUID;
|
||
|
||
}
|
||
|
||
|
||
|
||
private List<FiveTupleWithMask> updateFiveTupleWithMask(FiveTupleWithMask fiveTupleWithMask,
|
||
int protectIsSrcOrDst,
|
||
ProtectLevel templateProtectLevel) {
|
||
//参数是告警信息的FiveTupleWithMask、防护对象是src还是dst、某个安全等级下的安全事件策略模板templateProtectLevel
|
||
//首先先从告警信息中获取protectObject和peer
|
||
@Data
|
||
class CommunicateObject {
|
||
private String IP;
|
||
private String maskIP;
|
||
private String Port;
|
||
private String maskPort;
|
||
|
||
public CommunicateObject(String IP,
|
||
String maskIP,
|
||
String Port,
|
||
String maskPort) {
|
||
this.IP = IP;
|
||
this.maskIP = maskIP;
|
||
this.Port = Port;
|
||
this.maskPort = maskPort;
|
||
}
|
||
}
|
||
CommunicateObject protectObject;
|
||
CommunicateObject peer;
|
||
//0代表命中防护对象在告警信息的源ip
|
||
if (protectIsSrcOrDst == 0) {
|
||
protectObject = new CommunicateObject(
|
||
fiveTupleWithMask.getSourceIP(),
|
||
fiveTupleWithMask.getMaskSourceIP(),
|
||
fiveTupleWithMask.getSourcePort(),
|
||
fiveTupleWithMask.getMaskSourcePort()
|
||
);
|
||
peer = new CommunicateObject(
|
||
fiveTupleWithMask.getDestinationIP(),
|
||
fiveTupleWithMask.getMaskDestinationIP(),
|
||
fiveTupleWithMask.getDestinationPort(),
|
||
fiveTupleWithMask.getMaskDestinationPort()
|
||
);
|
||
} else {
|
||
protectObject = new CommunicateObject(
|
||
fiveTupleWithMask.getDestinationIP(),
|
||
fiveTupleWithMask.getMaskDestinationIP(),
|
||
fiveTupleWithMask.getDestinationPort(),
|
||
fiveTupleWithMask.getMaskDestinationPort()
|
||
);
|
||
peer = new CommunicateObject(
|
||
fiveTupleWithMask.getSourceIP(),
|
||
fiveTupleWithMask.getMaskSourceIP(),
|
||
fiveTupleWithMask.getSourcePort(),
|
||
fiveTupleWithMask.getMaskSourcePort()
|
||
);
|
||
}
|
||
//根据模板抽取防护对象和对端需要的字段
|
||
if (!templateProtectLevel.getHasProtectObjectIP()) {
|
||
protectObject.setIP(null);
|
||
protectObject.setMaskIP(null);
|
||
}
|
||
if (!templateProtectLevel.getHasProtectObjectPort()) {
|
||
protectObject.setPort(null);
|
||
protectObject.setMaskPort(null);
|
||
}
|
||
if (!templateProtectLevel.getHasPeerIP()) {
|
||
peer.setIP(null);
|
||
peer.setMaskIP(null);
|
||
}
|
||
if (!templateProtectLevel.getHasPeerPort()) {
|
||
peer.setPort(null);
|
||
peer.setMaskPort(null);
|
||
}
|
||
List<FiveTupleWithMask> newFiveTupleWithMask = new ArrayList<>();
|
||
//生成指令command1:防护对象为目的的五元组
|
||
FiveTupleWithMask command1 = new FiveTupleWithMask();
|
||
command1.setSourceIP(peer.getIP());
|
||
command1.setMaskSourceIP(peer.getMaskIP());
|
||
command1.setSourcePort(peer.getPort());
|
||
command1.setMaskSourcePort(peer.getMaskPort());
|
||
command1.setDestinationIP(protectObject.getIP());
|
||
command1.setMaskDestinationIP(protectObject.getMaskIP());
|
||
command1.setDestinationPort(protectObject.getPort());
|
||
command1.setMaskDestinationPort(protectObject.getMaskPort());
|
||
if (templateProtectLevel.getHasProtocol()){
|
||
command1.setProtocolNum(Integer.valueOf(fiveTupleWithMask.getProtocol()));
|
||
command1.setProtocol(fiveTupleWithMask.getProtocol());
|
||
command1.setMaskProtocol(fiveTupleWithMask.getMaskProtocol());
|
||
}
|
||
// newFiveTupleWithMask.add(command1);
|
||
//生成指令command2:防护对象为源的五元组
|
||
FiveTupleWithMask command2 = new FiveTupleWithMask();
|
||
|
||
command2.setSourceIP(protectObject.getIP());
|
||
command2.setMaskSourceIP(protectObject.getMaskIP());
|
||
command2.setSourcePort(protectObject.getPort());
|
||
command2.setMaskSourcePort(protectObject.getMaskPort());
|
||
|
||
command2.setDestinationIP(peer.getIP());
|
||
command2.setMaskDestinationIP(peer.getMaskIP());
|
||
command2.setDestinationPort(peer.getPort());
|
||
command2.setMaskDestinationPort(peer.getMaskPort());
|
||
if (templateProtectLevel.getHasProtocol()){
|
||
command2.setProtocol(fiveTupleWithMask.getProtocol());
|
||
command2.setProtocol(fiveTupleWithMask.getProtocol());
|
||
command2.setMaskProtocol(fiveTupleWithMask.getMaskProtocol());
|
||
}
|
||
/*
|
||
//若需要处置全方向流量,防护对象为源和目的的五元组都生成指令下发
|
||
if(templateProtectLevel.getIsFullFlow()){
|
||
newFiveTupleWithMask.add(command1);
|
||
newFiveTupleWithMask.add(command2);
|
||
}else {
|
||
//不需要处置全方向流量
|
||
// 判断防护对象为源还是目的,生成指令
|
||
if(templateProtectLevel.getIsProtectObjectIPSrc()){
|
||
newFiveTupleWithMask.add(command2);
|
||
}else {
|
||
newFiveTupleWithMask.add(command1);
|
||
}
|
||
}
|
||
*/
|
||
|
||
//若需要处置全方向流量,防护对象为源和目的的五元组都生成指令下发
|
||
|
||
// 判断防护对象为源还是目的,生成指令
|
||
if(templateProtectLevel.getIsProtectObjectSrc()){
|
||
newFiveTupleWithMask.add(command2);
|
||
}
|
||
if (templateProtectLevel.getIsProtectObjectDst()){
|
||
newFiveTupleWithMask.add(command1);
|
||
}
|
||
|
||
|
||
//目前告警信息还只是五元组,没有url、dns
|
||
return newFiveTupleWithMask;
|
||
}
|
||
|
||
|
||
|
||
public List<AlertMessage> queryAlarmsByCommandId(String commandId) {
|
||
|
||
return alertMessageMapper.queryAlermsByCommandId(commandId);
|
||
}
|
||
}
|