diff --git a/docker-compose.yml b/docker-compose.yml index 4479a64..f0fdae5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,5 +10,5 @@ services: logging: driver: json-file options: - max-size: "1g" - max-file: "2" + max-size: "200m" + max-file: "3" \ No newline at end of file diff --git a/src/config.toml b/src/config.toml index 74d0d39..01d6b79 100644 --- a/src/config.toml +++ b/src/config.toml @@ -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段 diff --git a/src/main.go b/src/main.go index c97e13b..db3508a 100644 --- a/src/main.go +++ b/src/main.go @@ -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) diff --git a/src/utils/ratelimiter.go b/src/utils/ratelimiter.go index 6531319..2cb7501 100644 --- a/src/utils/ratelimiter.go +++ b/src/utils/ratelimiter.go @@ -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) diff --git a/src/utils/ratelimiter_test.go b/src/utils/ratelimiter_test.go index 0277d69..5628a38 100644 --- a/src/utils/ratelimiter_test.go +++ b/src/utils/ratelimiter_test.go @@ -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) + } +}