package utils import ( "errors" "math" "net" "net/http" "strings" ) func GetIP(r *http.Request) string { ip := ClientPublicIP(r) if ip == "" { ip = ClientIP(r) } if ip == "" { ip = "0000" } return ip } // HasLocalIPddr 检测 IP 地址字符串是否是内网地址 // Deprecated: 此为一个错误名称错误拼写的函数,计划在将来移除,请使用 HasLocalIPAddr 函数 func HasLocalIPddr(ip string) bool { return HasLocalIPAddr(ip) } // HasLocalIPAddr 检测 IP 地址字符串是否是内网地址 func HasLocalIPAddr(ip string) bool { return HasLocalIP(net.ParseIP(ip)) } // HasLocalIP 检测 IP 地址是否是内网地址 // 通过直接对比ip段范围效率更高,详见:https://github.com/thinkeridea/go-extend/issues/2 func HasLocalIP(ip net.IP) bool { if ip.IsLoopback() { return true } ip4 := ip.To4() if ip4 == nil { return false } return ip4[0] == 10 || // 10.0.0.0/8 (ip4[0] == 172 && ip4[1] >= 16 && ip4[1] <= 31) || // 172.16.0.0/12 (ip4[0] == 169 && ip4[1] == 254) || // 169.254.0.0/16 (ip4[0] == 192 && ip4[1] == 168) // 192.168.0.0/16 } // ClientIP 尽最大努力实现获取客户端 IP 的算法。 // 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。 func ClientIP(r *http.Request) string { ip := strings.TrimSpace(strings.Split(r.Header.Get("X-Forwarded-For"), ",")[0]) if ip != "" { return ip } ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")) if ip != "" { return ip } if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil { return ip } return "" } // ClientPublicIP 尽最大努力实现获取客户端公网 IP 的算法。 // 解析 X-Real-IP 和 X-Forwarded-For 以便于反向代理(nginx 或 haproxy)可以正常工作。 func ClientPublicIP(r *http.Request) string { var ip string if ip = strings.TrimSpace(r.Header.Get("Ali-Cdn-Real-Ip")); ip != "" { return ip } for _, ip = range strings.Split(r.Header.Get("X-Forwarded-For"), ",") { if ip = strings.TrimSpace(ip); ip != "" && !HasLocalIPAddr(ip) { return ip } } if ip = strings.TrimSpace(r.Header.Get("X-Real-Ip")); ip != "" && !HasLocalIPAddr(ip) { return ip } if ip = RemoteIP(r); !HasLocalIPAddr(ip) { return ip } return "" } // RemoteIP 通过 RemoteAddr 获取 IP 地址, 只是一个快速解析方法。 func RemoteIP(r *http.Request) string { ip, _, _ := net.SplitHostPort(r.RemoteAddr) return ip } // IPString2Long 把ip字符串转为数值 func IPString2Long(ip string) (uint, error) { b := net.ParseIP(ip).To4() if b == nil { return 0, errors.New("invalid ipv4 format") } return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil } // Long2IPString 把数值转为ip字符串 func Long2IPString(i uint) (string, error) { if i > math.MaxUint32 { return "", errors.New("beyond the scope of ipv4") } ip := make(net.IP, net.IPv4len) ip[0] = byte(i >> 24) ip[1] = byte(i >> 16) ip[2] = byte(i >> 8) ip[3] = byte(i) return ip.String(), nil } // IP2Long 把net.IP转为数值 func IP2Long(ip net.IP) (uint, error) { b := ip.To4() if b == nil { return 0, errors.New("invalid ipv4 format") } return uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24, nil } // Long2IP 把数值转为net.IP func Long2IP(i uint) (net.IP, error) { if i > math.MaxUint32 { return nil, errors.New("beyond the scope of ipv4") } ip := make(net.IP, net.IPv4len) ip[0] = byte(i >> 24) ip[1] = byte(i >> 16) ip[2] = byte(i >> 8) ip[3] = byte(i) return ip, nil }