规则判断

This commit is contained in:
=
2023-12-05 16:16:06 +08:00
parent a9fc8f4cb4
commit 306f2ed4d3
9 changed files with 146 additions and 28 deletions
@@ -6,8 +6,9 @@ import lombok.Getter;
@AllArgsConstructor
@Getter
public enum SecurityRulePassTypeEnum {
REJECT(0, "reject"),
ALLOW(1, "allow")
DENY(-1, "DENY"),
ALLOW(1, "allow"),
NONE(0, "none")
;
private final Integer code;
@@ -1,7 +1,7 @@
package org.dromara.neutrinoproxy.server.dal;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.dromara.neutrinoproxy.server.dal.entity.SecurityRule;
import org.dromara.neutrinoproxy.server.dal.entity.SecurityRuleDO;
public interface SecurityRuleMapper extends BaseMapper<SecurityRule> {
public interface SecurityRuleMapper extends BaseMapper<SecurityRuleDO> {
}
@@ -38,7 +38,7 @@ public class SecurityGroupDO {
* 启用状态
* {@link EnableStatusEnum}
*/
private Integer enable;
private EnableStatusEnum enable;
/**
* 创建时间
*/
@@ -10,7 +10,6 @@ import lombok.ToString;
import lombok.experimental.Accessors;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.SecurityRulePassTypeEnum;
import org.noear.solon.core.util.IpUtil;
import java.util.Date;
@@ -18,7 +17,7 @@ import java.util.Date;
@ToString
@Accessors(chain = true)
@TableName("security_rule")
public class SecurityRule {
public class SecurityRuleDO {
@TableId(type = IdType.AUTO)
private Integer id;
@@ -68,7 +67,7 @@ public class SecurityRule {
* 启用状态
* {@link EnableStatusEnum}
*/
private Integer enable;
private EnableStatusEnum enable;
/**
* 创建时间
*/
@@ -83,16 +82,16 @@ public class SecurityRule {
* @param ip
* @return
*/
public boolean allow(String ip) {
public SecurityRulePassTypeEnum allow(String ip) {
// 被判断的IP地址为空允许访问
// 被判断的IP地址为空做判断
if (StrUtil.isEmpty(ip)) {
return false;
return SecurityRulePassTypeEnum.NONE;
}
// 没有规则默认允许访问
if (StrUtil.isEmpty(rule)) {
return true;
return SecurityRulePassTypeEnum.ALLOW;
}
// ipv6只适配单ip形式
@@ -107,14 +106,16 @@ public class SecurityRule {
// 单个ip,ipv6在此步已处理后面不需要额外判断ipv6的情况
if (rule.matches("(\\d+\\.){3}\\d+") || isIpv6) {
return passType == SecurityRulePassTypeEnum.ALLOW && rule.equals(ip);
if (rule.equals(ip)) {
return passType == SecurityRulePassTypeEnum.ALLOW ? SecurityRulePassTypeEnum.ALLOW : SecurityRulePassTypeEnum.DENY;
}
}
// 范围类型
if (rule.matches("(\\d+\\.){3}\\d+-(\\d+\\.){3}\\d+")) {
String[] ipRange = rule.split("-");
if (ipRange[0].compareTo(ip) <= 0 && ip.compareTo(ipRange[1]) <= 0) {
return passType == SecurityRulePassTypeEnum.ALLOW;
return passType == SecurityRulePassTypeEnum.ALLOW ? SecurityRulePassTypeEnum.ALLOW : SecurityRulePassTypeEnum.DENY;
}
}
@@ -124,18 +125,18 @@ public class SecurityRule {
Long beginIp = Ipv4Util.getBeginIpLong(netIp[0], Integer.valueOf(netIp[1]));
Long endIp = Ipv4Util.getEndIpLong(netIp[0], Integer.valueOf(netIp[1]));
if (beginIp <= ipLong && ipLong <= endIp) {
return passType == SecurityRulePassTypeEnum.ALLOW;
return passType == SecurityRulePassTypeEnum.ALLOW ? SecurityRulePassTypeEnum.ALLOW : SecurityRulePassTypeEnum.DENY;
}
}
if (rule.equalsIgnoreCase("ALL") || rule.equals("0.0.0.0") || rule.equals("0..0.0.0/0")) {
return passType == SecurityRulePassTypeEnum.ALLOW;
return passType == SecurityRulePassTypeEnum.ALLOW ? SecurityRulePassTypeEnum.ALLOW : SecurityRulePassTypeEnum.DENY;
}
}
// 都没有匹配到默认放行
return true;
// 都没有匹配到
return SecurityRulePassTypeEnum.NONE;
}
}
@@ -1,6 +1,11 @@
package org.dromara.neutrinoproxy.server.proxy.core;
import cn.hutool.core.util.StrUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.dromara.neutrinoproxy.core.Constants;
import org.dromara.neutrinoproxy.core.ProxyMessage;
@@ -8,11 +13,6 @@ import org.dromara.neutrinoproxy.server.constant.NetworkProtocolEnum;
import org.dromara.neutrinoproxy.server.proxy.domain.VisitorChannelAttachInfo;
import org.dromara.neutrinoproxy.server.service.FlowReportService;
import org.dromara.neutrinoproxy.server.util.ProxyUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelOption;
import io.netty.channel.SimpleChannelInboundHandler;
import org.noear.solon.Solon;
import java.net.InetSocketAddress;
@@ -62,8 +62,11 @@ public class TcpVisitorChannelHandler extends SimpleChannelInboundHandler<ByteBu
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Channel visitorChannel = ctx.channel();
InetSocketAddress sa = (InetSocketAddress) visitorChannel.localAddress();
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort());
// 判断IP是否在该端口绑定的安全组允许的规则内
Channel cmdChannel = ProxyUtil.getCmdChannelByServerPort(sa.getPort());
if (null == cmdChannel) {
// 该端口还没有代理客户端
ctx.channel().close();
@@ -0,0 +1,76 @@
package org.dromara.neutrinoproxy.server.service;
import cn.hutool.cache.Cache;
import cn.hutool.cache.CacheUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.ibatis.solon.annotation.Db;
import org.dromara.neutrinoproxy.server.constant.EnableStatusEnum;
import org.dromara.neutrinoproxy.server.constant.SecurityRulePassTypeEnum;
import org.dromara.neutrinoproxy.server.dal.SecurityGroupMapper;
import org.dromara.neutrinoproxy.server.dal.SecurityRuleMapper;
import org.dromara.neutrinoproxy.server.dal.entity.SecurityGroupDO;
import org.dromara.neutrinoproxy.server.dal.entity.SecurityRuleDO;
import org.noear.solon.annotation.Component;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SecurityGroupService {
@Db
private SecurityGroupMapper securityGroupMapper;
@Db
private SecurityRuleMapper securityRuleMapper;
private Map<Integer, SecurityGroupDO> securityGroupMap = new ConcurrentHashMap<>();
// 允许通过控制的缓存,缓存类型最近最久未使用缓存,容量100,超时时间5分钟
private Cache<String, Boolean> ipAllowControlCache = CacheUtil.newLRUCache(100, 1000 * 60 * 5);
public void init() {
List<SecurityGroupDO> groupDOList = securityGroupMapper.selectList(Wrappers.lambdaQuery(SecurityGroupDO.class));
groupDOList.forEach(securityGroupDO -> securityGroupMap.put(securityGroupDO.getId(), securityGroupDO));
}
public boolean judgeAllow(String ip, Integer groupId) {
SecurityGroupDO groupDO = securityGroupMap.get(groupId);
if (groupDO == null || groupDO.getEnable() == EnableStatusEnum.DISABLE) {
return true;
}
String judgeAllowMapKey = ip + groupId;
if (ipAllowControlCache.containsKey(judgeAllowMapKey)) {
return ipAllowControlCache.get(judgeAllowMapKey);
}
List<SecurityRuleDO> ruleDOList = securityRuleMapper.selectList(Wrappers.lambdaQuery(SecurityRuleDO.class)
.eq(SecurityRuleDO::getGroupId, groupId)
.orderByAsc(SecurityRuleDO::getPriority)
);
Boolean allow = null;
for (SecurityRuleDO ruleDO : ruleDOList) {
SecurityRulePassTypeEnum passType = ruleDO.allow(ip);
if (passType == SecurityRulePassTypeEnum.ALLOW) {
allow = true;
break;
}
if (passType == SecurityRulePassTypeEnum.DENY) {
allow = false;
break;
}
}
if (allow == null) {
allow = true;
}
// 当前IP没有匹配到任何一条规则,则放行
ipAllowControlCache.put(judgeAllowMapKey, allow);
return allow;
}
}