static IPRange() { //We want to ignore IP's that have been auto assigned //169.254.0.0 IPAddress autoAssignSubnetv4 = new IPAddress(new byte[] { 169, 254, 0, 0 }); //255.255.0.0 IPAddress autoAssignSubnetMaskv4 = new IPAddress(new byte[] { 255, 255, 0, 0 }); IPRange autoAssignRangev4 = new IPRange(autoAssignSubnetv4, autoAssignSubnetMaskv4); //IPv6 equivalent of 169.254.x.x is fe80: /64 IPAddress autoAssignSubnetv6 = new IPAddress(new byte[] { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); //mask for above IPAddress autoAssignSubnetMaskv6 = new IPAddress(new byte[] { 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); IPRange autoAssignRangev6 = new IPRange(autoAssignSubnetv6, autoAssignSubnetMaskv6); AutoAssignRanges = new List <IPRange>() { autoAssignRangev4, autoAssignRangev6 }; }
/// <summary> /// Returns all allowed local IP addresses. Caches results for up to 5 second since the previous refresh unless forceCacheUpdate is true. /// If <see cref="RestrictLocalAdaptorNames"/> has been set only returns IP addresses corresponding with specified adaptors. /// If <see cref="RestrictLocalAddressRanges"/> has been set only returns matching addresses ordered in descending /// preference. i.e. Most preferred at [0]. /// </summary> /// <param name="forceCacheUpdate">If true will refresh the cache and return latest result</param> /// <returns></returns> public static List <IPAddress> FilteredLocalAddresses(bool forceCacheUpdate) { if (filteredLocalAddressesCache != null && (DateTime.UtcNow - filteredLocalAddressesCacheUpdate).TotalSeconds < 5) { return(filteredLocalAddressesCache); } else { #if WINDOWS_PHONE || NETFX_CORE //On windows phone we simply ignore IP addresses from the auto assigned range as well as those without a valid prefix List <IPAddress> allowedIPs = new List <IPAddress>(); foreach (var hName in Windows.Networking.Connectivity.NetworkInformation.GetHostNames()) { IPAddress temp; if (!hName.DisplayName.StartsWith("169.254") && IPAddress.TryParse(hName.DisplayName, out temp)) { if (RestrictLocalAddressRanges != null) { bool valid = false; for (int i = 0; i < RestrictLocalAddressRanges.Length; i++) { valid |= RestrictLocalAddressRanges[i].Contains(hName.DisplayName); } if (valid) { allowedIPs.Add(IPAddress.Parse(hName.DisplayName)); } } else { allowedIPs.Add(IPAddress.Parse(hName.DisplayName)); } } } return(allowedIPs); #else List <IPAddress> validIPAddresses = new List <IPAddress>(); #if ANDROID var iFaces = Java.Net.NetworkInterface.NetworkInterfaces; while (iFaces.HasMoreElements) { bool interfaceValid = false; var iFace = iFaces.NextElement() as Java.Net.NetworkInterface; var javaAddresses = iFace.InetAddresses; if (RestrictLocalAdaptorNames != null) { foreach (var id in RestrictLocalAdaptorNames) { if (id == iFace.Name) { interfaceValid = true; break; } } } else { interfaceValid = true; } if (!interfaceValid) { continue; } javaAddresses = iFace.InetAddresses; while (javaAddresses.HasMoreElements) { var javaAddress = javaAddresses.NextElement() as Java.Net.InetAddress; IPAddress address = default(IPAddress); if (IPAddress.TryParse(javaAddress.HostAddress, out address)) { if (address.AddressFamily == AddressFamily.InterNetwork || address.AddressFamily == AddressFamily.InterNetworkV6) { if (!IPRange.IsAutoAssignedAddress(address)) { bool allowed = false; if (RestrictLocalAddressRanges != null) { if (IPRange.Contains(RestrictLocalAddressRanges, address)) { allowed = true; } } else { allowed = true; } if (!allowed) { continue; } if (address != IPAddress.None) { validIPAddresses.Add(address); } } } } } } #else foreach (var iFace in NetworkInterface.GetAllNetworkInterfaces()) { bool interfaceValid = false; var unicastAddresses = iFace.GetIPProperties().UnicastAddresses; //Check if this adaptor is allowed if (RestrictLocalAdaptorNames != null && iFace.OperationalStatus == OperationalStatus.Up) { foreach (var currentName in RestrictLocalAdaptorNames) { if (iFace.Name == currentName) { interfaceValid = true; break; } } } else if (iFace.OperationalStatus == OperationalStatus.Up) { interfaceValid = true; } //If the interface is not allowed move to the next adaptor if (!interfaceValid) { continue; } //If the adaptor is allowed we can now investigate the individual addresses foreach (var address in unicastAddresses) { if (address.Address.AddressFamily == AddressFamily.InterNetwork || address.Address.AddressFamily == AddressFamily.InterNetworkV6) { if (!IPRange.IsAutoAssignedAddress(address.Address)) { bool allowed = false; if (RestrictLocalAddressRanges != null) { if (IPRange.Contains(RestrictLocalAddressRanges, address.Address)) { allowed = true; } } else { allowed = true; } if (!allowed) { continue; } if (address.Address != IPAddress.None) { validIPAddresses.Add(address.Address); } } } } } #endif //Sort the results to be returned if (RestrictLocalAddressRanges != null) { validIPAddresses.Sort((a, b) => { for (int i = 0; i < RestrictLocalAddressRanges.Length; i++) { if (RestrictLocalAddressRanges[i].Contains(a)) { if (RestrictLocalAddressRanges[i].Contains(b)) { return(0); } else { return(-1); } } else if (RestrictLocalAddressRanges[i].Contains(b)) { return(1); } } return(0); }); } filteredLocalAddressesCache = validIPAddresses; filteredLocalAddressesCacheUpdate = DateTime.UtcNow; return(validIPAddresses); #endif } }
static IPRange() { //We want to ignore IP's that have been auto assigned //169.254.0.0 IPAddress autoAssignSubnetv4 = new IPAddress(new byte[] { 169, 254, 0, 0 }); //255.255.0.0 IPAddress autoAssignSubnetMaskv4 = new IPAddress(new byte[] { 255, 255, 0, 0 }); IPRange autoAssignRangev4 = new IPRange(autoAssignSubnetv4, autoAssignSubnetMaskv4); //IPv6 equivalent of 169.254.x.x is fe80: /64 IPAddress autoAssignSubnetv6 = new IPAddress(new byte[] { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); //mask for above IPAddress autoAssignSubnetMaskv6 = new IPAddress(new byte[] { 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); IPRange autoAssignRangev6 = new IPRange(autoAssignSubnetv6, autoAssignSubnetMaskv6); AutoAssignRanges = new List<IPRange>() { autoAssignRangev4, autoAssignRangev6 }; }
/// <summary> /// Discover peers using TCP port scan /// </summary> /// <param name="discoverTimeMS"></param> /// <returns></returns> private static Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> DiscoverPeersTCP(int discoverTimeMS) { #region Determine All Possible Peers/Port Combinations //Get a list of all IPEndPoint that we should try and connect to //This requires the network and peer portion of current IP addresses List<IPEndPoint> allIPEndPointsToConnect = new List<IPEndPoint>(); //Look at all possible addresses foreach (var iFace in NetworkInterface.GetAllNetworkInterfaces()) { bool interfaceValid = false; var unicastAddresses = iFace.GetIPProperties().UnicastAddresses; //Check if this adaptor is allowed if (HostInfo.RestrictLocalAdaptorNames != null) { foreach (var currentName in HostInfo.RestrictLocalAdaptorNames) { if (iFace.Name == currentName) { interfaceValid = true; break; } } } else interfaceValid = true; //If the interface is not allowed move to the next adaptor if (!interfaceValid) continue; //If the adaptor is allowed we can now investigate the individual addresses foreach (var address in unicastAddresses) { //We are only interested in IPV4 ranges. A TCPPortScan on an IPV6 range may take a while if (address.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPRange.IsAutoAssignedAddress(address.Address)) { //Check if we have restricted the addresses bool addressAllowed = true; if (HostInfo.IP.RestrictLocalAddressRanges != null) addressAllowed = IPRange.Contains(HostInfo.IP.RestrictLocalAddressRanges, address.Address); if (addressAllowed) { //Generate all possible IPEndPoints for the current address and subnetmask //We have a special catch for the loopback address which has a very large range List<IPAddress> addressesInRange; if (address.Address.Equals(IPAddress.Loopback)) addressesInRange = new List<IPAddress>() { IPAddress.Loopback }; else { IPRange range = new IPRange(address.Address, address.IPv4Mask); addressesInRange = range.AllAddressesInRange(); } foreach (IPAddress currentAddressInRange in addressesInRange) { for (int port = MinTargetLocalIPPort; port <= MaxTargetLocalIPPort; port++) allIPEndPointsToConnect.Add(new IPEndPoint(currentAddressInRange, port)); } } } } } #endregion #region Send Discovery Packet & Wait //For each address send the discovery packet SendReceiveOptions nullOptions = new SendReceiveOptions<NullSerializer>(); StreamTools.StreamSendWrapper sendStream = new StreamTools.StreamSendWrapper(new StreamTools.ThreadSafeStream(new MemoryStream(new byte[0]))); int previousConnectionTimeout = NetworkComms.ConnectionEstablishTimeoutMS; NetworkComms.ConnectionEstablishTimeoutMS = 1000; AutoResetEvent allSendsCompleteEvent = new AutoResetEvent(false); long interlockedCompletedCount = 0; object _syncRoot = new object(); List<Connection> allConnections = new List<Connection>(); //Get unconnected TCP connections foreach (IPEndPoint remoteEndPoint in allIPEndPointsToConnect) { Connection conn = TCPConnection.GetConnection(new ConnectionInfo(remoteEndPoint), false); conn.AppendIncomingPacketHandler<byte[]>(discoveryPacketType, PeerDiscoveryHandler); allConnections.Add(conn); } using (Packet sendPacket = new Packet(discoveryPacketType, sendStream, nullOptions)) { foreach (Connection conn in allConnections) { Connection innerConnection = conn; //The longest wait for the port scan is the TCP connect timeout //The thread pool will start a large number of threads (each of which does very little) // to greatly speed this up _tcpPortScanThreadPool.EnqueueItem(QueueItemPriority.Normal, (state) => { try { try { innerConnection.EstablishConnection(); innerConnection.SendPacket<byte[]>(sendPacket); } catch (CommsException) { } lock (_syncRoot) { interlockedCompletedCount++; if (interlockedCompletedCount == allIPEndPointsToConnect.Count) allSendsCompleteEvent.Set(); } } catch (Exception) { } }, null); } allSendsCompleteEvent.WaitOne(); } NetworkComms.ConnectionEstablishTimeoutMS = previousConnectionTimeout; sendStream.ThreadSafeStream.Dispose(true); AutoResetEvent sleep = new AutoResetEvent(false); //We wait at least 1 second so that connected peers can respond //If we do not wait and close all connections immediately we may miss some replies #if NET2 sleep.WaitOne(Math.Max(discoverTimeMS, 500), false); #else sleep.WaitOne(Math.Max(discoverTimeMS, 500)); #endif //Close any connections we may have established foreach (Connection conn in allConnections) { try { conn.CloseConnection(false); } catch (CommsException) { } } #endregion #region Return Discovered Peers Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>> result = new Dictionary<ShortGuid, Dictionary<ConnectionType, List<EndPoint>>>(); lock (_syncRoot) { foreach (var idPair in _discoveredPeers) { if (!result.ContainsKey(idPair.Key)) result.Add(idPair.Key, new Dictionary<ConnectionType, List<EndPoint>>()); foreach (var typePair in idPair.Value) { if (!result[idPair.Key].ContainsKey(typePair.Key)) result[idPair.Key].Add(typePair.Key, new List<EndPoint>()); foreach (var endPoint in typePair.Value) if (!result[idPair.Key][typePair.Key].Contains(endPoint.Key)) result[idPair.Key][typePair.Key].Add(endPoint.Key); } } } return result; #endregion }