mirror of
https://gitee.com/samwaf/SamWaf.git
synced 2026-10-31 02:01:44 +08:00
feat:change ssl load method
This commit is contained in:
@@ -42,6 +42,7 @@ import (
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
"time"
|
||||
@@ -221,7 +222,10 @@ func (m *wafSystenService) run() {
|
||||
HostTargetNoPort: map[string]string{},
|
||||
ServerOnline: map[int]innerbean.ServerRunTime{},
|
||||
//所有证书情况 对应端口 可能多个端口都是https 443,或者其他非标准端口也要实现https证书
|
||||
AllCertificate: map[int]map[string]*tls.Certificate{},
|
||||
AllCertificate: wafenginecore.AllCertificate{
|
||||
Mux: sync.Mutex{},
|
||||
Map: map[string]*tls.Certificate{},
|
||||
},
|
||||
|
||||
EngineCurrentStatus: 0, // 当前waf引擎状态
|
||||
Sensitive: make([]model.Sensitive, 0),
|
||||
@@ -441,11 +445,11 @@ func (m *wafSystenService) run() {
|
||||
}
|
||||
//如果本次是关闭,那么应该关闭主机
|
||||
if hosts[0].START_STATUS == 1 {
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hosts[0], false)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hosts[0])
|
||||
}
|
||||
//如果本次ssl和上次ssl不同
|
||||
if hosts[0].Ssl != hostsOld.Ssl || hosts[0].Keyfile != hostsOld.Keyfile || hosts[0].Certfile != hostsOld.Certfile {
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hosts[0], true)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hosts[0])
|
||||
}
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.LoadHost(hosts[0])
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.StartAllProxyServer()
|
||||
@@ -456,7 +460,7 @@ func (m *wafSystenService) run() {
|
||||
len(globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.HostTarget[hostsOld.Host+":"+strconv.Itoa(hostsOld.Port)].LoadBalanceRuntime.RevProxies) > 0 {
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.HostTarget[hostsOld.Host+":"+strconv.Itoa(hostsOld.Port)].LoadBalanceRuntime.RevProxies = nil
|
||||
}
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hostsOld, false)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(hostsOld)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.LoadHost(hosts[0])
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.StartAllProxyServer()
|
||||
}
|
||||
@@ -467,7 +471,7 @@ func (m *wafSystenService) run() {
|
||||
case enums.ChanTypeDelHost:
|
||||
host := msg.Content.(model.Hosts)
|
||||
if host.Id != "" {
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(host, false)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(host)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.EnumAllPortProxyServer()
|
||||
}
|
||||
break
|
||||
@@ -476,7 +480,7 @@ func (m *wafSystenService) run() {
|
||||
break
|
||||
case enums.ChanTypeSSL:
|
||||
host := msg.Content.(model.Hosts)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(host, true)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.RemoveHost(host)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.LoadHost(host)
|
||||
globalobj.GWAF_RUNTIME_OBJ_WAF_ENGINE.StartAllProxyServer()
|
||||
break
|
||||
|
||||
@@ -200,7 +200,7 @@ func (receiver *WafHostService) CheckPortExistApi(port int) int64 {
|
||||
|
||||
func (receiver *WafHostService) CheckAvailablePortExistApi(port int) int64 {
|
||||
var total int64 = 0
|
||||
global.GWAF_LOCAL_DB.Model(&model.Hosts{}).Where(" (start_status = 0 or start_status is null) and port=?", port).Count(&total)
|
||||
global.GWAF_LOCAL_DB.Model(&model.Hosts{}).Where(" start_status = 0 and port=?", port).Count(&total)
|
||||
return total
|
||||
}
|
||||
|
||||
|
||||
@@ -271,3 +271,29 @@ func GetPureDomain(host string) string {
|
||||
}
|
||||
return host
|
||||
}
|
||||
|
||||
// UpdateFileIsHasNewInfo 检查文件内容并更新
|
||||
func UpdateFileIsHasNewInfo(filePath, newContent string) error {
|
||||
// 检查文件是否存在
|
||||
if _, err := os.Stat(filePath); os.IsNotExist(err) {
|
||||
// 文件不存在,写入新内容
|
||||
if err := ioutil.WriteFile(filePath, []byte(newContent), 0644); err != nil {
|
||||
return fmt.Errorf("failed to write file %s: %v", filePath, err)
|
||||
}
|
||||
} else {
|
||||
// 文件存在,读取当前内容
|
||||
currentContent, err := ioutil.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read file %s: %v", filePath, err)
|
||||
}
|
||||
|
||||
// 比较内容是否一致
|
||||
if string(currentContent) != newContent {
|
||||
// 内容不一致,更新文件
|
||||
if err := ioutil.WriteFile(filePath, []byte(newContent), 0644); err != nil {
|
||||
return fmt.Errorf("failed to update file %s: %v", filePath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,4 +61,11 @@ func pathCoreSql(db *gorm.DB) {
|
||||
} else {
|
||||
zlog.Info("db", "hosts :auto_jump_https init successfully")
|
||||
}
|
||||
//20241030 初始化一次状态信息
|
||||
err = db.Exec("UPDATE hosts SET start_status=0 WHERE start_status IS NULL ").Error
|
||||
if err != nil {
|
||||
panic("failed to hosts :start_status " + err.Error())
|
||||
} else {
|
||||
zlog.Info("db", "hosts :start_status init successfully")
|
||||
}
|
||||
}
|
||||
|
||||
+1
-18
@@ -7,12 +7,10 @@ import (
|
||||
"SamWaf/wafproxy"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -97,28 +95,13 @@ func (waf *WafEngine) createTransport(r *http.Request, host string, isEnableLoad
|
||||
if r.TLS != nil {
|
||||
// 增加https标识
|
||||
customHeaders["X-FORWARDED-PROTO"] = "https"
|
||||
|
||||
hostParts := strings.Split(host, ":")
|
||||
port := "443"
|
||||
if len(hostParts) == 2 {
|
||||
port = hostParts[1]
|
||||
}
|
||||
transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
NameToCertificate: make(map[string]*tls.Certificate, 0),
|
||||
InsecureSkipVerify: false,
|
||||
GetCertificate: waf.GetCertificateFunc,
|
||||
},
|
||||
DialContext: dialContext,
|
||||
}
|
||||
portInt, _ := strconv.Atoi(port)
|
||||
|
||||
transport.TLSClientConfig.NameToCertificate = waf.AllCertificate[portInt]
|
||||
transport.TLSClientConfig.GetCertificate = func(clientInfo *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if x509Cert, ok := transport.TLSClientConfig.NameToCertificate[clientInfo.ServerName]; ok {
|
||||
return x509Cert, nil
|
||||
}
|
||||
return nil, errors.New("config error")
|
||||
}
|
||||
} else {
|
||||
transport = &http.Transport{
|
||||
DialContext: dialContext,
|
||||
|
||||
+103
-253
@@ -10,11 +10,9 @@ import (
|
||||
"SamWaf/model/baseorm"
|
||||
"SamWaf/model/detection"
|
||||
"SamWaf/model/wafenginmodel"
|
||||
"SamWaf/service/waf_service"
|
||||
"SamWaf/utils"
|
||||
"SamWaf/wafenginecore/loadbalance"
|
||||
"SamWaf/wafproxy"
|
||||
"SamWaf/webplugin"
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/flate"
|
||||
@@ -31,7 +29,6 @@ import (
|
||||
"golang.org/x/text/encoding"
|
||||
"golang.org/x/text/encoding/unicode"
|
||||
"golang.org/x/text/transform"
|
||||
"golang.org/x/time/rate"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -40,6 +37,7 @@ import (
|
||||
"runtime/debug"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
@@ -54,16 +52,108 @@ type WafEngine struct {
|
||||
//服务在线情况(key:端口,value :服务情况)
|
||||
ServerOnline map[int]innerbean.ServerRunTime
|
||||
|
||||
//所有证书情况 对应端口 可能多个端口都是https 443,或者其他非标准端口也要实现https证书
|
||||
//嵌套结构 (key:端口 ,再往下是 下面的主机名,value 证书)
|
||||
AllCertificate map[int]map[string]*tls.Certificate
|
||||
|
||||
EngineCurrentStatus int // 当前waf引擎状态
|
||||
AllCertificate AllCertificate //所有证书
|
||||
EngineCurrentStatus int // 当前waf引擎状态
|
||||
|
||||
//敏感词管理
|
||||
Sensitive []model.Sensitive //敏感词
|
||||
SensitiveManager *goahocorasick.Machine
|
||||
}
|
||||
type AllCertificate struct {
|
||||
Mux sync.Mutex
|
||||
Map map[string]*tls.Certificate
|
||||
}
|
||||
|
||||
// LoadSSL 加载证书
|
||||
func (ac *AllCertificate) LoadSSL(domain string, cert string, key string) error {
|
||||
ac.Mux.Lock()
|
||||
defer ac.Mux.Unlock()
|
||||
domain = strings.ToLower(domain)
|
||||
// 加载新的证书
|
||||
newCert, err := tls.X509KeyPair([]byte(cert), []byte(key))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certificate, ok := ac.Map[domain]
|
||||
if !ok {
|
||||
ac.Map[domain] = &newCert
|
||||
return nil
|
||||
} else {
|
||||
if certificate == nil {
|
||||
ac.Map[domain] = &newCert
|
||||
return nil
|
||||
}
|
||||
if certificate != nil && certificate.Certificate[0] != nil {
|
||||
zlog.Debug("需要重新加载证书")
|
||||
ac.Map[domain] = &newCert
|
||||
}
|
||||
}
|
||||
|
||||
// 检查域名是否已存在,如果存在则替换
|
||||
ac.Map[domain] = &newCert
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadSSLByFilePath 加载证书从文件
|
||||
func (ac *AllCertificate) LoadSSLByFilePath(domain string, certPath string, keyPath string) error {
|
||||
ac.Mux.Lock()
|
||||
defer ac.Mux.Unlock()
|
||||
domain = strings.ToLower(domain)
|
||||
// 加载新的证书
|
||||
newCert, err := tls.LoadX509KeyPair(certPath, keyPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certificate, ok := ac.Map[domain]
|
||||
if !ok {
|
||||
ac.Map[domain] = &newCert
|
||||
return nil
|
||||
} else {
|
||||
if certificate != nil && certificate.Certificate[0] != nil {
|
||||
//TODO 需要处理只有不同的情况才进行加载
|
||||
zlog.Debug("需要重新加载证书")
|
||||
ac.Map[domain] = &newCert
|
||||
}
|
||||
}
|
||||
|
||||
// 检查域名是否已存在,如果存在则替换
|
||||
ac.Map[domain] = &newCert
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveSSL 移除证书
|
||||
func (ac *AllCertificate) RemoveSSL(domain string) error {
|
||||
ac.Mux.Lock()
|
||||
defer ac.Mux.Unlock()
|
||||
domain = strings.ToLower(domain)
|
||||
_, ok := ac.Map[domain]
|
||||
if ok {
|
||||
ac.Map[domain] = nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSSL 加载证书
|
||||
func (ac *AllCertificate) GetSSL(domain string) *tls.Certificate {
|
||||
ac.Mux.Lock()
|
||||
defer ac.Mux.Unlock()
|
||||
domain = strings.ToLower(domain)
|
||||
certificate, ok := ac.Map[domain]
|
||||
if ok {
|
||||
return certificate
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetCertificateFunc 获取证书的函数
|
||||
func (waf *WafEngine) GetCertificateFunc(clientInfo *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
zlog.Debug("GetCertificate ", clientInfo.ServerName)
|
||||
x509Cert := waf.AllCertificate.GetSSL(clientInfo.ServerName)
|
||||
if x509Cert != nil {
|
||||
return x509Cert, nil
|
||||
}
|
||||
return nil, errors.New("config error")
|
||||
}
|
||||
|
||||
func (waf *WafEngine) Error() string {
|
||||
fs := "HTTP: %d, HostCode: %d, Message: %s"
|
||||
@@ -698,7 +788,7 @@ func (waf *WafEngine) StartWaf() {
|
||||
waf.StartAllProxyServer()
|
||||
}
|
||||
|
||||
// 关闭waf
|
||||
// CloseWaf 关闭waf
|
||||
func (waf *WafEngine) CloseWaf() {
|
||||
defer func() {
|
||||
e := recover()
|
||||
@@ -726,216 +816,9 @@ func (waf *WafEngine) CloseWaf() {
|
||||
waf.HostCode = map[string]string{}
|
||||
waf.HostTargetNoPort = map[string]string{}
|
||||
waf.ServerOnline = map[int]innerbean.ServerRunTime{}
|
||||
waf.AllCertificate = map[int]map[string]*tls.Certificate{}
|
||||
|
||||
}
|
||||
|
||||
// 加载全部host
|
||||
func (waf *WafEngine) LoadAllHost() {
|
||||
//重新查询
|
||||
var hosts []model.Hosts
|
||||
global.GWAF_LOCAL_DB.Find(&hosts)
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
waf.LoadHost(hosts[i])
|
||||
}
|
||||
}
|
||||
|
||||
// 加载指定host
|
||||
func (waf *WafEngine) LoadHost(inHost model.Hosts) innerbean.ServerRunTime {
|
||||
|
||||
//检测https
|
||||
if inHost.Ssl == 1 {
|
||||
cert, err := tls.X509KeyPair([]byte(inHost.Certfile), []byte(inHost.Keyfile))
|
||||
if err != nil {
|
||||
zlog.Warn("Cannot find %s cert & key file. Error is: %s\n", inHost.Host, err)
|
||||
return innerbean.ServerRunTime{}
|
||||
|
||||
}
|
||||
mm, ok := waf.AllCertificate[inHost.Port] //[hosts[i].Host]
|
||||
if !ok {
|
||||
mm = make(map[string]*tls.Certificate)
|
||||
waf.AllCertificate[inHost.Port] = mm
|
||||
}
|
||||
waf.AllCertificate[inHost.Port][inHost.Host] = &cert
|
||||
}
|
||||
_, ok := waf.ServerOnline[inHost.Port]
|
||||
if ok == false && inHost.GLOBAL_HOST == 0 {
|
||||
if inHost.START_STATUS == 0 {
|
||||
waf.ServerOnline[inHost.Port] = innerbean.ServerRunTime{
|
||||
ServerType: utils.GetServerByHosts(inHost),
|
||||
Port: inHost.Port,
|
||||
Status: 1,
|
||||
}
|
||||
} else {
|
||||
delete(waf.ServerOnline, inHost.Port)
|
||||
}
|
||||
|
||||
}
|
||||
//检查是否存在强制跳转HTTPS的情况
|
||||
if inHost.AutoJumpHTTPS == 1 {
|
||||
default80Port := 80
|
||||
_, ok := waf.ServerOnline[default80Port]
|
||||
if ok == false && inHost.GLOBAL_HOST == 0 {
|
||||
if inHost.START_STATUS == 0 {
|
||||
waf.ServerOnline[default80Port] = innerbean.ServerRunTime{
|
||||
ServerType: "http",
|
||||
Port: default80Port,
|
||||
Status: 1,
|
||||
}
|
||||
} else {
|
||||
delete(waf.ServerOnline, default80Port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//加载主机对于的规则
|
||||
ruleHelper := &utils.RuleHelper{}
|
||||
ruleHelper.InitRuleEngine()
|
||||
//查询规则
|
||||
var vcnt int
|
||||
global.GWAF_LOCAL_DB.Model(&model.Rules{}).Where("host_code = ? and rule_status<>999",
|
||||
inHost.Code).Select("sum(rule_version) as vcnt").Row().Scan(&vcnt)
|
||||
zlog.Debug("主机host" + inHost.Code + " 版本" + strconv.Itoa(vcnt))
|
||||
var ruleconfigs []model.Rules
|
||||
if vcnt > 0 {
|
||||
global.GWAF_LOCAL_DB.Where("host_code = ?and rule_status<>999", inHost.Code).Find(&ruleconfigs)
|
||||
ruleHelper.LoadRules(ruleconfigs)
|
||||
}
|
||||
//查询ip限流(应该针对一个网址只有一个)
|
||||
var anticcBean model.AntiCC
|
||||
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Limit(1).Find(&anticcBean)
|
||||
|
||||
//初始化插件-ip计数器
|
||||
var pluginIpRateLimiter *webplugin.IPRateLimiter
|
||||
if anticcBean.Id != "" {
|
||||
pluginIpRateLimiter = webplugin.NewIPRateLimiter(rate.Limit(anticcBean.Rate), anticcBean.Limit)
|
||||
}
|
||||
|
||||
//查询ip白名单
|
||||
var ipwhitelist []model.IPAllowList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ipwhitelist)
|
||||
|
||||
//查询url白名单
|
||||
var urlwhitelist []model.URLAllowList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&urlwhitelist)
|
||||
|
||||
//查询ip黑名单
|
||||
var ipblocklist []model.IPBlockList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ipblocklist)
|
||||
|
||||
//查询url白名单
|
||||
var urlblocklist []model.URLBlockList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&urlblocklist)
|
||||
|
||||
//查询url隐私保护
|
||||
var ldpurls []model.LDPUrl
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ldpurls)
|
||||
|
||||
//查询负载均衡
|
||||
var loadBalanceList []model.LoadBalance
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&loadBalanceList)
|
||||
//初始化主机host
|
||||
hostsafe := &wafenginmodel.HostSafe{
|
||||
LoadBalanceRuntime: &wafenginmodel.LoadBalanceRuntime{
|
||||
CurrentProxyIndex: 0,
|
||||
RevProxies: []*wafproxy.ReverseProxy{},
|
||||
WeightRoundRobinBalance: &loadbalance.WeightRoundRobinBalance{},
|
||||
IpHashBalance: loadbalance.NewConsistentHashBalance(nil),
|
||||
},
|
||||
LoadBalanceLists: loadBalanceList,
|
||||
Rule: ruleHelper,
|
||||
TargetHost: inHost.Remote_host + ":" + strconv.Itoa(inHost.Remote_port),
|
||||
RuleData: ruleconfigs,
|
||||
RuleVersionSum: vcnt,
|
||||
Host: inHost,
|
||||
PluginIpRateLimiter: pluginIpRateLimiter,
|
||||
IPWhiteLists: ipwhitelist,
|
||||
UrlWhiteLists: urlwhitelist,
|
||||
LdpUrlLists: ldpurls,
|
||||
IPBlockLists: ipblocklist,
|
||||
UrlBlockLists: urlblocklist,
|
||||
}
|
||||
hostsafe.Mux.Lock()
|
||||
defer hostsafe.Mux.Unlock()
|
||||
//目标关系情况
|
||||
waf.HostTarget[inHost.Host+":"+strconv.Itoa(inHost.Port)] = hostsafe
|
||||
//赋值到对照表里面
|
||||
waf.HostCode[inHost.Code] = inHost.Host + ":" + strconv.Itoa(inHost.Port)
|
||||
|
||||
//如果存在强制跳转
|
||||
if inHost.AutoJumpHTTPS == 1 {
|
||||
waf.HostTarget[inHost.Host+":80"] = hostsafe
|
||||
waf.HostCode[inHost.Code] = inHost.Host + ":80"
|
||||
}
|
||||
//如果是不限制端口的情况
|
||||
if inHost.UnrestrictedPort == 1 {
|
||||
zlog.Debug("来源端口宽松模式")
|
||||
waf.HostTargetNoPort[inHost.Host] = inHost.Host + ":" + strconv.Itoa(inHost.Port)
|
||||
} else {
|
||||
if _, ok := waf.HostTargetNoPort[inHost.Host]; ok {
|
||||
zlog.Debug("来源端口严苛模式")
|
||||
delete(waf.HostTargetNoPort, inHost.Host)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return waf.ServerOnline[inHost.Port]
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
移除主机
|
||||
*/
|
||||
func (waf *WafEngine) RemoveHost(host model.Hosts, isSslChange bool) {
|
||||
/*//主机情况
|
||||
HostTarget map[string]*wafenginmodel.HostSafe
|
||||
//主机和code的关系
|
||||
HostCode map[string]string
|
||||
ServerOnline map[int]innerbean.ServerRunTime
|
||||
|
||||
//所有证书情况 对应端口 可能多个端口都是https 443,或者其他非标准端口也要实现https证书
|
||||
AllCertificate map[int]map[string]*tls.Certificate*/
|
||||
//1.如果这个port里面没有了主机 那可以直接停掉服务
|
||||
//2.除了第一个情况之外的,把所有他的主机信息和关联信息都干掉
|
||||
|
||||
if waf_service.WafHostServiceApp.CheckAvailablePortExistApi(host.Port) == 0 || isSslChange {
|
||||
zlog.Debug("准备移除这个端口下所有信息")
|
||||
// a.移除证书数据
|
||||
_, ok := waf.AllCertificate[host.Port]
|
||||
if ok {
|
||||
delete(waf.AllCertificate, host.Port)
|
||||
}
|
||||
//b.移除对照关系
|
||||
delete(waf.HostCode, host.Code)
|
||||
//c.移除主机保护信息
|
||||
delete(waf.HostTarget, host.Host+":"+strconv.Itoa(host.Port))
|
||||
//d.暂停服务 并 移除服务信息
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, svrOk := waf.ServerOnline[host.Port]
|
||||
if svrOk {
|
||||
err := waf.ServerOnline[host.Port].Svr.Shutdown(ctx)
|
||||
if err != nil {
|
||||
zlog.Error("shutting down: " + err.Error())
|
||||
} else {
|
||||
zlog.Info("shutdown processed successfully port" + strconv.Itoa(host.Port))
|
||||
}
|
||||
delete(waf.ServerOnline, host.Port)
|
||||
}
|
||||
|
||||
} else {
|
||||
zlog.Debug("准备移除没用的主机信息")
|
||||
// a.移除某个端口下的证书数据
|
||||
_, ok := waf.AllCertificate[host.Port][host.Host]
|
||||
if ok {
|
||||
delete(waf.AllCertificate[host.Port], host.Host)
|
||||
}
|
||||
//b.移除对照关系
|
||||
delete(waf.HostCode, host.Code)
|
||||
//c.移除主机保护信息
|
||||
delete(waf.HostTarget, host.Host+":"+strconv.Itoa(host.Port))
|
||||
waf.AllCertificate = AllCertificate{
|
||||
Mux: sync.Mutex{},
|
||||
Map: map[string]*tls.Certificate{},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,21 +879,13 @@ func (waf *WafEngine) StartProxyServer(innruntime innerbean.ServerRunTime) {
|
||||
Addr: ":" + strconv.Itoa(innruntime.Port),
|
||||
Handler: waf,
|
||||
TLSConfig: &tls.Config{
|
||||
NameToCertificate: make(map[string]*tls.Certificate, 0),
|
||||
GetCertificate: waf.GetCertificateFunc,
|
||||
},
|
||||
}
|
||||
serclone := waf.ServerOnline[innruntime.Port]
|
||||
serclone.Svr = svr
|
||||
serclone.Status = 0
|
||||
waf.ServerOnline[innruntime.Port] = serclone
|
||||
|
||||
svr.TLSConfig.NameToCertificate = waf.AllCertificate[innruntime.Port]
|
||||
svr.TLSConfig.GetCertificate = func(clientInfo *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if x509Cert, ok := svr.TLSConfig.NameToCertificate[clientInfo.ServerName]; ok {
|
||||
return x509Cert, nil
|
||||
}
|
||||
return nil, errors.New("config error")
|
||||
}
|
||||
zlog.Info("启动HTTPS 服务器" + strconv.Itoa(innruntime.Port))
|
||||
err := svr.ListenAndServeTLS("", "")
|
||||
if err == http.ErrServerClosed {
|
||||
@@ -1088,28 +963,3 @@ func (waf *WafEngine) StopProxyServer(v innerbean.ServerRunTime) {
|
||||
v.Svr.Close()
|
||||
}
|
||||
}
|
||||
func (waf *WafEngine) ReLoadSensitive() {
|
||||
//敏感词处理
|
||||
var sensitiveList []model.Sensitive
|
||||
global.GWAF_LOCAL_DB.Find(&sensitiveList)
|
||||
//敏感词
|
||||
waf.Sensitive = sensitiveList
|
||||
if len(sensitiveList) == 0 {
|
||||
return
|
||||
}
|
||||
// 提取 content 字段并转换为 [][]rune
|
||||
var keywords [][]rune
|
||||
for _, sensitive := range waf.Sensitive {
|
||||
// 将 content 转换为 []rune 并追加到 keywords
|
||||
keywords = append(keywords, []rune(sensitive.Content))
|
||||
}
|
||||
|
||||
m := new(goahocorasick.Machine)
|
||||
err := m.Build(keywords)
|
||||
if err != nil {
|
||||
zlog.Error("load sensitive error", err)
|
||||
return
|
||||
}
|
||||
waf.SensitiveManager = m
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
package wafenginecore
|
||||
|
||||
import (
|
||||
"SamWaf/common/zlog"
|
||||
"SamWaf/global"
|
||||
"SamWaf/innerbean"
|
||||
"SamWaf/model"
|
||||
"SamWaf/model/wafenginmodel"
|
||||
"SamWaf/service/waf_service"
|
||||
"SamWaf/utils"
|
||||
"SamWaf/wafenginecore/loadbalance"
|
||||
"SamWaf/wafproxy"
|
||||
"SamWaf/webplugin"
|
||||
"context"
|
||||
goahocorasick "github.com/anknown/ahocorasick"
|
||||
"golang.org/x/time/rate"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 加载全部host
|
||||
func (waf *WafEngine) LoadAllHost() {
|
||||
//重新查询
|
||||
var hosts []model.Hosts
|
||||
global.GWAF_LOCAL_DB.Find(&hosts)
|
||||
for i := 0; i < len(hosts); i++ {
|
||||
waf.LoadHost(hosts[i])
|
||||
}
|
||||
}
|
||||
|
||||
// 加载指定host
|
||||
func (waf *WafEngine) LoadHost(inHost model.Hosts) innerbean.ServerRunTime {
|
||||
|
||||
//检测https
|
||||
if inHost.Ssl == 1 {
|
||||
/*dirPath := filepath.Join(utils.GetCurrentDir(), "ssl", "host", inHost.Id)
|
||||
// 检查目录是否存在
|
||||
if _, err := os.Stat(dirPath); os.IsNotExist(err) {
|
||||
// 创建目录
|
||||
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||
if err != nil {
|
||||
zlog.Error("failed to create directory:", err.Error())
|
||||
}
|
||||
}
|
||||
keyFilePath := filepath.Join(dirPath, "domain.key")
|
||||
certFilePath := filepath.Join(dirPath, "domain.crt")
|
||||
|
||||
// 检查 key 文件
|
||||
if err := utils.UpdateFileIsHasNewInfo(keyFilePath, inHost.Keyfile); err != nil {
|
||||
zlog.Error("failed to write key file: ", err.Error())
|
||||
}
|
||||
|
||||
// 检查 cert 文件
|
||||
if err := utils.UpdateFileIsHasNewInfo(certFilePath, inHost.Certfile); err != nil {
|
||||
zlog.Error("failed to write key file: ", err.Error())
|
||||
}
|
||||
//waf.AllCertificate.LoadSSLByFilePath(inHost.Host, certFilePath, keyFilePath)
|
||||
*/
|
||||
waf.AllCertificate.LoadSSL(inHost.Host, inHost.Certfile, inHost.Keyfile)
|
||||
|
||||
}
|
||||
onlineServer, ok := waf.ServerOnline[inHost.Port]
|
||||
if ok == false && inHost.GLOBAL_HOST == 0 {
|
||||
if inHost.START_STATUS == 0 {
|
||||
waf.ServerOnline[inHost.Port] = innerbean.ServerRunTime{
|
||||
ServerType: utils.GetServerByHosts(inHost),
|
||||
Port: inHost.Port,
|
||||
Status: 1,
|
||||
}
|
||||
} else {
|
||||
delete(waf.ServerOnline, inHost.Port)
|
||||
}
|
||||
|
||||
} else if ok {
|
||||
if (onlineServer.ServerType) == "https" && onlineServer.Svr != nil {
|
||||
|
||||
zlog.Debug(strconv.Itoa(len(onlineServer.Svr.TLSConfig.Certificates)))
|
||||
/*onlineServer.Svr.TLSConfig.NameToCertificate = waf.AllCertificate[inHost.Port]
|
||||
onlineServer.Svr.TLSConfig.GetCertificate = func(clientInfo *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
if x509Cert, ok := onlineServer.Svr.TLSConfig.NameToCertificate[clientInfo.ServerName]; ok {
|
||||
return x509Cert, nil
|
||||
}
|
||||
return nil, errors.New("config error")
|
||||
}*/
|
||||
}
|
||||
|
||||
}
|
||||
//检查是否存在强制跳转HTTPS的情况
|
||||
if inHost.AutoJumpHTTPS == 1 {
|
||||
default80Port := 80
|
||||
_, ok := waf.ServerOnline[default80Port]
|
||||
if ok == false && inHost.GLOBAL_HOST == 0 {
|
||||
if inHost.START_STATUS == 0 {
|
||||
waf.ServerOnline[default80Port] = innerbean.ServerRunTime{
|
||||
ServerType: "http",
|
||||
Port: default80Port,
|
||||
Status: 1,
|
||||
}
|
||||
} else {
|
||||
delete(waf.ServerOnline, default80Port)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//加载主机对于的规则
|
||||
ruleHelper := &utils.RuleHelper{}
|
||||
ruleHelper.InitRuleEngine()
|
||||
//查询规则
|
||||
var vcnt int
|
||||
global.GWAF_LOCAL_DB.Model(&model.Rules{}).Where("host_code = ? and rule_status<>999",
|
||||
inHost.Code).Select("sum(rule_version) as vcnt").Row().Scan(&vcnt)
|
||||
zlog.Debug("主机host" + inHost.Code + " 版本" + strconv.Itoa(vcnt))
|
||||
var ruleconfigs []model.Rules
|
||||
if vcnt > 0 {
|
||||
global.GWAF_LOCAL_DB.Where("host_code = ?and rule_status<>999", inHost.Code).Find(&ruleconfigs)
|
||||
ruleHelper.LoadRules(ruleconfigs)
|
||||
}
|
||||
//查询ip限流(应该针对一个网址只有一个)
|
||||
var anticcBean model.AntiCC
|
||||
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Limit(1).Find(&anticcBean)
|
||||
|
||||
//初始化插件-ip计数器
|
||||
var pluginIpRateLimiter *webplugin.IPRateLimiter
|
||||
if anticcBean.Id != "" {
|
||||
pluginIpRateLimiter = webplugin.NewIPRateLimiter(rate.Limit(anticcBean.Rate), anticcBean.Limit)
|
||||
}
|
||||
|
||||
//查询ip白名单
|
||||
var ipwhitelist []model.IPAllowList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ipwhitelist)
|
||||
|
||||
//查询url白名单
|
||||
var urlwhitelist []model.URLAllowList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&urlwhitelist)
|
||||
|
||||
//查询ip黑名单
|
||||
var ipblocklist []model.IPBlockList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ipblocklist)
|
||||
|
||||
//查询url白名单
|
||||
var urlblocklist []model.URLBlockList
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&urlblocklist)
|
||||
|
||||
//查询url隐私保护
|
||||
var ldpurls []model.LDPUrl
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&ldpurls)
|
||||
|
||||
//查询负载均衡
|
||||
var loadBalanceList []model.LoadBalance
|
||||
global.GWAF_LOCAL_DB.Where("host_code=? ", inHost.Code).Find(&loadBalanceList)
|
||||
//初始化主机host
|
||||
hostsafe := &wafenginmodel.HostSafe{
|
||||
LoadBalanceRuntime: &wafenginmodel.LoadBalanceRuntime{
|
||||
CurrentProxyIndex: 0,
|
||||
RevProxies: []*wafproxy.ReverseProxy{},
|
||||
WeightRoundRobinBalance: &loadbalance.WeightRoundRobinBalance{},
|
||||
IpHashBalance: loadbalance.NewConsistentHashBalance(nil),
|
||||
},
|
||||
LoadBalanceLists: loadBalanceList,
|
||||
Rule: ruleHelper,
|
||||
TargetHost: inHost.Remote_host + ":" + strconv.Itoa(inHost.Remote_port),
|
||||
RuleData: ruleconfigs,
|
||||
RuleVersionSum: vcnt,
|
||||
Host: inHost,
|
||||
PluginIpRateLimiter: pluginIpRateLimiter,
|
||||
IPWhiteLists: ipwhitelist,
|
||||
UrlWhiteLists: urlwhitelist,
|
||||
LdpUrlLists: ldpurls,
|
||||
IPBlockLists: ipblocklist,
|
||||
UrlBlockLists: urlblocklist,
|
||||
}
|
||||
hostsafe.Mux.Lock()
|
||||
defer hostsafe.Mux.Unlock()
|
||||
//目标关系情况
|
||||
waf.HostTarget[inHost.Host+":"+strconv.Itoa(inHost.Port)] = hostsafe
|
||||
//赋值到对照表里面
|
||||
waf.HostCode[inHost.Code] = inHost.Host + ":" + strconv.Itoa(inHost.Port)
|
||||
|
||||
//如果存在强制跳转
|
||||
if inHost.AutoJumpHTTPS == 1 {
|
||||
waf.HostTarget[inHost.Host+":80"] = hostsafe
|
||||
waf.HostCode[inHost.Code] = inHost.Host + ":80"
|
||||
}
|
||||
//如果是不限制端口的情况
|
||||
if inHost.UnrestrictedPort == 1 {
|
||||
zlog.Debug("来源端口宽松模式")
|
||||
waf.HostTargetNoPort[inHost.Host] = inHost.Host + ":" + strconv.Itoa(inHost.Port)
|
||||
} else {
|
||||
if _, ok := waf.HostTargetNoPort[inHost.Host]; ok {
|
||||
zlog.Debug("来源端口严苛模式")
|
||||
delete(waf.HostTargetNoPort, inHost.Host)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return waf.ServerOnline[inHost.Port]
|
||||
}
|
||||
|
||||
// RemovePortServer 检测如果没有端口在占用了,可以关闭相应端口
|
||||
func (waf *WafEngine) RemovePortServer() {
|
||||
for onlinePort := range waf.ServerOnline {
|
||||
if waf_service.WafHostServiceApp.CheckAvailablePortExistApi(onlinePort) == 0 {
|
||||
//暂停服务 并 移除服务信息
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, svrOk := waf.ServerOnline[onlinePort]
|
||||
if svrOk {
|
||||
err := waf.ServerOnline[onlinePort].Svr.Shutdown(ctx)
|
||||
if err != nil {
|
||||
zlog.Error("shutting down: " + err.Error())
|
||||
} else {
|
||||
zlog.Info("shutdown processed successfully port" + strconv.Itoa(onlinePort))
|
||||
}
|
||||
delete(waf.ServerOnline, onlinePort)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveHost 移除主机相关信息
|
||||
func (waf *WafEngine) RemoveHost(host model.Hosts) {
|
||||
|
||||
// 移除当前信息
|
||||
//a.移除对照关系
|
||||
delete(waf.HostCode, host.Code)
|
||||
//b.移除主机保护信息
|
||||
delete(waf.HostTarget, host.Host+":"+strconv.Itoa(host.Port))
|
||||
//c.移除某个端口下的证书数据
|
||||
waf.AllCertificate.RemoveSSL(host.Host)
|
||||
//检测如果端口已经没有关联服务就直接关闭掉
|
||||
waf.RemovePortServer()
|
||||
}
|
||||
|
||||
// ReLoadSensitive 加载敏感词
|
||||
func (waf *WafEngine) ReLoadSensitive() {
|
||||
//敏感词处理
|
||||
var sensitiveList []model.Sensitive
|
||||
global.GWAF_LOCAL_DB.Find(&sensitiveList)
|
||||
//敏感词
|
||||
waf.Sensitive = sensitiveList
|
||||
if len(sensitiveList) == 0 {
|
||||
return
|
||||
}
|
||||
// 提取 content 字段并转换为 [][]rune
|
||||
var keywords [][]rune
|
||||
for _, sensitive := range waf.Sensitive {
|
||||
// 将 content 转换为 []rune 并追加到 keywords
|
||||
keywords = append(keywords, []rune(sensitive.Content))
|
||||
}
|
||||
|
||||
m := new(goahocorasick.Machine)
|
||||
err := m.Build(keywords)
|
||||
if err != nil {
|
||||
zlog.Error("load sensitive error", err)
|
||||
return
|
||||
}
|
||||
waf.SensitiveManager = m
|
||||
|
||||
}
|
||||
@@ -44,6 +44,8 @@ func SSLReload() {
|
||||
}
|
||||
wafSslConfigService.AddInner(backSslConfig)
|
||||
err = wafSslConfigService.ModifyInner(updateSslConfig)
|
||||
/*fmt.Printf("updateSslConfig: %+v\n", updateSslConfig)
|
||||
fmt.Printf("backSslConfig: %+v\n", backSslConfig)*/
|
||||
if err != nil {
|
||||
zlog.Error(innerLogName, "ssl modify inner config:", err.Error())
|
||||
}
|
||||
@@ -54,6 +56,8 @@ func SSLReload() {
|
||||
zlog.Error(innerLogName, "ssl host update:", err.Error())
|
||||
continue
|
||||
}
|
||||
hosts.Keyfile = updateSslConfig.KeyContent
|
||||
hosts.Certfile = updateSslConfig.CertContent
|
||||
var chanInfo = spec.ChanCommonHost{
|
||||
HostCode: hosts.Code,
|
||||
Type: enums.ChanTypeSSL,
|
||||
|
||||
Reference in New Issue
Block a user