diff options
| author | BaronGreenback <jimcartlidge@yahoo.co.uk> | 2020-04-29 12:24:01 +0100 |
|---|---|---|
| committer | BaronGreenback <jimcartlidge@yahoo.co.uk> | 2020-04-29 12:24:01 +0100 |
| commit | 8a69300bf55bdf323ceabf68b2888dab3040e883 (patch) | |
| tree | d3932acf371a9bd834db761968642232c2467b9d /Emby.Server.Implementations/Networking/NetworkManager.cs | |
| parent | ebd589aa86abb7bdbc9ab981cb8f4c908f790ac1 (diff) | |
| parent | a0a5512069a56c64d4cf2556f4c04633bda2d120 (diff) | |
Changes styles as suggested by @barronpm
Added addtional comments & source type as per intellisense suggestion
change code as per sonacloud
Diffstat (limited to 'Emby.Server.Implementations/Networking/NetworkManager.cs')
| -rw-r--r-- | Emby.Server.Implementations/Networking/NetworkManager.cs | 477 |
1 files changed, 247 insertions, 230 deletions
diff --git a/Emby.Server.Implementations/Networking/NetworkManager.cs b/Emby.Server.Implementations/Networking/NetworkManager.cs index 5979d1eae..b14b84541 100644 --- a/Emby.Server.Implementations/Networking/NetworkManager.cs +++ b/Emby.Server.Implementations/Networking/NetworkManager.cs @@ -10,16 +10,22 @@ using Microsoft.Extensions.Logging; namespace Emby.Server.Implementations.Networking { + /// <summary> + /// Class to take care of network interface management. + /// </summary> public class NetworkManager : INetworkManager { private readonly ILogger _logger; - - private IPAddress[] _localIpAddresses; private readonly object _localIpAddressSyncLock = new object(); - private readonly object _subnetLookupLock = new object(); - private Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal); + private readonly Dictionary<string, List<string>> _subnetLookup = new Dictionary<string, List<string>>(StringComparer.Ordinal); + private IPAddress[] _localIpAddresses; + private List<PhysicalAddress> _macAddresses; + /// <summary> + /// Initializes a new instance of the <see cref="NetworkManager"/> class. + /// </summary> + /// <param name="logger">Logger to use for messages.</param> public NetworkManager(ILogger<NetworkManager> logger) { _logger = logger; @@ -28,10 +34,232 @@ namespace Emby.Server.Implementations.Networking NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged; } + /// <inheritdoc/> public event EventHandler NetworkChanged; + /// <inheritdoc/> public Func<string[]> LocalSubnetsFn { get; set; } + /// <inheritdoc/> + public IPAddress[] GetLocalIpAddresses() + { + lock (_localIpAddressSyncLock) + { + if (_localIpAddresses == null) + { + var addresses = GetLocalIpAddressesInternal().ToArray(); + + _localIpAddresses = addresses; + } + + return _localIpAddresses; + } + } + + /// <inheritdoc/> + public bool IsInPrivateAddressSpace(string endpoint) + { + return IsInPrivateAddressSpace(endpoint, true); + } + + /// <inheritdoc/> + public bool IsInLocalNetwork(string endpoint) + { + return IsInLocalNetworkInternal(endpoint, true); + } + + /// <inheritdoc/> + public bool IsAddressInSubnets(string addressString, string[] subnets) + { + return IsAddressInSubnets(IPAddress.Parse(addressString), addressString, subnets); + } + + /// <inheritdoc/> + public bool IsInPrivateAddressSpaceAndLocalSubnet(string endpoint) + { + if (endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase)) + { + var endpointFirstPart = endpoint.Split('.')[0]; + + var subnets = GetSubnets(endpointFirstPart); + + foreach (var subnet_Match in subnets) + { + // logger.LogDebug("subnet_Match:" + subnet_Match); + + if (endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + } + + return false; + } + + /// <summary> + /// Gets a random port number that is currently available. + /// </summary> + /// <returns>System.Int32.</returns> + public int GetRandomUnusedTcpPort() + { + var listener = new TcpListener(IPAddress.Any, 0); + listener.Start(); + var port = ((IPEndPoint)listener.LocalEndpoint).Port; + listener.Stop(); + return port; + } + + /// <inheritdoc/> + public int GetRandomUnusedUdpPort() + { + var localEndPoint = new IPEndPoint(IPAddress.Any, 0); + var udpClient = new UdpClient(localEndPoint); + using (udpClient) + { + var port = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; + return port; + } + } + + /// <inheritdoc/> + public List<PhysicalAddress> GetMacAddresses() + { + if (_macAddresses == null) + { + _macAddresses = GetMacAddressesInternal().ToList(); + } + + return _macAddresses; + } + + /// <inheritdoc/> + public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask) + { + IPAddress network1 = GetNetworkAddress(address1, subnetMask); + IPAddress network2 = GetNetworkAddress(address2, subnetMask); + return network1.Equals(network2); + } + + /// <inheritdoc/> + public bool IsAddressInSubnets(IPAddress address, bool excludeInterfaces, bool excludeRFC) + { + byte[] octet = address.GetAddressBytes(); + + if ((octet[0] == 127) || // RFC1122 + (octet[0] == 169 && octet[1] == 254)) // RFC3927 + { + // don't use on loopback or 169 interfaces + return false; + } + + string addressString = address.ToString(); + string excludeAddress = "[" + addressString + "]"; + var subnets = LocalSubnetsFn(); + + // Exclude any addresses if they appear in the LAN list in [ ] + if (Array.IndexOf(subnets, excludeAddress) != -1) + { + return false; + } + + return IsAddressInSubnets(address, addressString, subnets); + } + + /// <inheritdoc/> + public IPAddress GetLocalIpSubnetMask(IPAddress address) + { + NetworkInterface[] interfaces; + + try + { + var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown }; + + interfaces = NetworkInterface.GetAllNetworkInterfaces() + .Where(i => validStatuses.Contains(i.OperationalStatus)) + .ToArray(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error in GetAllNetworkInterfaces"); + return null; + } + + foreach (NetworkInterface ni in interfaces) + { + foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) + { + if (ip.Address.Equals(address) && ip.IPv4Mask != null) + { + return ip.IPv4Mask; + } + } + } + + return null; + } + + /// <summary> + /// Checks if the give address false within the ranges givin in [subnets]. The addresses in subnets can be hosts or subnets in the CIDR format. + /// </summary> + /// <param name="address">IPAddress version of the address.</param> + /// <param name="addressString">The address to check.</param> + /// <param name="subnets">If true, check against addresses in the LAN settings which have [] arroud and return true if it matches the address give in address.</param> + /// <returns><c>false</c>if the address isn't in the subnets, <c>true</c> otherwise.</returns> + private static bool IsAddressInSubnets(IPAddress address, string addressString, string[] subnets) + { + foreach (var subnet in subnets) + { + var normalizedSubnet = subnet.Trim(); + // Is the subnet a host address and does it match the address being passes? + if (string.Equals(normalizedSubnet, addressString, StringComparison.OrdinalIgnoreCase)) + { + return true; + } + + // Parse CIDR subnets and see if address falls within it. + if (normalizedSubnet.Contains('/', StringComparison.Ordinal)) + { + try + { + var ipNetwork = IPNetwork.Parse(normalizedSubnet); + if (ipNetwork.Contains(address)) + { + return true; + } + } + catch + { + // Ignoring - invalid subnet passed encountered. + } + } + } + + return false; + } + + private static Task<IPAddress[]> GetIpAddresses(string hostName) + { + return Dns.GetHostAddressesAsync(hostName); + } + + private static async Task<IEnumerable<IPAddress>> GetLocalIpAddressesFallback() + { + var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false); + + // Reverse them because the last one is usually the correct one + // It's not fool-proof so ultimately the consumer will have to examine them and decide + return host.AddressList + .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6) + .Reverse(); + } + + private static IEnumerable<PhysicalAddress> GetMacAddressesInternal() + => NetworkInterface.GetAllNetworkInterfaces() + .Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback) + .Select(x => x.GetPhysicalAddress()) + .Where(x => x != null && x != PhysicalAddress.None); + private void OnNetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) { _logger.LogDebug("NetworkAvailabilityChanged"); @@ -55,21 +283,6 @@ namespace Emby.Server.Implementations.Networking NetworkChanged?.Invoke(this, EventArgs.Empty); } - public IPAddress[] GetLocalIpAddresses() - { - lock (_localIpAddressSyncLock) - { - if (_localIpAddresses == null) - { - var addresses = GetLocalIpAddressesInternal().ToArray(); - - _localIpAddresses = addresses; - } - - return _localIpAddresses; - } - } - private List<IPAddress> GetLocalIpAddressesInternal() { var list = GetIPsDefault().ToList(); @@ -89,6 +302,7 @@ namespace Emby.Server.Implementations.Networking { continue; } + if (Array.IndexOf(subnets, "[" + i.ToString() + "]") == -1) { listClone.Add(i); @@ -103,12 +317,7 @@ namespace Emby.Server.Implementations.Networking .ToList(); } - public bool IsInPrivateAddressSpace(string endpoint) - { - return IsInPrivateAddressSpace(endpoint, true); - } - - // checks if the address in endpoint is an RFC1918, RFC1122, or RFC3927 address + // Checks if the address in endpoint is an RFC1918, RFC1122, or RFC3927 address private bool IsInPrivateAddressSpace(string endpoint, bool checkSubnets) { if (string.Equals(endpoint, "::1", StringComparison.OrdinalIgnoreCase)) @@ -116,12 +325,12 @@ namespace Emby.Server.Implementations.Networking return true; } - // ipv6 + // IPV6 if (endpoint.Split('.').Length > 4) { // Handle ipv4 mapped to ipv6 var originalEndpoint = endpoint; - endpoint = endpoint.Replace("::ffff:", string.Empty); + endpoint = endpoint.Replace("::ffff:", string.Empty, StringComparison.OrdinalIgnoreCase); if (string.Equals(endpoint, originalEndpoint, StringComparison.OrdinalIgnoreCase)) { @@ -131,27 +340,20 @@ namespace Emby.Server.Implementations.Networking // Private address space: - if (endpoint.ToLower() == "localhost") + if (string.Equals(endpoint, "localhost", StringComparison.OrdinalIgnoreCase)) { return true; } - try - { - byte[] octet = IPAddress.Parse(endpoint).GetAddressBytes(); + byte[] octet = IPAddress.Parse(endpoint).GetAddressBytes(); - if ((octet[0] == 10) || - (octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918 - (octet[0] == 192 && octet[1] == 168) || // RFC1918 - (octet[0] == 127) || // RFC1122 - (octet[0] == 169 && octet[1] == 254)) // RFC3927 - { - return false; - } - } - catch + if ((octet[0] == 10) || + (octet[0] == 172 && (octet[1] >= 16 && octet[1] <= 31)) || // RFC1918 + (octet[0] == 192 && octet[1] == 168) || // RFC1918 + (octet[0] == 127) || // RFC1122 + (octet[0] == 169 && octet[1] == 254)) // RFC3927 { - + return false; } if (checkSubnets && IsInPrivateAddressSpaceAndLocalSubnet(endpoint)) @@ -162,29 +364,7 @@ namespace Emby.Server.Implementations.Networking return false; } - public bool IsInPrivateAddressSpaceAndLocalSubnet(string endpoint) - { - if (endpoint.StartsWith("10.", StringComparison.OrdinalIgnoreCase)) - { - var endpointFirstPart = endpoint.Split('.')[0]; - - var subnets = GetSubnets(endpointFirstPart); - - foreach (var subnet_Match in subnets) - { - //logger.LogDebug("subnet_Match:" + subnet_Match); - - if (endpoint.StartsWith(subnet_Match + ".", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - } - } - - return false; - } - - // Gives a list of possible subnets from the system whose interface ip starts with endpointFirstPart + // Gives a list of possible subnets from the system whose interface ip starts with endpointFirstPart private List<string> GetSubnets(string endpointFirstPart) { lock (_subnetLookupLock) @@ -230,74 +410,6 @@ namespace Emby.Server.Implementations.Networking } } - public bool IsInLocalNetwork(string endpoint) - { - return IsInLocalNetworkInternal(endpoint, true); - } - - public bool IsAddressInSubnets(string addressString, string[] subnets) - { - return IsAddressInSubnets(IPAddress.Parse(addressString), addressString, subnets); - } - - // returns true if address is in the LAN list in the config file - // always returns false if address has been excluded from the LAN if excludeInterfaces is true - // and excludes RFC addresses if excludeRFC is true - public bool IsAddressInSubnets(IPAddress address, bool excludeInterfaces, bool excludeRFC) - { - byte[] octet = address.GetAddressBytes(); - - if ((octet[0] == 127) || // RFC1122 - (octet[0] == 169 && octet[1] == 254)) // RFC3927 - { - // don't use on loopback or 169 interfaces - return false; - } - - string addressString = address.ToString(); - string excludeAddress = "[" + addressString + "]"; - var subnets = LocalSubnetsFn(); - - // Exclude any addresses if they appear in the LAN list in [ ] - if (Array.IndexOf(subnets, excludeAddress) != -1) - { - return false; - } - return IsAddressInSubnets(address, addressString, subnets); - } - - // Checks to see if address/addressString (same but different type) falls within subnets[] - private static bool IsAddressInSubnets(IPAddress address, string addressString, string[] subnets) - { - foreach (var subnet in subnets) - { - var normalizedSubnet = subnet.Trim(); - // is the subnet a host address and does it match the address being passes? - if (string.Equals(normalizedSubnet, addressString, StringComparison.OrdinalIgnoreCase)) - { - return true; - } - // parse CIDR subnets and see if address falls within it. - if (normalizedSubnet.Contains('/', StringComparison.Ordinal)) - { - try - { - var ipNetwork = IPNetwork.Parse(normalizedSubnet); - if (ipNetwork.Contains(address)) - { - return true; - } - } - catch - { - // Ignoring - invalid subnet passed encountered. - } - } - } - - return false; - } - private bool IsInLocalNetworkInternal(string endpoint, bool resolveHost) { if (string.IsNullOrEmpty(endpoint)) @@ -315,7 +427,7 @@ namespace Emby.Server.Implementations.Networking var localSubnets = localSubnetsFn(); foreach (var subnet in localSubnets) { - // only validate if there's at least one valid entry + // Only validate if there's at least one valid entry. if (!string.IsNullOrWhiteSpace(subnet)) { return IsAddressInSubnets(address, addressString, localSubnets) || IsInPrivateAddressSpace(addressString, false); @@ -372,7 +484,7 @@ namespace Emby.Server.Implementations.Networking } catch (InvalidOperationException) { - // Can happen with reverse proxy or IIS url rewriting + // Can happen with reverse proxy or IIS url rewriting? } catch (Exception ex) { @@ -384,11 +496,6 @@ namespace Emby.Server.Implementations.Networking return false; } - private static Task<IPAddress[]> GetIpAddresses(string hostName) - { - return Dns.GetHostAddressesAsync(hostName); - } - private IEnumerable<IPAddress> GetIPsDefault() { IEnumerable<NetworkInterface> interfaces; @@ -418,64 +525,6 @@ namespace Emby.Server.Implementations.Networking .Select(x => x.First()); } - private static async Task<IEnumerable<IPAddress>> GetLocalIpAddressesFallback() - { - var host = await Dns.GetHostEntryAsync(Dns.GetHostName()).ConfigureAwait(false); - - // Reverse them because the last one is usually the correct one - // It's not fool-proof so ultimately the consumer will have to examine them and decide - return host.AddressList - .Where(i => i.AddressFamily == AddressFamily.InterNetwork || i.AddressFamily == AddressFamily.InterNetworkV6) - .Reverse(); - } - - /// <summary> - /// Gets a random port number that is currently available - /// </summary> - /// <returns>System.Int32.</returns> - public int GetRandomUnusedTcpPort() - { - var listener = new TcpListener(IPAddress.Any, 0); - listener.Start(); - var port = ((IPEndPoint)listener.LocalEndpoint).Port; - listener.Stop(); - return port; - } - - public int GetRandomUnusedUdpPort() - { - var localEndPoint = new IPEndPoint(IPAddress.Any, 0); - using (var udpClient = new UdpClient(localEndPoint)) - { - var port = ((IPEndPoint)udpClient.Client.LocalEndPoint).Port; - return port; - } - } - - private List<PhysicalAddress> _macAddresses; - public List<PhysicalAddress> GetMacAddresses() - { - if (_macAddresses == null) - { - _macAddresses = GetMacAddressesInternal().ToList(); - } - - return _macAddresses; - } - - private static IEnumerable<PhysicalAddress> GetMacAddressesInternal() - => NetworkInterface.GetAllNetworkInterfaces() - .Where(i => i.NetworkInterfaceType != NetworkInterfaceType.Loopback) - .Select(x => x.GetPhysicalAddress()) - .Where(x => x != null && x != PhysicalAddress.None); - - public bool IsInSameSubnet(IPAddress address1, IPAddress address2, IPAddress subnetMask) - { - IPAddress network1 = GetNetworkAddress(address1, subnetMask); - IPAddress network2 = GetNetworkAddress(address2, subnetMask); - return network1.Equals(network2); - } - private IPAddress GetNetworkAddress(IPAddress address, IPAddress subnetMask) { byte[] ipAdressBytes = address.GetAddressBytes(); @@ -494,37 +543,5 @@ namespace Emby.Server.Implementations.Networking return new IPAddress(broadcastAddress); } - - public IPAddress GetLocalIpSubnetMask(IPAddress address) - { - NetworkInterface[] interfaces; - - try - { - var validStatuses = new[] { OperationalStatus.Up, OperationalStatus.Unknown }; - - interfaces = NetworkInterface.GetAllNetworkInterfaces() - .Where(i => validStatuses.Contains(i.OperationalStatus)) - .ToArray(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in GetAllNetworkInterfaces"); - return null; - } - - foreach (NetworkInterface ni in interfaces) - { - foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses) - { - if (ip.Address.Equals(address) && ip.IPv4Mask != null) - { - return ip.IPv4Mask; - } - } - } - - return null; - } } } |
