diff --git a/internal/nodes/http_request.go b/internal/nodes/http_request.go index 4b5d0c7..496514d 100644 --- a/internal/nodes/http_request.go +++ b/internal/nodes/http_request.go @@ -233,6 +233,12 @@ func (this *HTTPRequest) Do() { // 开始调用 func (this *HTTPRequest) doBegin() { + // 是否找不到域名匹配 + if this.ReqServer.Id == 0 { + this.doMismatch() + return + } + if !this.isLnRequest { // 处理request limit if this.web.RequestLimit != nil && diff --git a/internal/nodes/http_request_mismatch.go b/internal/nodes/http_request_mismatch.go new file mode 100644 index 0000000..73aa217 --- /dev/null +++ b/internal/nodes/http_request_mismatch.go @@ -0,0 +1,68 @@ +// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . + +package nodes + +import ( + "github.com/TeaOSLab/EdgeCommon/pkg/nodeutils" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" + "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/firewallconfigs" + "github.com/TeaOSLab/EdgeNode/internal/ttlcache" + "github.com/TeaOSLab/EdgeNode/internal/waf" + "net/http" + "time" +) + +// 域名无匹配情况处理 +func (this *HTTPRequest) doMismatch() { + // 是否为健康检查 + var healthCheckKey = this.RawReq.Header.Get(serverconfigs.HealthCheckHeaderName) + if len(healthCheckKey) > 0 { + _, err := nodeutils.Base64DecodeMap(healthCheckKey) + if err == nil { + this.writer.WriteHeader(http.StatusOK) + return + } + } + + // 是否已经在黑名单 + var remoteIP = this.RemoteAddr() + if waf.SharedIPBlackList.Contains(waf.IPTypeAll, firewallconfigs.FirewallScopeGlobal, 0, remoteIP) { + this.Close() + return + } + + // 根据配置进行相应的处理 + if sharedNodeConfig.GlobalConfig != nil && sharedNodeConfig.GlobalConfig.HTTPAll.MatchDomainStrictly { + // 检查cc + // TODO 可以在管理端配置是否开启以及最多尝试次数 + if len(remoteIP) > 0 { + const maxAttempts = 100 + if ttlcache.SharedCache.IncreaseInt64("MISMATCH_DOMAIN:"+remoteIP, int64(1), time.Now().Unix()+60, false) > maxAttempts { + // 在加入之前再次检查黑名单 + if !waf.SharedIPBlackList.Contains(waf.IPTypeAll, firewallconfigs.FirewallScopeGlobal, 0, remoteIP) { + waf.SharedIPBlackList.RecordIP(waf.IPTypeAll, firewallconfigs.FirewallScopeGlobal, 0, remoteIP, time.Now().Unix()+int64(3600), 0, true, 0, 0, "access mismatch domain '"+this.RawReq.Host+"' too frequently") + } + } + } + + // 处理当前连接 + var httpAllConfig = sharedNodeConfig.GlobalConfig.HTTPAll + var mismatchAction = httpAllConfig.DomainMismatchAction + if mismatchAction != nil && mismatchAction.Code == "page" { + if mismatchAction.Options != nil { + this.writer.Header().Set("Content-Type", "text/html; charset=utf-8") + this.writer.WriteHeader(mismatchAction.Options.GetInt("statusCode")) + _, _ = this.writer.Write([]byte(mismatchAction.Options.GetString("contentHTML"))) + } else { + http.Error(this.writer, "404 page not found: '"+this.URL()+"'", http.StatusNotFound) + } + return + } else { + http.Error(this.writer, "404 page not found: '"+this.URL()+"'", http.StatusNotFound) + this.Close() + return + } + } + + http.Error(this.writer, "404 page not found: '"+this.URL()+"'", http.StatusNotFound) +} diff --git a/internal/nodes/listener_http.go b/internal/nodes/listener_http.go index 0d2f1aa..868dee5 100644 --- a/internal/nodes/listener_http.go +++ b/internal/nodes/listener_http.go @@ -3,7 +3,6 @@ package nodes import ( "context" "crypto/tls" - "github.com/TeaOSLab/EdgeCommon/pkg/nodeutils" "github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs" "github.com/TeaOSLab/EdgeNode/internal/remotelogs" "github.com/TeaOSLab/EdgeNode/internal/zero" @@ -172,8 +171,8 @@ func (this *HTTPListener) ServeHTTP(rawWriter http.ResponseWriter, rawReq *http. server, serverName := this.findNamedServer(domain) if server == nil { if server == nil { - this.handleMismatch(rawReq, rawWriter) - return + // 增加默认的一个服务 + server = this.emptyServer() } else { serverName = domain } @@ -195,48 +194,7 @@ func (this *HTTPListener) ServeHTTP(rawWriter http.ResponseWriter, rawReq *http. req.Do() } -// 处理域名不匹配的情况 -func (this *HTTPListener) handleMismatch(rawReq *http.Request, rawWriter http.ResponseWriter) { - // TODO 需要记录访问记录和防止CC - - // 是否为健康检查 - var healthCheckKey = rawReq.Header.Get(serverconfigs.HealthCheckHeaderName) - if len(healthCheckKey) > 0 { - _, err := nodeutils.Base64DecodeMap(healthCheckKey) - if err == nil { - rawWriter.WriteHeader(http.StatusOK) - return - } - } - - // 严格匹配域名模式下,我们拒绝用户访问 - if sharedNodeConfig.GlobalConfig != nil && sharedNodeConfig.GlobalConfig.HTTPAll.MatchDomainStrictly { - var httpAllConfig = sharedNodeConfig.GlobalConfig.HTTPAll - var mismatchAction = httpAllConfig.DomainMismatchAction - if mismatchAction != nil && mismatchAction.Code == "page" { - if mismatchAction.Options != nil { - rawWriter.Header().Set("Content-Type", "text/html; charset=utf-8") - rawWriter.WriteHeader(mismatchAction.Options.GetInt("statusCode")) - _, _ = rawWriter.Write([]byte(mismatchAction.Options.GetString("contentHTML"))) - } else { - http.Error(rawWriter, "404 page not found: '"+rawReq.URL.String()+"'", http.StatusNotFound) - } - return - } else { - hijacker, ok := rawWriter.(http.Hijacker) - if ok { - conn, _, _ := hijacker.Hijack() - if conn != nil { - _ = conn.Close() - return - } - } - } - } - - http.Error(rawWriter, "404 page not found: '"+rawReq.URL.String()+"'", http.StatusNotFound) -} - +// 检查host是否为IP func (this *HTTPListener) isIP(host string) bool { // IPv6 if strings.Index(host, "[") > -1 { @@ -251,3 +209,21 @@ func (this *HTTPListener) isIP(host string) bool { return true } + +// 默认的访问日志 +func (this *HTTPListener) emptyServer() *serverconfigs.ServerConfig { + var server = &serverconfigs.ServerConfig{ + Type: serverconfigs.ServerTypeHTTPProxy, + } + + var accessLogRef = serverconfigs.NewHTTPAccessLogRef() + // TODO 需要配置是否记录日志 + accessLogRef.IsOn = true + accessLogRef.Fields = append([]int{}, serverconfigs.HTTPAccessLogDefaultFieldsCodes...) + server.Web = &serverconfigs.HTTPWebConfig{ + IsOn: true, + AccessLogRef: accessLogRef, + } + + return server +}