From 306f2ed4d393ed7d78be47b6c3aef462d23baa8a Mon Sep 17 00:00:00 2001
From: = <=>
Date: Tue, 5 Dec 2023 16:16:06 +0800
Subject: [PATCH] =?UTF-8?q?=E8=A7=84=E5=88=99=E5=88=A4=E6=96=AD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
neutrino-proxy-core/pom.xml | 5 ++
.../constant/SecurityRulePassTypeEnum.java | 5 +-
.../server/dal/SecurityRuleMapper.java | 4 +-
.../server/dal/entity/SecurityGroupDO.java | 2 +-
...{SecurityRule.java => SecurityRuleDO.java} | 27 +++----
.../proxy/core/TcpVisitorChannelHandler.java | 15 ++--
.../server/service/SecurityGroupService.java | 76 +++++++++++++++++++
.../src/main/resources/app.yml | 10 ++-
.../resources/sql/mysql/init-structure.sql | 30 ++++++++
9 files changed, 146 insertions(+), 28 deletions(-)
rename neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/{SecurityRule.java => SecurityRuleDO.java} (81%)
create mode 100644 neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/service/SecurityGroupService.java
diff --git a/neutrino-proxy-core/pom.xml b/neutrino-proxy-core/pom.xml
index fc566dbf..f29d6890 100644
--- a/neutrino-proxy-core/pom.xml
+++ b/neutrino-proxy-core/pom.xml
@@ -30,6 +30,11 @@
hutool-core
${hutool.version}
+
+ cn.hutool
+ hutool-cache
+ ${hutool.version}
+
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/SecurityRulePassTypeEnum.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/SecurityRulePassTypeEnum.java
index 32d96759..60991e30 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/SecurityRulePassTypeEnum.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/constant/SecurityRulePassTypeEnum.java
@@ -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;
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/SecurityRuleMapper.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/SecurityRuleMapper.java
index 03f9f1b4..9ded6d66 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/SecurityRuleMapper.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/SecurityRuleMapper.java
@@ -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 {
+public interface SecurityRuleMapper extends BaseMapper {
}
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityGroupDO.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityGroupDO.java
index 9c07ff87..b1129c7b 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityGroupDO.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityGroupDO.java
@@ -38,7 +38,7 @@ public class SecurityGroupDO {
* 启用状态
* {@link EnableStatusEnum}
*/
- private Integer enable;
+ private EnableStatusEnum enable;
/**
* 创建时间
*/
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRule.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRuleDO.java
similarity index 81%
rename from neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRule.java
rename to neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRuleDO.java
index f72b895e..128940d4 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRule.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/dal/entity/SecurityRuleDO.java
@@ -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;
}
}
diff --git a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java
index 8f723802..3110dec7 100644
--- a/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java
+++ b/neutrino-proxy-server/src/main/java/org/dromara/neutrinoproxy/server/proxy/core/TcpVisitorChannelHandler.java
@@ -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 securityGroupMap = new ConcurrentHashMap<>();
+
+ // 允许通过控制的缓存,缓存类型最近最久未使用缓存,容量100,超时时间5分钟
+ private Cache ipAllowControlCache = CacheUtil.newLRUCache(100, 1000 * 60 * 5);
+
+ public void init() {
+ List 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 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;
+ }
+}
diff --git a/neutrino-proxy-server/src/main/resources/app.yml b/neutrino-proxy-server/src/main/resources/app.yml
index 665cfc83..cb798520 100644
--- a/neutrino-proxy-server/src/main/resources/app.yml
+++ b/neutrino-proxy-server/src/main/resources/app.yml
@@ -74,13 +74,15 @@ neutrino:
data:
db:
# 数据库类型,目前支持h2、mysql、mariadb
- type: ${DB_TYPE:h2}
+ # type: ${DB_TYPE:h2}
+ type: ${DB_TYPE:mysql}
# 数据库连接URL
- url: ${DB_URL:jdbc:h2:file:./data/db;MODE=MySQL;AUTO_SERVER=TRUE}
+ # url: ${DB_URL:jdbc:h2:file:./data/db;MODE=MySQL;AUTO_SERVER=TRUE}
+ url: ${DB_URL:jdbc:mysql://okfly.vip:37889/neutrino-proxy?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false&serverTimezone=UTC&allowPublicKeyRetrieval=true}
# 数据库用户名
- username: ${DB_USER:}
+ username: ${DB_USER:root}
# 数据库密码
- password: ${DB_PASSWORD:}
+ password: ${DB_PASSWORD:Root1234@}
#添加MIME印射(如果有需要?)
#是否启用静态文件服务。(可不配,默认为启用)
diff --git a/neutrino-proxy-server/src/main/resources/sql/mysql/init-structure.sql b/neutrino-proxy-server/src/main/resources/sql/mysql/init-structure.sql
index c6c0037b..f763edd0 100644
--- a/neutrino-proxy-server/src/main/resources/sql/mysql/init-structure.sql
+++ b/neutrino-proxy-server/src/main/resources/sql/mysql/init-structure.sql
@@ -50,6 +50,35 @@ CREATE TABLE IF NOT EXISTS `port_group` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;
+#安全组
+CREATE TABLE IF NOT EXISTS `security_group` (
+ `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `name` varchar(20) NOT NULL COMMENT '安全组名称',
+ `description` varchar(255) COMMENT '安全组描述',
+ `user_id` int NOT NULL COMMENT '用户ID',
+ `enable` int(1) NOT NULL COMMENT '启用状态',
+ `create_time` datetime(3) NOT NULL COMMENT '创建时间',
+ `update_time` datetime(3) NOT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+#安全组规则
+CREATE TABLE IF NOT EXISTS `security_rule` (
+ `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `group_id` int NOT NULL COMMENT '关联安全组',
+ `name` varchar(20) NOT NULL COMMENT '规则名称',
+ `description` varchar(255) NOT NULL COMMENT '规则描述',
+ `rule` text NOT NULL COMMENT '规则内容',
+ `pass_type` int(1) NOT NULL COMMENT '放行类型',
+ `priority` int(1) NOT NULL COMMENT '优先级',
+ `user_id` int NOT NULL COMMENT '用户ID',
+ `enable` int(1) NOT NULL COMMENT '启用状态',
+ `create_time` datetime(3) NOT NULL COMMENT '创建时间',
+ `update_time` datetime(3) NOT NULL COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ KEY `I_group_id_priority` (`group_id`, `priority`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
#############################代理配置相关表#############################
#license表
CREATE TABLE IF NOT EXISTS `license` (
@@ -207,3 +236,4 @@ CREATE TABLE IF NOT EXISTS `flow_report_month` (
KEY `I_flow_report_month_user_id` (`user_id`),
KEY `I_flow_report_month_license_id` (`license_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+