1
0

forwarded_trust.go 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package sub
  2. import (
  3. "net"
  4. "net/netip"
  5. "strings"
  6. "sync"
  7. "github.com/gin-gonic/gin"
  8. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  9. "github.com/mhsanaei/3x-ui/v3/internal/web/service"
  10. )
  11. var warnSuppressedForwardedOnce sync.Once
  12. var forwardedHeaderNames = [...]string{"X-Forwarded-Host", "X-Forwarded-Proto", "X-Real-IP"}
  13. func (s *SubService) forwardedHeadersTrusted(c *gin.Context) (trusted bool) {
  14. if !hasForwardedHeaders(c) {
  15. return true
  16. }
  17. trusted = true
  18. defer func() {
  19. _ = recover()
  20. }()
  21. configured, err := s.settingService.GetTrustedProxyCIDRs()
  22. if err != nil {
  23. return true
  24. }
  25. configured = strings.TrimSpace(configured)
  26. if configured == "" || configured == service.DefaultTrustedProxyCIDRs {
  27. return true
  28. }
  29. return remoteAddrInCIDRs(c.Request.RemoteAddr, configured)
  30. }
  31. func hasForwardedHeaders(c *gin.Context) bool {
  32. for _, name := range forwardedHeaderNames {
  33. if c.GetHeader(name) != "" {
  34. return true
  35. }
  36. }
  37. return false
  38. }
  39. func warnSuppressedForwardedHeaders(c *gin.Context) {
  40. present := make([]string, 0, 3)
  41. for _, name := range forwardedHeaderNames {
  42. if c.GetHeader(name) != "" {
  43. present = append(present, name)
  44. }
  45. }
  46. if len(present) == 0 {
  47. return
  48. }
  49. headers := strings.Join(present, ", ")
  50. logger.Debugf("sub: ignoring %s from %s, which is outside trustedProxyCIDRs", headers, c.Request.RemoteAddr)
  51. warnSuppressedForwardedOnce.Do(func() {
  52. logger.Warningf("sub: ignoring %s from %s because it is outside trustedProxyCIDRs; subscription URLs will use the request host. Add the proxy to that setting, or set subURI, if the generated links look wrong.", headers, c.Request.RemoteAddr)
  53. })
  54. }
  55. func remoteAddrInCIDRs(remoteAddr, cidrs string) bool {
  56. host := remoteAddr
  57. if h, _, err := net.SplitHostPort(remoteAddr); err == nil {
  58. host = h
  59. }
  60. addr, err := netip.ParseAddr(strings.TrimSpace(host))
  61. if err != nil {
  62. return false
  63. }
  64. addr = addr.Unmap()
  65. for value := range strings.SplitSeq(cidrs, ",") {
  66. value = strings.TrimSpace(value)
  67. if value == "" {
  68. continue
  69. }
  70. if prefix, err := netip.ParsePrefix(value); err == nil {
  71. if prefix.Contains(addr) {
  72. return true
  73. }
  74. continue
  75. }
  76. if proxyIP, err := netip.ParseAddr(value); err == nil && proxyIP.Unmap() == addr.Unmap() {
  77. return true
  78. }
  79. }
  80. return false
  81. }