github.com/songzhibin97/gkit@v1.2.13/net/ip/ip.go (about)

     1  package ip
     2  
     3  import (
     4  	"errors"
     5  	"math"
     6  	"net"
     7  	"net/http"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	xForwardedFor = "X-Forwarded-For"
    13  	xRealIP       = "X-Real-IP"
    14  )
    15  
    16  func HasLocalIPAddr(ip string) bool {
    17  	return HasLocalIP(net.ParseIP(ip))
    18  }
    19  
    20  func HasLocalIP(ip net.IP) bool {
    21  	if ip.IsLoopback() {
    22  		return true
    23  	}
    24  
    25  	ip4 := ip.To4()
    26  	if ip4 == nil {
    27  		return false
    28  	}
    29  
    30  	return ip4[0] == 10 || // 10.0.0.0/8
    31  		(ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12
    32  		(ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16
    33  		(ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16
    34  }
    35  
    36  func ClientIP(req *http.Request) string {
    37  	if ip := strings.TrimSpace(strings.Split(req.Header.Get(xForwardedFor), ",")[0]); ip != "" {
    38  		return ip
    39  	}
    40  	if ip := strings.TrimSpace(req.Header.Get(xRealIP)); ip != "" {
    41  		return ip
    42  	}
    43  	return RemoteIP(req)
    44  }
    45  
    46  func ClientPublicIP(req *http.Request) string {
    47  	if ip := strings.TrimSpace(strings.Split(req.Header.Get(xForwardedFor), ",")[0]); ip != "" && !HasLocalIPAddr(ip) {
    48  		return ip
    49  	}
    50  	if ip := strings.TrimSpace(req.Header.Get(xRealIP)); ip != "" && !HasLocalIPAddr(ip) {
    51  		return ip
    52  	}
    53  	if ip := RemoteIP(req); ip != "" && !HasLocalIPAddr(ip) {
    54  		return ip
    55  	}
    56  	return ""
    57  }
    58  
    59  func RemoteIP(req *http.Request) string {
    60  	ip, _, err := net.SplitHostPort(strings.TrimSpace(req.RemoteAddr))
    61  	if err != nil {
    62  		return ""
    63  	}
    64  	return ip
    65  }
    66  
    67  func IsWebsocket(req *http.Request) bool {
    68  	if strings.Contains(strings.ToLower(requestHeader(req, "Connection")), "upgrade") &&
    69  		strings.EqualFold(requestHeader(req, "Upgrade"), "websocket") {
    70  		return true
    71  	}
    72  	return false
    73  }
    74  
    75  func requestHeader(req *http.Request, key string) string {
    76  	return req.Header.Get(key)
    77  }
    78  
    79  // ContentType returns the Content-Type header of the request.
    80  func ContentType(req *http.Request) string {
    81  	return filterFlags(requestHeader(req, "Content-Type"))
    82  }
    83  
    84  func filterFlags(content string) string {
    85  	for i, char := range content {
    86  		if char == ' ' || char == ';' {
    87  			return content[:i]
    88  		}
    89  	}
    90  	return content
    91  }
    92  
    93  func StringToLong(ip string) (uint, error) {
    94  	b := net.ParseIP(ip).To4()
    95  	if b == nil {
    96  		return 0, errors.New("invalid ipv4 format")
    97  	}
    98  
    99  	return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
   100  }
   101  
   102  func LongToIPString(i uint) (string, error) {
   103  	if i > math.MaxUint32 {
   104  		return "", errors.New("beyond the scope of ipv4")
   105  	}
   106  
   107  	ip := make(net.IP, net.IPv4len)
   108  	ip[0] = byte(i >> 24)
   109  	ip[1] = byte(i >> 16)
   110  	ip[2] = byte(i >> 8)
   111  	ip[3] = byte(i)
   112  
   113  	return ip.String(), nil
   114  }
   115  
   116  func ToLong(ip net.IP) (uint, error) {
   117  	b := ip.To4()
   118  	if b == nil {
   119  		return 0, errors.New("invalid ipv4 format")
   120  	}
   121  
   122  	return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil
   123  }
   124  
   125  func LongToIP(i uint) (net.IP, error) {
   126  	if i > math.MaxUint32 {
   127  		return nil, errors.New("beyond the scope of ipv4")
   128  	}
   129  
   130  	ip := make(net.IP, net.IPv4len)
   131  	ip[0] = byte(i >> 24)
   132  	ip[1] = byte(i >> 16)
   133  	ip[2] = byte(i >> 8)
   134  	ip[3] = byte(i)
   135  
   136  	return ip, nil
   137  }