github.com/kaydxh/golang@v0.0.131/go/net/ip.go (about) 1 /* 2 *Copyright (c) 2022, kaydxh 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining a copy 5 *of this software and associated documentation files (the "Software"), to deal 6 *in the Software without restriction, including without limitation the rights 7 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 *copies of the Software, and to permit persons to whom the Software is 9 *furnished to do so, subject to the following conditions: 10 * 11 *The above copyright notice and this permission notice shall be included in all 12 *copies or substantial portions of the Software. 13 * 14 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 *SOFTWARE. 21 */ 22 package net 23 24 import ( 25 "context" 26 "errors" 27 "fmt" 28 "net" 29 "os" 30 "strconv" 31 32 hash_ "github.com/kaydxh/golang/go/encoding/hash" 33 os_ "github.com/kaydxh/golang/go/os" 34 ) 35 36 // This code is borrowed from https://github.com/uber/tchannel-go/blob/dev/localip.go 37 38 // scoreAddr scores how likely the given addr is to be a remote address and returns the 39 // IP to use when listening. Any address which receives a negative score should not be used. 40 // Scores are calculated as: 41 // -1 for any unknown IP addresses. 42 // +300 for IPv4 addresses 43 // +100 for non-local addresses, extra +100 for "up" interaces. 44 func scoreAddr(iface net.Interface, addr net.Addr) (int, net.IP) { 45 var ip net.IP 46 if netAddr, ok := addr.(*net.IPNet); ok { 47 ip = netAddr.IP 48 } else if netIP, ok := addr.(*net.IPAddr); ok { 49 ip = netIP.IP 50 } else { 51 return -1, nil 52 } 53 54 var score int 55 if ip.To4() != nil { 56 score += 300 57 } 58 if iface.Flags&net.FlagLoopback == 0 && !ip.IsLoopback() { 59 score += 100 60 if iface.Flags&net.FlagUp != 0 { 61 score += 100 62 } 63 } 64 65 return score, ip 66 } 67 68 // HostIP tries to find an IP that can be used by other machines to reach this machine. 69 func GetHostIP() (net.IP, error) { 70 interfaces, err := net.Interfaces() 71 if err != nil { 72 return nil, err 73 } 74 75 bestScore := -1 76 var bestIP net.IP 77 // Select the highest scoring IP as the best IP. 78 for _, iface := range interfaces { 79 addrs, err := iface.Addrs() 80 if err != nil { 81 // Skip this interface if there is an error. 82 continue 83 } 84 85 for _, addr := range addrs { 86 score, ip := scoreAddr(iface, addr) 87 if score > bestScore { 88 bestScore = score 89 bestIP = ip 90 } 91 } 92 } 93 94 if bestScore == -1 { 95 return nil, errors.New("no addresses to listen on") 96 } 97 98 return bestIP, nil 99 } 100 101 func GetLocalFirstIP() (string, error) { 102 ips, err := GetLocalIPs() 103 if err != nil { 104 return "", err 105 } 106 if len(ips) == 0 { 107 return "", fmt.Errorf("no valid ip") 108 } 109 110 return ips[0], nil 111 } 112 113 func GetLocalIPs() ([]string, error) { 114 localAddrs, err := GetLocalAddrs() 115 if err != nil { 116 return nil, err 117 } 118 119 var ips []string 120 for _, addr := range localAddrs { 121 if addr.IP.To4() != nil && !addr.IP.IsLoopback() { 122 ips = append(ips, addr.IP.String()) 123 } 124 125 } 126 127 return ips, nil 128 } 129 130 func GetLocalAddrs() ([]*net.IPNet, error) { 131 var localAddrs []*net.IPNet 132 addrs, err := net.InterfaceAddrs() 133 if err != nil { 134 return nil, err 135 } 136 137 for _, addr := range addrs { 138 ipNet, ok := addr.(*net.IPNet) 139 if ok { 140 localAddrs = append(localAddrs, ipNet) 141 } 142 } 143 144 return localAddrs, nil 145 } 146 147 // IsIPv4 returns if netIP is IPv4. 148 func IsIPv4(netIP net.IP) bool { 149 return netIP != nil && netIP.To4() != nil 150 } 151 152 func IsIPv4String(ip string) bool { 153 netIP := ParseIP(ip) 154 return IsIPv4(netIP) 155 } 156 157 func LookupHostIPv4(host string) (addrs []string, err error) { 158 return LookupHostIPv4WithContext(context.Background(), host) 159 } 160 161 func LookupHostIPv4WithContext(ctx context.Context, host string) (addrs []string, err error) { 162 ips, err := net.DefaultResolver.LookupHost(ctx, host) 163 if err != nil { 164 return 165 } 166 167 for _, ip := range ips { 168 if IsIPv4String(ip) { 169 addrs = append(addrs, ip) 170 } 171 } 172 173 return addrs, err 174 } 175 176 // SplitHostIntPort split host and integral port 177 func SplitHostIntPort(s string) (string, int, error) { 178 host, port, err := net.SplitHostPort(s) 179 if err != nil { 180 return "", 0, err 181 } 182 portInt, err := strconv.Atoi(port) 183 if err != nil { 184 return "", 0, err 185 } 186 return host, portInt, err 187 } 188 189 // parseTarget takes the user input target string and default port, returns formatted host and port info. 190 // If target doesn't specify a port, set the port to be the defaultPort. 191 // If target is in IPv6 format and host-name is enclosed in square brackets, brackets 192 // are stripped when setting the host. 193 // examples: 194 // target: "www.google.com" defaultPort: "443" returns host: "www.google.com", port: "443" 195 // target: "ipv4-host:80" defaultPort: "443" returns host: "ipv4-host", port: "80" 196 // target: "[ipv6-host]" defaultPort: "443" returns host: "ipv6-host", port: "443" 197 // target: ":80" defaultPort: "443" returns host: "localhost", port: "80" 198 func ParseTarget(target, defaultPort string) (host, port string, err error) { 199 if target == "" { 200 return "", "", fmt.Errorf("target is empty") 201 } 202 if ip := net.ParseIP(target); ip != nil { 203 // target is an IPv4 or IPv6(without brackets) address 204 return target, defaultPort, nil 205 } 206 if host, port, err = net.SplitHostPort(target); err == nil { 207 if port == "" { 208 // If the port field is empty (target ends with colon), e.g. "[::1]:", this is an error. 209 return "", "", fmt.Errorf("missing port after port-separator colon") 210 } 211 // target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port 212 if host == "" { 213 // Keep consistent with net.Dial(): If the host is empty, as in ":80", the local system is assumed. 214 host = "localhost" 215 } 216 return host, port, nil 217 } 218 if host, port, err = net.SplitHostPort(target + ":" + defaultPort); err == nil { 219 // target doesn't have port 220 return host, port, nil 221 } 222 return "", "", fmt.Errorf("invalid target address %v, error info: %v", target, err) 223 } 224 225 // 1 get k8s pod name 226 // 2 get ip:pid 227 func GetServerName() string { 228 serverName := fmt.Sprintf("%v:%v", os.Getenv("POD_NAMESPACE"), os.Getenv("POD_NAME")) 229 if serverName == ":" { 230 ip, _ := GetHostIP() 231 pid := os_.GetProcId() 232 return fmt.Sprintf("%s:%v", ip.String(), pid) 233 } 234 return serverName 235 } 236 237 func GetServerId() uint32 { 238 return hash_.HashCode(GetServerName()) 239 }