diff --git a/main.go b/main.go index 93d4ad8..7d4b744 100644 --- a/main.go +++ b/main.go @@ -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 diff --git a/service/waf_service/waf_host.go b/service/waf_service/waf_host.go index cd49664..5a37813 100644 --- a/service/waf_service/waf_host.go +++ b/service/waf_service/waf_host.go @@ -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 } diff --git a/utils/common.go b/utils/common.go index ad78014..8a939f1 100644 --- a/utils/common.go +++ b/utils/common.go @@ -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 +} diff --git a/wafdb/patch_sql.go b/wafdb/patch_sql.go index d213bc0..d31b3d6 100644 --- a/wafdb/patch_sql.go +++ b/wafdb/patch_sql.go @@ -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") + } } diff --git a/wafenginecore/proxy.go b/wafenginecore/proxy.go index 9918cb3..362113e 100644 --- a/wafenginecore/proxy.go +++ b/wafenginecore/proxy.go @@ -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, diff --git a/wafenginecore/wafengine.go b/wafenginecore/wafengine.go index 6931648..7657d87 100644 --- a/wafenginecore/wafengine.go +++ b/wafenginecore/wafengine.go @@ -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 - -} diff --git a/wafenginecore/wafworker.go b/wafenginecore/wafworker.go new file mode 100644 index 0000000..f25a2cc --- /dev/null +++ b/wafenginecore/wafworker.go @@ -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 + +} diff --git a/waftask/task_ssl.go b/waftask/task_ssl.go index 2fa88af..5530fa4 100644 --- a/waftask/task_ssl.go +++ b/waftask/task_ssl.go @@ -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,