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  }