github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/znet/ip.go (about) 1 package znet 2 3 import ( 4 "errors" 5 "math" 6 "math/big" 7 "net" 8 "net/http" 9 "strconv" 10 "strings" 11 "sync" 12 ) 13 14 var ( 15 RemoteIPHeaders = []string{"X-Forwarded-For", "X-Real-IP"} 16 TrustedProxies = []string{"0.0.0.0/0"} 17 LocalNetworks = []string{"127.0.0.0/8", "10.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "172.0.0.0/8", "192.168.0.0/16"} 18 ) 19 20 var ( 21 localNetworks []*net.IPNet 22 localNetworksOnce sync.Once 23 ) 24 25 func getLocalNetworks() []*net.IPNet { 26 localNetworksOnce.Do(func() { 27 localNetworks = make([]*net.IPNet, 0, len(LocalNetworks)) 28 for _, sNetwork := range LocalNetworks { 29 _, network, err := net.ParseCIDR(sNetwork) 30 if err == nil { 31 localNetworks = append(localNetworks, network) 32 } 33 } 34 }) 35 return localNetworks 36 } 37 38 // IsLocalAddrIP IsLocalAddrIP 39 func IsLocalAddrIP(ip string) bool { 40 return IsLocalIP(net.ParseIP(ip)) 41 } 42 43 // IsLocalIP IsLocalIP 44 func IsLocalIP(ip net.IP) bool { 45 for _, network := range getLocalNetworks() { 46 if network.Contains(ip) { 47 return true 48 } 49 } 50 if ip.String() == "0.0.0.0" { 51 return true 52 } 53 return ip.IsLoopback() || ip.IsLinkLocalMulticast() || ip.IsLinkLocalUnicast() 54 } 55 56 func getTrustedIP(r *http.Request, remoteIP string) string { 57 ip := remoteIP 58 for i := range RemoteIPHeaders { 59 key := RemoteIPHeaders[i] 60 val := r.Header.Get(key) 61 ips := parseHeadersIP(val) 62 for i := range ips { 63 Log.Debug(i, ips[i]) 64 } 65 } 66 return ip 67 } 68 69 func getRemoteIP(r *http.Request) []string { 70 ips := make([]string, 0) 71 ip := RemoteIP(r) 72 trusted := ip == "" 73 if !trusted { 74 if len(TrustedProxies) > 0 { 75 for i := range TrustedProxies { 76 proxy := TrustedProxies[i] 77 if InNetwork(ip, proxy) { 78 trusted = true 79 break 80 } 81 } 82 } else { 83 trusted = true 84 } 85 } 86 87 if trusted { 88 for i := range RemoteIPHeaders { 89 key := RemoteIPHeaders[i] 90 val := r.Header.Get(key) 91 ips = append(ips, parseHeadersIP(val)...) 92 } 93 } 94 return append(ips, ip) 95 } 96 97 func parseHeadersIP(val string) []string { 98 if val == "" { 99 return []string{} 100 } 101 str := strings.Split(val, ",") 102 l := len(str) 103 ips := make([]string, l) 104 for i := l - 1; i >= 0; i-- { 105 ips[l-1-i] = strings.TrimSpace(str[i]) 106 } 107 return ips 108 } 109 110 // ClientIP ClientIP 111 func ClientIP(r *http.Request) (ip string) { 112 ips := getRemoteIP(r) 113 if len(ips) > 0 && ips[0] != "" { 114 return ips[0] 115 } 116 return 117 } 118 119 // ClientPublicIP ClientPublicIP 120 func ClientPublicIP(r *http.Request) string { 121 var ip string 122 ips := getRemoteIP(r) 123 for i := range ips { 124 ip = ips[i] 125 if ip != "" && !IsLocalAddrIP(ip) { 126 return ip 127 } 128 } 129 return "" 130 } 131 132 // RemoteIP Remote IP 133 func RemoteIP(r *http.Request) string { 134 if ip, _, err := net.SplitHostPort(strings.TrimSpace(r.RemoteAddr)); err == nil { 135 return ip 136 } 137 138 return "" 139 } 140 141 // IPToLong IPToLong 142 func IPToLong(ip string) (i uint, err error) { 143 return NetIPToLong(net.ParseIP(ip)) 144 } 145 146 // LongToIP LongToIP 147 func LongToIP(i uint) (string, error) { 148 ip, err := LongToNetIP(i) 149 if err != nil { 150 return "", err 151 } 152 153 return ip.String(), nil 154 } 155 156 // NetIPToLong NetIPToLong 157 func NetIPToLong(ip net.IP) (i uint, err error) { 158 b := ip.To4() 159 if b == nil { 160 err = errors.New("invalid ipv4 format") 161 return 162 } 163 164 i = uint(b[3]) | uint(b[2])<<8 | uint(b[1])<<16 | uint(b[0])<<24 165 return 166 } 167 168 // NetIPv6ToLong NetIPv6ToLong 169 func NetIPv6ToLong(ip net.IP) (*big.Int, error) { 170 if ip == nil { 171 return nil, errors.New("invalid ipv6 format") 172 } 173 IPv6Int := big.NewInt(0) 174 IPv6Int.SetBytes(ip.To16()) 175 return IPv6Int, nil 176 } 177 178 // LongToNetIP LongToNetIP 179 func LongToNetIP(i uint) (ip net.IP, err error) { 180 if i > math.MaxUint32 { 181 err = errors.New("beyond the scope of ipv4") 182 return 183 } 184 185 ip = make(net.IP, net.IPv4len) 186 ip[0] = byte(i >> 24) 187 ip[1] = byte(i >> 16) 188 ip[2] = byte(i >> 8) 189 ip[3] = byte(i) 190 191 return 192 } 193 194 // LongToNetIPv6 LongToNetIPv6 195 func LongToNetIPv6(i *big.Int) (ip net.IP, err error) { 196 ip = i.Bytes() 197 return 198 } 199 200 // IsIP IsIP 201 func IsIP(ip string) bool { 202 return net.ParseIP(ip) != nil 203 } 204 205 // GetIPv GetIPv 206 func GetIPv(s string) int { 207 for i := 0; i < len(s); i++ { 208 switch s[i] { 209 case '.': 210 return 4 211 case ':': 212 return 6 213 } 214 } 215 return 0 216 } 217 218 func netCIDR(network string) (*net.IPNet, error) { 219 _, n, err := net.ParseCIDR(network) 220 if err != nil && IsIP(network) { 221 _, n, err = net.ParseCIDR(network + "/24") 222 } 223 if err != nil { 224 return nil, err 225 } 226 return n, nil 227 } 228 229 // InNetwork InNetwork 230 func InNetwork(ip, network string) bool { 231 n, err := netCIDR(network) 232 if err != nil { 233 return false 234 } 235 netIP := net.ParseIP(ip) 236 return n.Contains(netIP) 237 } 238 239 // Port GetPort Check if the port is available, if not, then automatically get an available 240 func Port(port int, change bool) (newPort int, err error) { 241 host := ":" + strconv.Itoa(port) 242 listener, err := net.Listen("tcp", host) 243 if err != nil { 244 if !change && port != 0 { 245 return 0, err 246 } 247 listener, err = net.Listen("tcp", ":0") 248 if err != nil { 249 return 0, err 250 } 251 } 252 defer listener.Close() 253 addr := listener.Addr().String() 254 _, portString, err := net.SplitHostPort(addr) 255 if err != nil { 256 return 0, err 257 } 258 return strconv.Atoi(portString) 259 } 260 261 // MultiplePort Check if the multiple port is available, if not, then automatically get an available 262 func MultiplePort(ports []int, change bool) (int, error) { 263 last := len(ports) - 1 264 for k, v := range ports { 265 c := false 266 if last == k { 267 c = change 268 } 269 n, err := Port(v, c) 270 if err == nil { 271 return n, nil 272 } 273 } 274 return 0, errors.New("no available port") 275 }