mirror of
https://github.com/sky22333/hubproxy.git
synced 2026-08-05 03:24:57 +08:00
限流优化
This commit is contained in:
@@ -10,5 +10,5 @@ services:
|
||||
logging:
|
||||
driver: json-file
|
||||
options:
|
||||
max-size: "1g"
|
||||
max-file: "2"
|
||||
max-size: "200m"
|
||||
max-file: "3"
|
||||
@@ -20,8 +20,7 @@ periodHours = 3.0
|
||||
# 白名单中的IP不受限流限制
|
||||
whiteList = [
|
||||
"127.0.0.1",
|
||||
"172.17.0.0/16",
|
||||
"192.168.1.0/24"
|
||||
"127.0.0.2"
|
||||
]
|
||||
|
||||
# IP黑名单,支持单个IP或IP段
|
||||
|
||||
@@ -90,6 +90,7 @@ func registerFrontendRoutes(router *gin.Engine, enabled bool) {
|
||||
func buildRouter(cfg *config.AppConfig) *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
router := gin.Default()
|
||||
utils.ConfigureTrustedProxies(router)
|
||||
|
||||
router.Use(gin.CustomRecovery(func(c *gin.Context, recovered interface{}) {
|
||||
log.Printf("Panic 已恢复: %v", recovered)
|
||||
|
||||
@@ -17,6 +17,19 @@ const (
|
||||
MaxIPCacheSize = 10000
|
||||
)
|
||||
|
||||
// 可信反代
|
||||
var trustedProxyCIDRs = []string{
|
||||
"127.0.0.0/8",
|
||||
"10.0.0.0/8",
|
||||
"172.16.0.0/12",
|
||||
"192.168.0.0/16",
|
||||
}
|
||||
|
||||
// ConfigureTrustedProxies 可信反代
|
||||
func ConfigureTrustedProxies(router *gin.Engine) {
|
||||
_ = router.SetTrustedProxies(trustedProxyCIDRs)
|
||||
}
|
||||
|
||||
// IPRateLimiter IP限流器结构体
|
||||
type IPRateLimiter struct {
|
||||
ips map[string]*rateLimiterEntry
|
||||
@@ -219,34 +232,7 @@ func RateLimitMiddleware(limiter *IPRateLimiter) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
var ip string
|
||||
|
||||
if forwarded := c.GetHeader("X-Forwarded-For"); forwarded != "" {
|
||||
ips := strings.Split(forwarded, ",")
|
||||
ip = strings.TrimSpace(ips[0])
|
||||
} else if realIP := c.GetHeader("X-Real-IP"); realIP != "" {
|
||||
ip = realIP
|
||||
} else if remoteIP := c.GetHeader("X-Original-Forwarded-For"); remoteIP != "" {
|
||||
ips := strings.Split(remoteIP, ",")
|
||||
ip = strings.TrimSpace(ips[0])
|
||||
} else {
|
||||
ip = c.ClientIP()
|
||||
}
|
||||
|
||||
cleanIP := extractIPFromAddress(ip)
|
||||
|
||||
normalizedIP := normalizeIPForRateLimit(cleanIP)
|
||||
if cleanIP != normalizedIP {
|
||||
fmt.Printf("请求IP: %s (提纯后: %s, 限流段: %s), X-Forwarded-For: %s, X-Real-IP: %s\n",
|
||||
ip, cleanIP, normalizedIP,
|
||||
c.GetHeader("X-Forwarded-For"),
|
||||
c.GetHeader("X-Real-IP"))
|
||||
} else {
|
||||
fmt.Printf("请求IP: %s (提纯后: %s), X-Forwarded-For: %s, X-Real-IP: %s\n",
|
||||
ip, cleanIP,
|
||||
c.GetHeader("X-Forwarded-For"),
|
||||
c.GetHeader("X-Real-IP"))
|
||||
}
|
||||
cleanIP := extractIPFromAddress(c.ClientIP())
|
||||
|
||||
ipLimiter, allowed := limiter.GetLimiter(cleanIP)
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestExtractIPFromAddress(t *testing.T) {
|
||||
if got := extractIPFromAddress("127.0.0.1:5000"); got != "127.0.0.1" {
|
||||
@@ -19,3 +24,51 @@ func TestNormalizeIPv6ForRateLimit(t *testing.T) {
|
||||
t.Fatalf("IPv6 normalized = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientIPIgnoresSpoofedXFFWithoutTrustedProxy(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
router := gin.New()
|
||||
ConfigureTrustedProxies(router)
|
||||
|
||||
var got string
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
got = c.ClientIP()
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
req.RemoteAddr = "203.0.113.50:12345"
|
||||
req.Header.Set("X-Forwarded-For", "127.0.0.1")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if got != "203.0.113.50" {
|
||||
t.Fatalf("ClientIP() = %q, want 203.0.113.50", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClientIPTrustsXFFFromTrustedProxy(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
router := gin.New()
|
||||
if err := router.SetTrustedProxies([]string{"127.0.0.1"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var got string
|
||||
router.GET("/", func(c *gin.Context) {
|
||||
got = c.ClientIP()
|
||||
})
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
req.RemoteAddr = "127.0.0.1:54321"
|
||||
req.Header.Set("X-Forwarded-For", "203.0.113.50")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
if got != "203.0.113.50" {
|
||||
t.Fatalf("ClientIP() = %q, want 203.0.113.50", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user