feat: add management ip whitelist

#303
This commit is contained in:
samwaf
2025-05-23 13:45:17 +08:00
parent 63226568fd
commit 40fa30367a
10 changed files with 193 additions and 2 deletions

View File

@@ -40,6 +40,7 @@ type APIGroup struct {
WafPrivateInfoApi
WafCacheRuleApi
WafTunnelApi
WafVpConfigApi
}
var APIGroupAPP = new(APIGroup)

44
api/waf_vpconfig_api.go Normal file
View File

@@ -0,0 +1,44 @@
package api
import (
"SamWaf/global"
"SamWaf/model/common/response"
"SamWaf/model/request"
response2 "SamWaf/model/response"
"SamWaf/wafconfig"
"github.com/gin-gonic/gin"
)
type WafVpConfigApi struct {
}
// UpdateIpWhitelistApi 更新IP白名单配置
func (w *WafVpConfigApi) UpdateIpWhitelistApi(c *gin.Context) {
var req request.WafVpConfigIpWhitelistUpdateReq
err := c.ShouldBindJSON(&req)
if err == nil {
// 调用配置文件更新函数
err = wafconfig.UpdateIpWhitelist(req.IpWhitelist)
if err != nil {
response.FailWithMessage("更新IP白名单失败: "+err.Error(), c)
} else {
response.OkWithMessage("更新IP白名单成功", c)
}
} else {
response.FailWithMessage("解析请求失败", c)
}
}
// GetIpWhitelistApi 获取IP白名单配置
func (w *WafVpConfigApi) GetIpWhitelistApi(c *gin.Context) {
// 直接从全局变量获取IP白名单
ipWhitelist := global.GWAF_IP_WHITELIST
// 构造响应数据
resp := response2.WafVpConfigIpWhitelistGetResp{
IpWhitelist: ipWhitelist,
}
response.OkWithDetailed(resp, "获取IP白名单成功", c)
}

View File

@@ -65,6 +65,9 @@ var (
GWAF_CUSTOM_SERVER_NAME string // 当前服务器自定义名称
GWAF_TENANT_ID string = "SamWafCom" // 当前租户ID
//管理端访问控制
GWAF_IP_WHITELIST string = "0.0.0.0/0,::/0" //IP白名单 后台默认放行所有
//zlog 日志相关信息
GWAF_LOG_OUTPUT_FORMAT string = "console" //zlog输出格式 控制台格式console,json格式
GWAF_RELEASE string = "false" // 当前是否为发行版

View File

@@ -0,0 +1,51 @@
package middleware
import (
"SamWaf/global"
"github.com/gin-gonic/gin"
"net"
"net/http"
"strings"
)
// IPWhitelist IP白名单中间件
func IPWhitelist() gin.HandlerFunc {
return func(c *gin.Context) {
clientIP := c.ClientIP()
allowed := false
allowedIPs := strings.Split(global.GWAF_IP_WHITELIST, ",")
if global.GWAF_IP_WHITELIST == "0.0.0.0/0,::/0" {
allowed = true
} else if len(allowedIPs) == 0 {
allowed = true
} else {
for _, ip := range allowedIPs {
if ip == "0.0.0.0/0" || ip == "::/0" {
allowed = true
break
}
if isIPMatch(clientIP, ip) {
allowed = true
break
}
}
}
if !allowed {
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
"message": "Access denied",
})
return
}
c.Next()
}
}
// 支持 CIDR 范围匹配,例如 "192.168.0.0/16"
func isIPMatch(clientIP, allowed string) bool {
if _, ipNet, err := net.ParseCIDR(allowed); err == nil {
return ipNet.Contains(net.ParseIP(clientIP))
}
return clientIP == allowed
}

View File

@@ -0,0 +1,6 @@
package request
// WafVpConfigIpWhitelistUpdateReq IP白名单更新请求
type WafVpConfigIpWhitelistUpdateReq struct {
IpWhitelist string `json:"ip_whitelist"` // IP白名单多个IP用逗号分隔
}

View File

@@ -0,0 +1,6 @@
package response
// WafVpConfigIpWhitelistGetResp IP白名单获取响应
type WafVpConfigIpWhitelistGetResp struct {
IpWhitelist string `json:"ip_whitelist"` // IP白名单多个IP用逗号分隔
}

View File

