github.com/status-im/status-go@v1.1.0/server/ips.go (about) 1 package server 2 3 import ( 4 "net" 5 6 "go.uber.org/zap" 7 8 "github.com/status-im/status-go/common" 9 "github.com/status-im/status-go/logutils" 10 ) 11 12 var ( 13 LocalHostIP = net.IP{127, 0, 0, 1} 14 Localhost = "Localhost" 15 ) 16 17 func GetOutboundIP() (net.IP, error) { 18 conn, err := net.Dial("udp", "255.255.255.255:8080") 19 if err != nil { 20 return nil, err 21 } 22 defer conn.Close() 23 24 localAddr := conn.LocalAddr().(*net.UDPAddr) 25 26 return localAddr.IP, nil 27 } 28 29 // addrToIPNet casts addr to IPNet. 30 // Returns nil if addr is not of IPNet type. 31 func addrToIPNet(addr net.Addr) *net.IPNet { 32 switch v := addr.(type) { 33 case *net.IPNet: 34 return v 35 default: 36 return nil 37 } 38 } 39 40 // filterAddressesForPairingServer filters private unicast addresses. 41 // ips is a 2-dimensional array, where each sub-array is a list of IP 42 // addresses for a single network interface. 43 func filterAddressesForPairingServer(ips [][]net.IP) []net.IP { 44 var result = map[string]net.IP{} 45 46 for _, niIps := range ips { 47 var ipv4, ipv6 []net.IP 48 49 for _, ip := range niIps { 50 51 // Only take private global unicast addrs 52 if !ip.IsGlobalUnicast() || !ip.IsPrivate() { 53 continue 54 } 55 56 if v := ip.To4(); v != nil { 57 ipv4 = append(ipv4, ip) 58 } else { 59 ipv6 = append(ipv6, ip) 60 } 61 } 62 63 // Prefer IPv4 over IPv6 for shorter connection string 64 if len(ipv4) == 0 { 65 for _, ip := range ipv6 { 66 result[ip.String()] = ip 67 } 68 } else { 69 for _, ip := range ipv4 { 70 result[ip.String()] = ip 71 } 72 } 73 } 74 75 var out []net.IP 76 for _, v := range result { 77 out = append(out, v) 78 } 79 80 return out 81 } 82 83 // getAndroidLocalIP uses the net dial default ip as the standard Android IP address 84 // patches https://github.com/status-im/status-mobile/issues/17156 85 // more work required for a more robust implementation, see https://github.com/wlynxg/anet 86 func getAndroidLocalIP() ([][]net.IP, error) { 87 ip, err := GetOutboundIP() 88 if err != nil { 89 return nil, err 90 } 91 92 return [][]net.IP{{ip}}, nil 93 } 94 95 // getLocalAddresses returns an array of all addresses 96 // of all available network interfaces. 97 func getLocalAddresses() ([][]net.IP, error) { 98 // TODO until we can resolve Android errors when calling net.Interfaces() just return the outbound local address. 99 // Sorry Android 100 if common.OperatingSystemIs(common.AndroidPlatform) { 101 return getAndroidLocalIP() 102 } 103 104 nis, err := net.Interfaces() 105 if err != nil { 106 return nil, err 107 } 108 109 var ips [][]net.IP 110 111 for _, ni := range nis { 112 var niIps []net.IP 113 114 addrs, err := ni.Addrs() 115 if err != nil { 116 logutils.ZapLogger().Warn("failed to get addresses of network interface", 117 zap.String("networkInterface", ni.Name), 118 zap.Error(err)) 119 continue 120 } 121 122 for _, addr := range addrs { 123 var ip net.IP 124 if ipNet := addrToIPNet(addr); ipNet == nil { 125 continue 126 } else { 127 ip = ipNet.IP 128 } 129 niIps = append(niIps, ip) 130 } 131 132 if len(niIps) > 0 { 133 ips = append(ips, niIps) 134 } 135 } 136 137 return ips, nil 138 } 139 140 // GetLocalAddressesForPairingServer is a high-level func 141 // that returns a list of addresses to be used by local pairing server. 142 func GetLocalAddressesForPairingServer() ([]net.IP, error) { 143 ips, err := getLocalAddresses() 144 if err != nil { 145 return nil, err 146 } 147 return filterAddressesForPairingServer(ips), nil 148 } 149 150 // findReachableAddresses returns a filtered remoteIps array, 151 // in which each IP matches one or more of given localNets. 152 func findReachableAddresses(remoteIPs []net.IP, localNets []net.IPNet) []net.IP { 153 var result []net.IP 154 for _, localNet := range localNets { 155 for _, remoteIP := range remoteIPs { 156 if localNet.Contains(remoteIP) { 157 result = append(result, remoteIP) 158 } 159 } 160 } 161 return result 162 } 163 164 // getAllAvailableNetworks collects all networks 165 // from available network interfaces. 166 func getAllAvailableNetworks() ([]net.IPNet, error) { 167 var localNets []net.IPNet 168 169 nis, err := net.Interfaces() 170 if err != nil { 171 return nil, err 172 } 173 174 for _, ni := range nis { 175 addrs, err := ni.Addrs() 176 if err != nil { 177 logutils.ZapLogger().Warn("failed to get addresses of network interface", 178 zap.String("networkInterface", ni.Name), 179 zap.Error(err)) 180 continue 181 } 182 183 for _, localAddr := range addrs { 184 localNets = append(localNets, *addrToIPNet(localAddr)) 185 } 186 } 187 return localNets, nil 188 } 189 190 // FindReachableAddressesForPairingClient is a high-level func 191 // that returns a reachable server's address to be used by local pairing client. 192 func FindReachableAddressesForPairingClient(serverIps []net.IP) ([]net.IP, error) { 193 // TODO until we can resolve Android errors when calling net.Interfaces() just noop. Sorry Android 194 if common.OperatingSystemIs(common.AndroidPlatform) { 195 return serverIps, nil 196 } 197 198 nets, err := getAllAvailableNetworks() 199 if err != nil { 200 return nil, err 201 } 202 return findReachableAddresses(serverIps, nets), nil 203 }