github.com/ulule/limiter/v3@v3.11.3-0.20230613131926-4cb9c1da4633/network.go (about) 1 package limiter 2 3 import ( 4 "net" 5 "net/http" 6 "strings" 7 ) 8 9 var ( 10 // DefaultIPv4Mask defines the default IPv4 mask used to obtain user IP. 11 DefaultIPv4Mask = net.CIDRMask(32, 32) 12 // DefaultIPv6Mask defines the default IPv6 mask used to obtain user IP. 13 DefaultIPv6Mask = net.CIDRMask(128, 128) 14 ) 15 16 // GetIP returns IP address from request. 17 // If options is defined and either TrustForwardHeader is true or ClientIPHeader is defined, 18 // it will lookup IP in HTTP headers. 19 // Please be advised that using this option could be insecure (ie: spoofed) if your reverse 20 // proxy is not configured properly to forward a trustworthy client IP. 21 // Please read the section "Limiter behind a reverse proxy" in the README for further information. 22 func (limiter *Limiter) GetIP(r *http.Request) net.IP { 23 return GetIP(r, limiter.Options) 24 } 25 26 // GetIPWithMask returns IP address from request by applying a mask. 27 // If options is defined and either TrustForwardHeader is true or ClientIPHeader is defined, 28 // it will lookup IP in HTTP headers. 29 // Please be advised that using this option could be insecure (ie: spoofed) if your reverse 30 // proxy is not configured properly to forward a trustworthy client IP. 31 // Please read the section "Limiter behind a reverse proxy" in the README for further information. 32 func (limiter *Limiter) GetIPWithMask(r *http.Request) net.IP { 33 return GetIPWithMask(r, limiter.Options) 34 } 35 36 // GetIPKey extracts IP from request and returns hashed IP to use as store key. 37 // If options is defined and either TrustForwardHeader is true or ClientIPHeader is defined, 38 // it will lookup IP in HTTP headers. 39 // Please be advised that using this option could be insecure (ie: spoofed) if your reverse 40 // proxy is not configured properly to forward a trustworthy client IP. 41 // Please read the section "Limiter behind a reverse proxy" in the README for further information. 42 func (limiter *Limiter) GetIPKey(r *http.Request) string { 43 return limiter.GetIPWithMask(r).String() 44 } 45 46 // GetIP returns IP address from request. 47 // If options is defined and either TrustForwardHeader is true or ClientIPHeader is defined, 48 // it will lookup IP in HTTP headers. 49 // Please be advised that using this option could be insecure (ie: spoofed) if your reverse 50 // proxy is not configured properly to forward a trustworthy client IP. 51 // Please read the section "Limiter behind a reverse proxy" in the README for further information. 52 func GetIP(r *http.Request, options ...Options) net.IP { 53 if len(options) >= 1 { 54 if options[0].ClientIPHeader != "" { 55 ip := getIPFromHeader(r, options[0].ClientIPHeader) 56 if ip != nil { 57 return ip 58 } 59 } 60 if options[0].TrustForwardHeader { 61 ip := getIPFromXFFHeader(r) 62 if ip != nil { 63 return ip 64 } 65 66 ip = getIPFromHeader(r, "X-Real-IP") 67 if ip != nil { 68 return ip 69 } 70 } 71 } 72 73 remoteAddr := strings.TrimSpace(r.RemoteAddr) 74 host, _, err := net.SplitHostPort(remoteAddr) 75 if err != nil { 76 return net.ParseIP(remoteAddr) 77 } 78 79 return net.ParseIP(host) 80 } 81 82 // GetIPWithMask returns IP address from request by applying a mask. 83 // If options is defined and either TrustForwardHeader is true or ClientIPHeader is defined, 84 // it will lookup IP in HTTP headers. 85 // Please be advised that using this option could be insecure (ie: spoofed) if your reverse 86 // proxy is not configured properly to forward a trustworthy client IP. 87 // Please read the section "Limiter behind a reverse proxy" in the README for further information. 88 func GetIPWithMask(r *http.Request, options ...Options) net.IP { 89 if len(options) == 0 { 90 return GetIP(r) 91 } 92 93 ip := GetIP(r, options[0]) 94 if ip.To4() != nil { 95 return ip.Mask(options[0].IPv4Mask) 96 } 97 if ip.To16() != nil { 98 return ip.Mask(options[0].IPv6Mask) 99 } 100 return ip 101 } 102 103 func getIPFromXFFHeader(r *http.Request) net.IP { 104 headers := r.Header.Values("X-Forwarded-For") 105 if len(headers) == 0 { 106 return nil 107 } 108 109 parts := []string{} 110 for _, header := range headers { 111 parts = append(parts, strings.Split(header, ",")...) 112 } 113 114 for i := range parts { 115 part := strings.TrimSpace(parts[i]) 116 ip := net.ParseIP(part) 117 if ip != nil { 118 return ip 119 } 120 } 121 122 return nil 123 } 124 125 func getIPFromHeader(r *http.Request, name string) net.IP { 126 header := strings.TrimSpace(r.Header.Get(name)) 127 if header == "" { 128 return nil 129 } 130 131 ip := net.ParseIP(header) 132 if ip != nil { 133 return ip 134 } 135 136 return nil 137 }