@@ -38,6 +38,7 @@ type ApiGroup struct {
WafPrivateInfoRouter
WafCacheRuleRouter
WafTunnelRouter
WafVpConfigRouter
}
type PublicApiGroup struct {
LoginRouter

View File

@@ -0,0 +1,16 @@
package router
import (
"SamWaf/api"
"github.com/gin-gonic/gin"
)
type WafVpConfigRouter struct {
}
func (receiver *WafVpConfigRouter) InitWafVpConfigRouter(group *gin.RouterGroup) {
wafVpConfigApi := api.APIGroupAPP.WafVpConfigApi
router := group.Group("")
router.POST("/samwaf/vipconfig/updateIpWhitelist", wafVpConfigApi.UpdateIpWhitelistApi)
router.GET("/samwaf/vipconfig/getIpWhitelist", wafVpConfigApi.GetIpWhitelistApi)
}

View File

@@ -102,6 +102,13 @@ func LoadAndInitConfig() {
configChanged = true
}
//配置和提取白名单
if config.IsSet("security.ip_whitelist") {
global.GWAF_IP_WHITELIST = config.GetString("security.ip_whitelist")
} else {
config.Set("security.ip_whitelist", global.GWAF_IP_WHITELIST)
configChanged = true
}
// 只有在配置发生变化时才写入文件
if configChanged {
err := config.WriteConfig()
@@ -115,3 +122,55 @@ func LoadAndInitConfig() {
fmt.Printf("%s\tINFO\tuser_code:%s ,soft_id:%s\n",
currentTime, global.GWAF_USER_CODE, global.GWAF_TENANT_ID)
}
// UpdateIpWhitelist 更新IP白名单配置
func UpdateIpWhitelist(ipWhitelist string) error {
// 格式化当前时间为指定格式
currentTime := time.Now().Format("2006-01-02 15:04:05.000")
// 判断配置目录是否存在
configDir := utils.GetCurrentDir() + "/conf/"
if _, err := os.Stat(configDir); os.IsNotExist(err) {
if err := os.MkdirAll(configDir, os.ModePerm); err != nil {
fmt.Printf("%s\tERROR\t创建config目录失败:%v\n", currentTime, err)
return err
}
}
config := viper.New()
config.AddConfigPath(configDir) // 文件所在目录
config.SetConfigName("config") // 文件名
config.SetConfigType("yml") // 文件类型
// 读取配置文件
if err := config.ReadInConfig(); err != nil {
if _, ok := err.(viper.ConfigFileNotFoundError); ok {
fmt.Printf("%s\tWARN\t找不到配置文件..\n", currentTime)
config.Set("local_port", global.GWAF_LOCAL_SERVER_PORT)
err = config.SafeWriteConfig()
if err != nil {
return err
}
} else {
fmt.Printf("%s\tERROR\t配置文件出错..\n", currentTime)
return err
}
}
// 更新IP白名单配置
config.Set("security.ip_whitelist", ipWhitelist)
// 更新全局变量
global.GWAF_IP_WHITELIST = ipWhitelist
// 写入配置文件
err := config.WriteConfig()
if err != nil {
fmt.Printf("%s\tERROR\twrite config failed:%v\n", currentTime, err)
return err
}
fmt.Printf("%s\tINFO\tIP whitelist config updated\n", currentTime)
return nil
}

View File

@@ -28,12 +28,12 @@ type WafWebManager struct {
func (web *WafWebManager) initRouter(r *gin.Engine) {
PublicRouterGroup := r.Group("")
PublicRouterGroup.Use(middleware.SecApi())
PublicRouterGroup.Use(middleware.SecApi(), middleware.IPWhitelist())
router.PublicApiGroupApp.InitLoginRouter(PublicRouterGroup)
router.PublicApiGroupApp.InitCenterRouter(PublicRouterGroup) //注册中心接收接口
RouterGroup := r.Group("")
RouterGroup.Use(middleware.Auth(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare()) //TODO 中心管控 特定
RouterGroup.Use(middleware.Auth(), middleware.CenterApi(), middleware.SecApi(), middleware.GinGlobalExceptionMiddleWare(), middleware.IPWhitelist()) //TODO 中心管控 特定
{
router.ApiGroupApp.InitHostRouter(RouterGroup)
router.ApiGroupApp.InitLogRouter(RouterGroup)
@@ -72,6 +72,7 @@ func (web *WafWebManager) initRouter(r *gin.Engine) {
router.ApiGroupApp.InitWafPrivateInfoRouter(RouterGroup)
router.ApiGroupApp.InitWafCacheRuleRouter(RouterGroup)
router.ApiGroupApp.InitWafTunnelRouter(RouterGroup)
router.ApiGroupApp.InitWafVpConfigRouter(RouterGroup)
}
if global.GWAF_RELEASE == "true" {
@@ -130,6 +131,9 @@ func (web *WafWebManager) StartLocalServer() error {
gin.SetMode(gin.ReleaseMode)
gin.DefaultWriter = io.Discard
}
if global.GWAF_IP_WHITELIST == "0.0.0.0/0,::/0" {
zlog.Warn("管理端未配置 IP 白名单,默认允许所有 IP40.0.0.0/0 IPv6 ::/0 访问")
}
r := gin.Default()
r.Use(web.cors()) //解决跨域
web.initRouter(r)