diff --git a/internal/nodes/client_conn_base.go b/internal/nodes/client_conn_base.go index 3473a2a..fe54891 100644 --- a/internal/nodes/client_conn_base.go +++ b/internal/nodes/client_conn_base.go @@ -17,6 +17,7 @@ type BaseClientConn struct { hasLimit bool isPersistent bool // 是否为持久化连接 + fingerprint []byte isClosed bool @@ -128,3 +129,13 @@ func (this *BaseClientConn) SetLinger(seconds int) error { func (this *BaseClientConn) SetIsPersistent(isPersistent bool) { this.isPersistent = isPersistent } + +// SetFingerprint 设置指纹信息 +func (this *BaseClientConn) SetFingerprint(fingerprint []byte) { + this.fingerprint = fingerprint +} + +// Fingerprint 读取指纹信息 +func (this *BaseClientConn) Fingerprint() []byte { + return this.fingerprint +} diff --git a/internal/nodes/client_conn_interface.go b/internal/nodes/client_conn_interface.go index 8026554..75c9926 100644 --- a/internal/nodes/client_conn_interface.go +++ b/internal/nodes/client_conn_interface.go @@ -26,4 +26,10 @@ type ClientConnInterface interface { // SetIsPersistent 设置是否为持久化 SetIsPersistent(isPersistent bool) + + // SetFingerprint 设置指纹信息 + SetFingerprint(fingerprint []byte) + + // Fingerprint 读取指纹信息 + Fingerprint() []byte } diff --git a/internal/nodes/client_tls_conn.go b/internal/nodes/client_tls_conn.go index 69335d9..98db73b 100644 --- a/internal/nodes/client_tls_conn.go +++ b/internal/nodes/client_tls_conn.go @@ -68,3 +68,17 @@ func (this *ClientTLSConn) SetIsPersistent(isPersistent bool) { } } } + +func (this *ClientTLSConn) Fingerprint() []byte { + tlsConn, ok := this.rawConn.(*tls.Conn) + if ok { + var rawConn = tlsConn.NetConn() + if rawConn != nil { + clientConn, ok := rawConn.(*ClientConn) + if ok { + return clientConn.fingerprint + } + } + } + return nil +} diff --git a/internal/nodes/http_request_waf.go b/internal/nodes/http_request_waf.go index 3904bef..01cbbe7 100644 --- a/internal/nodes/http_request_waf.go +++ b/internal/nodes/http_request_waf.go @@ -402,3 +402,17 @@ func (this *HTTPRequest) WAFOnAction(action interface{}) (goNext bool) { } return true } + +func (this *HTTPRequest) WAFFingerprint() []byte { + var requestConn = this.RawReq.Context().Value(HTTPConnContextKey) + if requestConn == nil { + return nil + } + + clientConn, ok := requestConn.(ClientConnInterface) + if ok { + return clientConn.Fingerprint() + } + + return nil +} diff --git a/internal/nodes/listener_base.go b/internal/nodes/listener_base.go index 41ccdec..f1703a0 100644 --- a/internal/nodes/listener_base.go +++ b/internal/nodes/listener_base.go @@ -36,6 +36,15 @@ func (this *BaseListener) buildTLSConfig() *tls.Config { return &tls.Config{ Certificates: nil, GetConfigForClient: func(clientInfo *tls.ClientHelloInfo) (config *tls.Config, e error) { + // 指纹信息 + var fingerprint = this.calculateFingerprint(clientInfo) + if len(fingerprint) > 0 { + clientConn, ok := clientInfo.Conn.(ClientConnInterface) + if ok { + clientConn.SetFingerprint(fingerprint) + } + } + tlsPolicy, _, err := this.matchSSL(this.helloServerName(clientInfo)) if err != nil { return nil, err @@ -50,6 +59,15 @@ func (this *BaseListener) buildTLSConfig() *tls.Config { return tlsPolicy.TLSConfig(), nil }, GetCertificate: func(clientInfo *tls.ClientHelloInfo) (certificate *tls.Certificate, e error) { + // 指纹信息 + var fingerprint = this.calculateFingerprint(clientInfo) + if len(fingerprint) > 0 { + clientConn, ok := clientInfo.Conn.(ClientConnInterface) + if ok { + clientConn.SetFingerprint(fingerprint) + } + } + tlsPolicy, cert, err := this.matchSSL(this.helloServerName(clientInfo)) if err != nil { return nil, err diff --git a/internal/nodes/listener_base_ext.go b/internal/nodes/listener_base_ext.go new file mode 100644 index 0000000..6f8e191 --- /dev/null +++ b/internal/nodes/listener_base_ext.go @@ -0,0 +1,10 @@ +// Copyright 2023 Liuxiangchao iwind.liu@gmail.com. All rights reserved. Official site: https://goedge.cn . +//go:build !plus + +package nodes + +import "crypto/tls" + +func (this *BaseListener) calculateFingerprint(clientInfo *tls.ClientHelloInfo) []byte { + return nil +} diff --git a/internal/waf/checkpoints/cc2.go b/internal/waf/checkpoints/cc2.go index 37bf6ea..cf39f58 100644 --- a/internal/waf/checkpoints/cc2.go +++ b/internal/waf/checkpoints/cc2.go @@ -3,6 +3,7 @@ package checkpoints import ( + "fmt" "github.com/TeaOSLab/EdgeNode/internal/ttlcache" "github.com/TeaOSLab/EdgeNode/internal/waf/requests" "github.com/TeaOSLab/EdgeNode/internal/zero" @@ -35,7 +36,11 @@ type CC2Checkpoint struct { func (this *CC2Checkpoint) RequestValue(req requests.Request, param string, options maps.Map, ruleId int64) (value interface{}, hasRequestBody bool, sysErr error, userErr error) { var keys = options.GetSlice("keys") var keyValues = []string{} + var hasRemoteAddr = false for _, key := range keys { + if key == "${remoteAddr}" || key == "${rawRemoteAddr}" { + hasRemoteAddr = true + } keyValues = append(keyValues, req.Format(types.String(key))) } if len(keyValues) == 0 { @@ -66,8 +71,29 @@ func (this *CC2Checkpoint) RequestValue(req requests.Request, param string, opti } } + var expiresAt = time.Now().Unix() + period var ccKey = "WAF-CC-" + types.String(ruleId) + "-" + strings.Join(keyValues, "@") - value = ccCache.IncreaseInt64(ccKey, 1, time.Now().Unix()+period, false) + value = ccCache.IncreaseInt64(ccKey, 1, expiresAt, false) + + // 基于指纹统计 + if hasRemoteAddr { + var fingerprint = req.WAFFingerprint() + if len(fingerprint) > 0 { + var fpKeyValues = []string{} + for _, key := range keys { + if key == "${remoteAddr}" || key == "${rawRemoteAddr}" { + fpKeyValues = append(fpKeyValues, fmt.Sprintf("%x", fingerprint)) + continue + } + fpKeyValues = append(fpKeyValues, req.Format(types.String(key))) + } + var fpCCKey = "WAF-CC-" + types.String(ruleId) + "-" + strings.Join(fpKeyValues, "@") + var fpValue = ccCache.IncreaseInt64(fpCCKey, 1, expiresAt, false) + if fpValue > value.(int64) { + value = fpValue + } + } + } return } diff --git a/internal/waf/requests/request.go b/internal/waf/requests/request.go index f7aac5a..2ad5f1f 100644 --- a/internal/waf/requests/request.go +++ b/internal/waf/requests/request.go @@ -32,6 +32,9 @@ type Request interface { // WAFOnAction 动作回调 WAFOnAction(action interface{}) (goNext bool) + // WAFFingerprint 读取连接指纹 + WAFFingerprint() []byte + // Format 格式化变量 Format(string) string }