This commit is contained in:
unknown
2026-02-04 20:27:13 +08:00
commit 3b042d1dad
9410 changed files with 1488147 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
// Copyright 2022 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
//go:build plus
package nodes
import (
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
teaconst "github.com/TeaOSLab/EdgeNode/internal/const"
"github.com/TeaOSLab/EdgeNode/internal/events"
"github.com/TeaOSLab/EdgeNode/internal/iplibrary"
"github.com/TeaOSLab/EdgeNode/internal/uam"
"github.com/TeaOSLab/EdgeNode/internal/utils/agents"
"github.com/TeaOSLab/EdgeNode/internal/utils/counters"
"github.com/TeaOSLab/EdgeNode/internal/utils/ttlcache"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/types"
"net/http"
"strings"
)
var sharedUAMManager *uam.Manager
func init() {
if !teaconst.IsMain {
return
}
events.On(events.EventLoaded, func() {
if sharedUAMManager != nil {
return
}
manager, _ := uam.NewManager(sharedNodeConfig.NodeId, sharedNodeConfig.Secret)
if manager != nil {
sharedUAMManager = manager
}
})
events.On(events.EventReload, func() {
if sharedUAMManager != nil {
return
}
manager, _ := uam.NewManager(sharedNodeConfig.NodeId, sharedNodeConfig.Secret)
if manager != nil {
sharedUAMManager = manager
}
})
}
func (this *HTTPRequest) isUAMRequest() bool {
if this.web.UAM == nil || !this.web.UAM.IsOn || this.RawReq.Method != http.MethodPost {
return false
}
var cookiesString = this.RawReq.Header.Get("Cookie")
if len(cookiesString) == 0 {
return false
}
return strings.HasPrefix(cookiesString, uam.CookiePrevKey+"=") ||
strings.Contains(cookiesString, " "+uam.CookiePrevKey+"=")
}
// UAM
// TODO 需要检查是否为plus
func (this *HTTPRequest) doUAM() (block bool) {
var serverId int64
if this.ReqServer != nil {
serverId = this.ReqServer.Id
}
var uamConfig = this.web.UAM
if uamConfig == nil ||
!uamConfig.IsOn ||
!uamConfig.MatchURL(this.requestScheme()+"://"+this.ReqHost+this.Path()) ||
!uamConfig.MatchRequest(this.Format) {
return
}
var policy = this.nodeConfig.FindUAMPolicyWithClusterId(this.ReqServer.ClusterId)
if policy == nil {
policy = nodeconfigs.NewUAMPolicy()
}
if policy == nil || !policy.IsOn {
return
}
// 获取UAM管理器
var manager = sharedUAMManager
if manager == nil {
return false
}
// 忽略URL白名单
if this.RawReq.URL.Path == "/favicon.ico" || this.RawReq.URL.Path == "/favicon.png" {
return false
}
// 检查白名单
var remoteAddr = this.requestRemoteAddr(true)
// 检查UAM白名单
if uamConfig.AddToWhiteList && ttlcache.SharedInt64Cache.Read("UAM:WHITE:"+remoteAddr) != nil {
return false
}
// 检查是否为白名单直连
if !Tea.IsTesting() && this.nodeConfig.IPIsAutoAllowed(remoteAddr) {
return
}
// 是否在全局名单中
canGoNext, isInAllowedList, _ := iplibrary.AllowIP(remoteAddr, serverId)
if !canGoNext {
this.disableLog = true
this.Close()
return true
}
if isInAllowedList {
return false
}
// 如果是搜索引擎直接通过
var userAgent = this.RawReq.UserAgent()
if len(userAgent) == 0 {
// 如果User-Agent为空则直接阻止
this.writer.WriteHeader(http.StatusForbidden)
// 增加失败次数
if manager.IncreaseFails(policy, remoteAddr, serverId) {
this.isAttack = true
}
return true
}
// 不管是否开启允许搜索引擎,这里都放行,避免收录了拦截的代码
if agents.SharedManager.ContainsIP(remoteAddr) {
return false
}
if policy.AllowSearchEngines {
if searchEngineRegex.MatchString(userAgent) {
return false
}
}
// 如果是python之类的直接拦截
if policy.DenySpiders && spiderRegexp.MatchString(userAgent) {
this.writer.WriteHeader(http.StatusForbidden)
// 增加失败次数
if manager.IncreaseFails(policy, remoteAddr, serverId) {
this.isAttack = true
}
return true
}
// 检查预生成Key
var step = this.Header().Get("X-GE-UA-Step")
if step == uam.StepPrev {
if this.Method() != http.MethodPost {
this.writer.WriteHeader(http.StatusForbidden)
return true
}
if manager.CheckPrevKey(policy, uamConfig, this.RawReq, remoteAddr, this.writer) {
_, _ = this.writer.Write([]byte(`{"ok": true}`))
} else {
_, _ = this.writer.Write([]byte(`{"ok": false}`))
}
// 增加失败次数
if manager.IncreaseFails(policy, remoteAddr, serverId) {
this.isAttack = true
}
return true
}
// 检查是否启用QPS
if uamConfig.MinQPSPerIP > 0 && len(step) == 0 {
var avgQPS = counters.SharedCounter.IncreaseKey("UAM:"+remoteAddr, 60) / 60
if avgQPS <= 0 {
avgQPS = 1
}
if avgQPS < types.Uint32(uamConfig.MinQPSPerIP) {
return false
}
}
// 检查Cookie中的Key
isVerified, isAttack, _ := manager.CheckKey(policy, this.RawReq, this.writer, remoteAddr, serverId, uamConfig.KeyLife)
if isVerified {
return false
}
this.isAttack = isAttack
// 检查是否已生成有效的prev key如果已经生成则表示当前请求是附带请求比如favicon.ico不再重新生成新的
// TODO 考虑这里的必要性
if manager.ExistsActivePreKey(this.RawReq) {
return true
}
// 显示加载页面
err := manager.LoadPage(policy, this.RawReq, this.Format, remoteAddr, this.writer)
if err != nil {
return false
}
return true
}