mirror of https://github.com/jellyfin/jellyfin.git
Apply review suggestions
This commit is contained in:
parent
a5f16136eb
commit
a5bfeb28aa
|
@ -26,11 +26,6 @@ namespace Jellyfin.Networking.Manager
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly object _initLock;
|
private readonly object _initLock;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// List of all interface MAC addresses.
|
|
||||||
/// </summary>
|
|
||||||
private readonly List<PhysicalAddress> _macAddresses;
|
|
||||||
|
|
||||||
private readonly ILogger<NetworkManager> _logger;
|
private readonly ILogger<NetworkManager> _logger;
|
||||||
|
|
||||||
private readonly IConfigurationManager _configurationManager;
|
private readonly IConfigurationManager _configurationManager;
|
||||||
|
@ -40,30 +35,35 @@ namespace Jellyfin.Networking.Manager
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Holds the published server URLs and the IPs to use them on.
|
/// Holds the published server URLs and the IPs to use them on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly Dictionary<IPData, string> _publishedServerUrls;
|
private IReadOnlyDictionary<IPData, string> _publishedServerUrls;
|
||||||
|
|
||||||
private List<IPNetwork> _remoteAddressFilter;
|
private IReadOnlyList<IPNetwork> _remoteAddressFilter;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to stop "event-racing conditions".
|
/// Used to stop "event-racing conditions".
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool _eventfire;
|
private bool _eventfire;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of all interface MAC addresses.
|
||||||
|
/// </summary>
|
||||||
|
private IReadOnlyList<PhysicalAddress> _macAddresses;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Dictionary containing interface addresses and their subnets.
|
/// Dictionary containing interface addresses and their subnets.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<IPData> _interfaces;
|
private IReadOnlyList<IPData> _interfaces;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unfiltered user defined LAN subnets (<see cref="NetworkConfiguration.LocalNetworkSubnets"/>)
|
/// Unfiltered user defined LAN subnets (<see cref="NetworkConfiguration.LocalNetworkSubnets"/>)
|
||||||
/// or internal interface network subnets if undefined by user.
|
/// or internal interface network subnets if undefined by user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<IPNetwork> _lanSubnets;
|
private IReadOnlyList<IPNetwork> _lanSubnets;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// User defined list of subnets to excluded from the LAN.
|
/// User defined list of subnets to excluded from the LAN.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<IPNetwork> _excludedSubnets;
|
private IReadOnlyList<IPNetwork> _excludedSubnets;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True if this object is disposed.
|
/// True if this object is disposed.
|
||||||
|
@ -127,7 +127,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Published server override list.
|
/// Gets the Published server override list.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Dictionary<IPData, string> PublishedServerUrls => _publishedServerUrls;
|
public IReadOnlyDictionary<IPData, string> PublishedServerUrls => _publishedServerUrls;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -206,8 +206,8 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Refreshing interfaces.");
|
_logger.LogDebug("Refreshing interfaces.");
|
||||||
|
|
||||||
_interfaces.Clear();
|
var interfaces = new List<IPData>();
|
||||||
_macAddresses.Clear();
|
var macAddresses = new List<PhysicalAddress>();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -224,7 +224,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
// Populate MAC list
|
// Populate MAC list
|
||||||
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback && PhysicalAddress.None.Equals(mac))
|
if (adapter.NetworkInterfaceType != NetworkInterfaceType.Loopback && PhysicalAddress.None.Equals(mac))
|
||||||
{
|
{
|
||||||
_macAddresses.Add(mac);
|
macAddresses.Add(mac);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate interface list
|
// Populate interface list
|
||||||
|
@ -236,7 +236,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
interfaceObject.Index = ipProperties.GetIPv4Properties().Index;
|
interfaceObject.Index = ipProperties.GetIPv4Properties().Index;
|
||||||
interfaceObject.Name = adapter.Name;
|
interfaceObject.Name = adapter.Name;
|
||||||
|
|
||||||
_interfaces.Add(interfaceObject);
|
interfaces.Add(interfaceObject);
|
||||||
}
|
}
|
||||||
else if (IsIPv6Enabled && info.Address.AddressFamily == AddressFamily.InterNetworkV6)
|
else if (IsIPv6Enabled && info.Address.AddressFamily == AddressFamily.InterNetworkV6)
|
||||||
{
|
{
|
||||||
|
@ -244,7 +244,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
interfaceObject.Index = ipProperties.GetIPv6Properties().Index;
|
interfaceObject.Index = ipProperties.GetIPv6Properties().Index;
|
||||||
interfaceObject.Name = adapter.Name;
|
interfaceObject.Name = adapter.Name;
|
||||||
|
|
||||||
_interfaces.Add(interfaceObject);
|
interfaces.Add(interfaceObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,23 +265,26 @@ namespace Jellyfin.Networking.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no interfaces are found, fallback to loopback interfaces.
|
// If no interfaces are found, fallback to loopback interfaces.
|
||||||
if (_interfaces.Count == 0)
|
if (interfaces.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No interface information available. Using loopback interface(s).");
|
_logger.LogWarning("No interface information available. Using loopback interface(s).");
|
||||||
|
|
||||||
if (IsIPv4Enabled && !IsIPv6Enabled)
|
if (IsIPv4Enabled && !IsIPv6Enabled)
|
||||||
{
|
{
|
||||||
_interfaces.Add(new IPData(IPAddress.Loopback, new IPNetwork(IPAddress.Loopback, 8), "lo"));
|
interfaces.Add(new IPData(IPAddress.Loopback, new IPNetwork(IPAddress.Loopback, 8), "lo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsIPv4Enabled && IsIPv6Enabled)
|
if (!IsIPv4Enabled && IsIPv6Enabled)
|
||||||
{
|
{
|
||||||
_interfaces.Add(new IPData(IPAddress.IPv6Loopback, new IPNetwork(IPAddress.IPv6Loopback, 128), "lo"));
|
interfaces.Add(new IPData(IPAddress.IPv6Loopback, new IPNetwork(IPAddress.IPv6Loopback, 128), "lo"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Discovered {NumberOfInterfaces} interfaces.", _interfaces.Count);
|
_logger.LogDebug("Discovered {NumberOfInterfaces} interfaces.", interfaces.Count);
|
||||||
_logger.LogDebug("Interfaces addresses: {Addresses}", _interfaces.OrderByDescending(s => s.AddressFamily == AddressFamily.InterNetwork).Select(s => s.Address.ToString()));
|
_logger.LogDebug("Interfaces addresses: {Addresses}", interfaces.OrderByDescending(s => s.AddressFamily == AddressFamily.InterNetwork).Select(s => s.Address.ToString()));
|
||||||
|
|
||||||
|
_macAddresses = macAddresses;
|
||||||
|
_interfaces = interfaces;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,36 +300,37 @@ namespace Jellyfin.Networking.Manager
|
||||||
// Get configuration options
|
// Get configuration options
|
||||||
var subnets = config.LocalNetworkSubnets;
|
var subnets = config.LocalNetworkSubnets;
|
||||||
|
|
||||||
if (!NetworkExtensions.TryParseToSubnets(subnets, out _lanSubnets, false))
|
|
||||||
{
|
|
||||||
_lanSubnets.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NetworkExtensions.TryParseToSubnets(subnets, out _excludedSubnets, true))
|
|
||||||
{
|
|
||||||
_excludedSubnets.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no LAN addresses are specified, all private subnets and Loopback are deemed to be the LAN
|
// If no LAN addresses are specified, all private subnets and Loopback are deemed to be the LAN
|
||||||
if (_lanSubnets.Count == 0)
|
if (!NetworkExtensions.TryParseToSubnets(subnets, out var lanSubnets, false) || lanSubnets.Count == 0)
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
|
_logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
|
||||||
|
|
||||||
|
var fallbackLanSubnets = new List<IPNetwork>();
|
||||||
if (IsIPv6Enabled)
|
if (IsIPv6Enabled)
|
||||||
{
|
{
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.IPv6Loopback, 128)); // RFC 4291 (Loopback)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.IPv6Loopback, 128)); // RFC 4291 (Loopback)
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10)); // RFC 4291 (Site local)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10)); // RFC 4291 (Site local)
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7)); // RFC 4193 (Unique local)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7)); // RFC 4193 (Unique local)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsIPv4Enabled)
|
if (IsIPv4Enabled)
|
||||||
{
|
{
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Loopback, 8)); // RFC 5735 (Loopback)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Loopback, 8)); // RFC 5735 (Loopback)
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8)); // RFC 1918 (private)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8)); // RFC 1918 (private)
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12)); // RFC 1918 (private)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12)); // RFC 1918 (private)
|
||||||
_lanSubnets.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16)); // RFC 1918 (private)
|
fallbackLanSubnets.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16)); // RFC 1918 (private)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lanSubnets = fallbackLanSubnets;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_lanSubnets = lanSubnets;
|
||||||
|
}
|
||||||
|
|
||||||
|
_excludedSubnets = NetworkExtensions.TryParseToSubnets(subnets, out var excludedSubnets, true)
|
||||||
|
? excludedSubnets
|
||||||
|
: new List<IPNetwork>();
|
||||||
|
|
||||||
_logger.LogInformation("Defined LAN addresses: {0}", _lanSubnets.Select(s => s.Prefix + "/" + s.PrefixLength));
|
_logger.LogInformation("Defined LAN addresses: {0}", _lanSubnets.Select(s => s.Prefix + "/" + s.PrefixLength));
|
||||||
_logger.LogInformation("Defined LAN exclusions: {0}", _excludedSubnets.Select(s => s.Prefix + "/" + s.PrefixLength));
|
_logger.LogInformation("Defined LAN exclusions: {0}", _excludedSubnets.Select(s => s.Prefix + "/" + s.PrefixLength));
|
||||||
|
@ -342,26 +346,27 @@ namespace Jellyfin.Networking.Manager
|
||||||
lock (_initLock)
|
lock (_initLock)
|
||||||
{
|
{
|
||||||
// Respect explicit bind addresses
|
// Respect explicit bind addresses
|
||||||
|
var interfaces = _interfaces.ToList();
|
||||||
var localNetworkAddresses = config.LocalNetworkAddresses;
|
var localNetworkAddresses = config.LocalNetworkAddresses;
|
||||||
if (localNetworkAddresses.Length > 0 && !string.IsNullOrWhiteSpace(localNetworkAddresses[0]))
|
if (localNetworkAddresses.Length > 0 && !string.IsNullOrWhiteSpace(localNetworkAddresses[0]))
|
||||||
{
|
{
|
||||||
var bindAddresses = localNetworkAddresses.Select(p => NetworkExtensions.TryParseToSubnet(p, out var network)
|
var bindAddresses = localNetworkAddresses.Select(p => NetworkExtensions.TryParseToSubnet(p, out var network)
|
||||||
? network.Prefix
|
? network.Prefix
|
||||||
: (_interfaces.Where(x => x.Name.Equals(p, StringComparison.OrdinalIgnoreCase))
|
: (interfaces.Where(x => x.Name.Equals(p, StringComparison.OrdinalIgnoreCase))
|
||||||
.Select(x => x.Address)
|
.Select(x => x.Address)
|
||||||
.FirstOrDefault() ?? IPAddress.None))
|
.FirstOrDefault() ?? IPAddress.None))
|
||||||
.Where(x => x != IPAddress.None)
|
.Where(x => x != IPAddress.None)
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
_interfaces = _interfaces.Where(x => bindAddresses.Contains(x.Address)).ToList();
|
interfaces = interfaces.Where(x => bindAddresses.Contains(x.Address)).ToList();
|
||||||
|
|
||||||
if (bindAddresses.Contains(IPAddress.Loopback))
|
if (bindAddresses.Contains(IPAddress.Loopback))
|
||||||
{
|
{
|
||||||
_interfaces.Add(new IPData(IPAddress.Loopback, new IPNetwork(IPAddress.Loopback, 8), "lo"));
|
interfaces.Add(new IPData(IPAddress.Loopback, new IPNetwork(IPAddress.Loopback, 8), "lo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bindAddresses.Contains(IPAddress.IPv6Loopback))
|
if (bindAddresses.Contains(IPAddress.IPv6Loopback))
|
||||||
{
|
{
|
||||||
_interfaces.Add(new IPData(IPAddress.IPv6Loopback, new IPNetwork(IPAddress.IPv6Loopback, 128), "lo"));
|
interfaces.Add(new IPData(IPAddress.IPv6Loopback, new IPNetwork(IPAddress.IPv6Loopback, 128), "lo"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +382,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
foreach (var virtualInterfacePrefix in virtualInterfacePrefixes)
|
foreach (var virtualInterfacePrefix in virtualInterfacePrefixes)
|
||||||
{
|
{
|
||||||
_interfaces.RemoveAll(x => x.Name.StartsWith(virtualInterfacePrefix, StringComparison.OrdinalIgnoreCase));
|
interfaces.RemoveAll(x => x.Name.StartsWith(virtualInterfacePrefix, StringComparison.OrdinalIgnoreCase));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -385,16 +390,17 @@ namespace Jellyfin.Networking.Manager
|
||||||
// Remove all IPv4 interfaces if IPv4 is disabled
|
// Remove all IPv4 interfaces if IPv4 is disabled
|
||||||
if (!IsIPv4Enabled)
|
if (!IsIPv4Enabled)
|
||||||
{
|
{
|
||||||
_interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
|
interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all IPv6 interfaces if IPv6 is disabled
|
// Remove all IPv6 interfaces if IPv6 is disabled
|
||||||
if (!IsIPv6Enabled)
|
if (!IsIPv6Enabled)
|
||||||
{
|
{
|
||||||
_interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);
|
interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Using bind addresses: {0}", _interfaces.OrderByDescending(x => x.AddressFamily == AddressFamily.InterNetwork).Select(x => x.Address));
|
_logger.LogInformation("Using bind addresses: {0}", interfaces.OrderByDescending(x => x.AddressFamily == AddressFamily.InterNetwork).Select(x => x.Address));
|
||||||
|
_interfaces = interfaces;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,10 +416,11 @@ namespace Jellyfin.Networking.Manager
|
||||||
if (remoteIPFilter.Any() && !string.IsNullOrWhiteSpace(remoteIPFilter.First()))
|
if (remoteIPFilter.Any() && !string.IsNullOrWhiteSpace(remoteIPFilter.First()))
|
||||||
{
|
{
|
||||||
// Parse all IPs with netmask to a subnet
|
// Parse all IPs with netmask to a subnet
|
||||||
|
var remoteAddressFilter = new List<IPNetwork>();
|
||||||
var remoteFilteredSubnets = remoteIPFilter.Where(x => x.Contains('/', StringComparison.OrdinalIgnoreCase)).ToArray();
|
var remoteFilteredSubnets = remoteIPFilter.Where(x => x.Contains('/', StringComparison.OrdinalIgnoreCase)).ToArray();
|
||||||
if (!NetworkExtensions.TryParseToSubnets(remoteFilteredSubnets, out _remoteAddressFilter, false))
|
if (NetworkExtensions.TryParseToSubnets(remoteFilteredSubnets, out var remoteAddressFilterResult, false))
|
||||||
{
|
{
|
||||||
_remoteAddressFilter.Clear();
|
remoteAddressFilter = remoteAddressFilterResult.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse everything else as an IP and construct subnet with a single IP
|
// Parse everything else as an IP and construct subnet with a single IP
|
||||||
|
@ -422,9 +429,11 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
if (IPAddress.TryParse(ip, out var ipp))
|
if (IPAddress.TryParse(ip, out var ipp))
|
||||||
{
|
{
|
||||||
_remoteAddressFilter.Add(new IPNetwork(ipp, ipp.AddressFamily == AddressFamily.InterNetwork ? 32 : 128));
|
remoteAddressFilter.Add(new IPNetwork(ipp, ipp.AddressFamily == AddressFamily.InterNetwork ? 32 : 128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_remoteAddressFilter = remoteAddressFilter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -440,8 +449,8 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
lock (_initLock)
|
lock (_initLock)
|
||||||
{
|
{
|
||||||
_publishedServerUrls.Clear();
|
var publishedServerUrls = new Dictionary<IPData, string>();
|
||||||
string[] overrides = config.PublishedServerUriBySubnet;
|
var overrides = config.PublishedServerUriBySubnet;
|
||||||
|
|
||||||
foreach (var entry in overrides)
|
foreach (var entry in overrides)
|
||||||
{
|
{
|
||||||
|
@ -456,31 +465,31 @@ namespace Jellyfin.Networking.Manager
|
||||||
var identifier = parts[0];
|
var identifier = parts[0];
|
||||||
if (string.Equals(identifier, "all", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(identifier, "all", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_publishedServerUrls[new IPData(IPAddress.Broadcast, null)] = replacement;
|
publishedServerUrls[new IPData(IPAddress.Broadcast, null)] = replacement;
|
||||||
}
|
}
|
||||||
else if (string.Equals(identifier, "external", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(identifier, "external", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_publishedServerUrls[new IPData(IPAddress.Any, new IPNetwork(IPAddress.Any, 0))] = replacement;
|
publishedServerUrls[new IPData(IPAddress.Any, new IPNetwork(IPAddress.Any, 0))] = replacement;
|
||||||
_publishedServerUrls[new IPData(IPAddress.IPv6Any, new IPNetwork(IPAddress.IPv6Any, 0))] = replacement;
|
publishedServerUrls[new IPData(IPAddress.IPv6Any, new IPNetwork(IPAddress.IPv6Any, 0))] = replacement;
|
||||||
}
|
}
|
||||||
else if (string.Equals(identifier, "internal", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(identifier, "internal", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
foreach (var lan in _lanSubnets)
|
foreach (var lan in _lanSubnets)
|
||||||
{
|
{
|
||||||
var lanPrefix = lan.Prefix;
|
var lanPrefix = lan.Prefix;
|
||||||
_publishedServerUrls[new IPData(lanPrefix, new IPNetwork(lanPrefix, lan.PrefixLength))] = replacement;
|
publishedServerUrls[new IPData(lanPrefix, new IPNetwork(lanPrefix, lan.PrefixLength))] = replacement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (NetworkExtensions.TryParseToSubnet(identifier, out var result) && result is not null)
|
else if (NetworkExtensions.TryParseToSubnet(identifier, out var result) && result is not null)
|
||||||
{
|
{
|
||||||
var data = new IPData(result.Prefix, result);
|
var data = new IPData(result.Prefix, result);
|
||||||
_publishedServerUrls[data] = replacement;
|
publishedServerUrls[data] = replacement;
|
||||||
}
|
}
|
||||||
else if (TryParseInterface(identifier, out var ifaces))
|
else if (TryParseInterface(identifier, out var ifaces))
|
||||||
{
|
{
|
||||||
foreach (var iface in ifaces)
|
foreach (var iface in ifaces)
|
||||||
{
|
{
|
||||||
_publishedServerUrls[iface] = replacement;
|
publishedServerUrls[iface] = replacement;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -488,6 +497,8 @@ namespace Jellyfin.Networking.Manager
|
||||||
_logger.LogError("Unable to parse bind override: {Entry}", entry);
|
_logger.LogError("Unable to parse bind override: {Entry}", entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_publishedServerUrls = publishedServerUrls;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,6 +531,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
// Format is <IPAddress>,<Index>,<Name>: <next interface>. Set index to -ve to simulate a gateway.
|
// Format is <IPAddress>,<Index>,<Name>: <next interface>. Set index to -ve to simulate a gateway.
|
||||||
var interfaceList = MockNetworkSettings.Split('|');
|
var interfaceList = MockNetworkSettings.Split('|');
|
||||||
|
var interfaces = new List<IPData>();
|
||||||
foreach (var details in interfaceList)
|
foreach (var details in interfaceList)
|
||||||
{
|
{
|
||||||
var parts = details.Split(',');
|
var parts = details.Split(',');
|
||||||
|
@ -531,7 +543,7 @@ namespace Jellyfin.Networking.Manager
|
||||||
{
|
{
|
||||||
var data = new IPData(address, subnet, parts[2]);
|
var data = new IPData(address, subnet, parts[2]);
|
||||||
data.Index = index;
|
data.Index = index;
|
||||||
_interfaces.Add(data);
|
interfaces.Add(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -539,6 +551,8 @@ namespace Jellyfin.Networking.Manager
|
||||||
_logger.LogWarning("Could not parse mock interface settings: {Part}", details);
|
_logger.LogWarning("Could not parse mock interface settings: {Part}", details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_interfaces = interfaces;
|
||||||
}
|
}
|
||||||
|
|
||||||
EnforceBindSettings(config);
|
EnforceBindSettings(config);
|
||||||
|
@ -565,11 +579,12 @@ namespace Jellyfin.Networking.Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public bool TryParseInterface(string intf, out List<IPData> result)
|
public bool TryParseInterface(string intf, out IReadOnlyList<IPData> result)
|
||||||
{
|
{
|
||||||
result = new List<IPData>();
|
var resultList = new List<IPData>();
|
||||||
if (string.IsNullOrEmpty(intf) || _interfaces is null)
|
if (string.IsNullOrEmpty(intf) || _interfaces is null)
|
||||||
{
|
{
|
||||||
|
result = resultList.AsReadOnly();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,13 +600,15 @@ namespace Jellyfin.Networking.Manager
|
||||||
if ((IsIPv4Enabled && iface.Address.AddressFamily == AddressFamily.InterNetwork)
|
if ((IsIPv4Enabled && iface.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
|| (IsIPv6Enabled && iface.Address.AddressFamily == AddressFamily.InterNetworkV6))
|
|| (IsIPv6Enabled && iface.Address.AddressFamily == AddressFamily.InterNetworkV6))
|
||||||
{
|
{
|
||||||
result.Add(iface);
|
resultList.Add(iface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = resultList.AsReadOnly();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = resultList.AsReadOnly();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Calculates the list of interfaces to use for Kestrel.
|
/// Calculates the list of interfaces to use for Kestrel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>A List{IPData} object containing all the interfaces to bind.
|
/// <returns>A IReadOnlyList{IPData} object containing all the interfaces to bind.
|
||||||
/// If all the interfaces are specified, and none are excluded, it returns zero items
|
/// If all the interfaces are specified, and none are excluded, it returns zero items
|
||||||
/// to represent any address.</returns>
|
/// to represent any address.</returns>
|
||||||
/// <param name="individualInterfaces">When false, return <see cref="IPAddress.Any"/> or <see cref="IPAddress.IPv6Any"/> for all interfaces.</param>
|
/// <param name="individualInterfaces">When false, return <see cref="IPAddress.Any"/> or <see cref="IPAddress.IPv6Any"/> for all interfaces.</param>
|
||||||
|
@ -39,7 +39,7 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list containing the loopback interfaces.
|
/// Returns a list containing the loopback interfaces.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>List{IPData}.</returns>
|
/// <returns>IReadOnlyList{IPData}.</returns>
|
||||||
IReadOnlyList<IPData> GetLoopbacks();
|
IReadOnlyList<IPData> GetLoopbacks();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -120,7 +120,7 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <param name="intf">Interface name.</param>
|
/// <param name="intf">Interface name.</param>
|
||||||
/// <param name="result">Resulting object's IP addresses, if successful.</param>
|
/// <param name="result">Resulting object's IP addresses, if successful.</param>
|
||||||
/// <returns>Success of the operation.</returns>
|
/// <returns>Success of the operation.</returns>
|
||||||
bool TryParseInterface(string intf, out List<IPData> result);
|
bool TryParseInterface(string intf, out IReadOnlyList<IPData> result);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns all internal (LAN) bind interface addresses.
|
/// Returns all internal (LAN) bind interface addresses.
|
||||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Jellyfin.Extensions;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
|
||||||
namespace MediaBrowser.Common.Net
|
namespace MediaBrowser.Common.Net
|
||||||
|
@ -193,20 +194,15 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <param name="result">An <see cref="IPNetwork"/>.</param>
|
/// <param name="result">An <see cref="IPNetwork"/>.</param>
|
||||||
/// <param name="negated">Boolean signaling if negated or not negated values should be parsed.</param>
|
/// <param name="negated">Boolean signaling if negated or not negated values should be parsed.</param>
|
||||||
/// <returns><c>True</c> if parsing was successful.</returns>
|
/// <returns><c>True</c> if parsing was successful.</returns>
|
||||||
public static bool TryParseToSubnet(string value, out IPNetwork result, bool negated = false)
|
public static bool TryParseToSubnet(ReadOnlySpan<char> value, out IPNetwork result, bool negated = false)
|
||||||
{
|
{
|
||||||
result = new IPNetwork(IPAddress.None, 32);
|
result = new IPNetwork(IPAddress.None, 32);
|
||||||
|
var splitString = value.Trim().Split('/');
|
||||||
if (string.IsNullOrEmpty(value))
|
if (splitString.MoveNext())
|
||||||
{
|
{
|
||||||
return false;
|
var ipBlock = splitString.Current;
|
||||||
}
|
|
||||||
|
|
||||||
var splitString = value.Trim().Split("/");
|
|
||||||
var ipBlock = splitString[0];
|
|
||||||
|
|
||||||
var address = IPAddress.None;
|
var address = IPAddress.None;
|
||||||
if (negated && ipBlock.StartsWith('!') && IPAddress.TryParse(ipBlock[1..], out var tmpAddress))
|
if (negated && ipBlock.StartsWith("!") && IPAddress.TryParse(ipBlock[1..], out var tmpAddress))
|
||||||
{
|
{
|
||||||
address = tmpAddress;
|
address = tmpAddress;
|
||||||
}
|
}
|
||||||
|
@ -215,11 +211,11 @@ namespace MediaBrowser.Common.Net
|
||||||
address = tmpAddress;
|
address = tmpAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (address != IPAddress.None && address is not null)
|
if (address != IPAddress.None)
|
||||||
{
|
{
|
||||||
if (splitString.Length > 1)
|
if (splitString.MoveNext())
|
||||||
{
|
{
|
||||||
var subnetBlock = splitString[1];
|
var subnetBlock = splitString.Current;
|
||||||
if (int.TryParse(subnetBlock, out var netmask))
|
if (int.TryParse(subnetBlock, out var netmask))
|
||||||
{
|
{
|
||||||
result = new IPNetwork(address, netmask);
|
result = new IPNetwork(address, netmask);
|
||||||
|
@ -237,27 +233,25 @@ namespace MediaBrowser.Common.Net
|
||||||
{
|
{
|
||||||
result = new IPNetwork(address, 128);
|
result = new IPNetwork(address, 128);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!result.Prefix.Equals(IPAddress.None))
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to parse a host string.
|
/// Attempts to parse a host span.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="host">Host name to parse.</param>
|
/// <param name="host">Host name to parse.</param>
|
||||||
/// <param name="addresses">Object representing the string, if it has successfully been parsed.</param>
|
/// <param name="addresses">Object representing the span, if it has successfully been parsed.</param>
|
||||||
/// <param name="isIPv4Enabled"><c>true</c> if IPv4 is enabled.</param>
|
/// <param name="isIPv4Enabled"><c>true</c> if IPv4 is enabled.</param>
|
||||||
/// <param name="isIPv6Enabled"><c>true</c> if IPv6 is enabled.</param>
|
/// <param name="isIPv6Enabled"><c>true</c> if IPv6 is enabled.</param>
|
||||||
/// <returns><c>true</c> if the parsing is successful, <c>false</c> if not.</returns>
|
/// <returns><c>true</c> if the parsing is successful, <c>false</c> if not.</returns>
|
||||||
public static bool TryParseHost(string host, [NotNullWhen(true)] out IPAddress[] addresses, bool isIPv4Enabled = true, bool isIPv6Enabled = false)
|
public static bool TryParseHost(ReadOnlySpan<char> host, [NotNullWhen(true)] out IPAddress[] addresses, bool isIPv4Enabled = true, bool isIPv6Enabled = false)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(host))
|
if (host.IsEmpty)
|
||||||
{
|
{
|
||||||
addresses = Array.Empty<IPAddress>();
|
addresses = Array.Empty<IPAddress>();
|
||||||
return false;
|
return false;
|
||||||
|
@ -268,19 +262,24 @@ namespace MediaBrowser.Common.Net
|
||||||
// See if it's an IPv6 with port address e.g. [::1] or [::1]:120.
|
// See if it's an IPv6 with port address e.g. [::1] or [::1]:120.
|
||||||
if (host[0] == '[')
|
if (host[0] == '[')
|
||||||
{
|
{
|
||||||
int i = host.IndexOf(']', StringComparison.Ordinal);
|
int i = host.IndexOf("]", StringComparison.Ordinal);
|
||||||
if (i != -1)
|
if (i != -1)
|
||||||
{
|
{
|
||||||
return TryParseHost(host.Remove(i)[1..], out addresses);
|
return TryParseHost(host[1..(i - 1)], out addresses);
|
||||||
}
|
}
|
||||||
|
|
||||||
addresses = Array.Empty<IPAddress>();
|
addresses = Array.Empty<IPAddress>();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var hosts = host.Split(':');
|
var hosts = new List<string>();
|
||||||
|
var splitSpan = host.Split(':');
|
||||||
|
while (splitSpan.MoveNext())
|
||||||
|
{
|
||||||
|
hosts.Add(splitSpan.Current.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
if (hosts.Length <= 2)
|
if (hosts.Count <= 2)
|
||||||
{
|
{
|
||||||
// Is hostname or hostname:port
|
// Is hostname or hostname:port
|
||||||
if (_fqdnRegex.IsMatch(hosts[0]))
|
if (_fqdnRegex.IsMatch(hosts[0]))
|
||||||
|
@ -315,11 +314,15 @@ namespace MediaBrowser.Common.Net
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hosts.Length <= 9 && IPAddress.TryParse(host.Split('/')[0], out var address)) // 8 octets + port
|
else if (hosts.Count <= 9) // 8 octets + port
|
||||||
|
{
|
||||||
|
splitSpan = host.Split('/');
|
||||||
|
if (splitSpan.MoveNext() && IPAddress.TryParse(splitSpan.Current, out var address))
|
||||||
{
|
{
|
||||||
addresses = new[] { address };
|
addresses = new[] { address };
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addresses = Array.Empty<IPAddress>();
|
addresses = Array.Empty<IPAddress>();
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -428,7 +428,7 @@ namespace Rssdp.Infrastructure
|
||||||
if (result.ReceivedBytes > 0)
|
if (result.ReceivedBytes > 0)
|
||||||
{
|
{
|
||||||
var remoteEndpoint = (IPEndPoint)result.RemoteEndPoint;
|
var remoteEndpoint = (IPEndPoint)result.RemoteEndPoint;
|
||||||
var localEndpointAdapter = _networkManager.GetAllBindInterfaces().Where(a => a.Index == result.PacketInformation.Interface).First();
|
var localEndpointAdapter = _networkManager.GetAllBindInterfaces().First(a => a.Index == result.PacketInformation.Interface);
|
||||||
|
|
||||||
ProcessMessage(
|
ProcessMessage(
|
||||||
UTF8Encoding.UTF8.GetString(receiveBuffer, 0, result.ReceivedBytes),
|
UTF8Encoding.UTF8.GetString(receiveBuffer, 0, result.ReceivedBytes),
|
||||||
|
|
|
@ -203,7 +203,7 @@ namespace Jellyfin.Networking.Tests
|
||||||
using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger<NetworkManager>());
|
using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger<NetworkManager>());
|
||||||
NetworkManager.MockNetworkSettings = string.Empty;
|
NetworkManager.MockNetworkSettings = string.Empty;
|
||||||
|
|
||||||
_ = nm.TryParseInterface(result, out List<IPData>? resultObj);
|
_ = nm.TryParseInterface(result, out IReadOnlyList<IPData>? resultObj);
|
||||||
|
|
||||||
// Check to see if dns resolution is working. If not, skip test.
|
// Check to see if dns resolution is working. If not, skip test.
|
||||||
_ = NetworkExtensions.TryParseHost(source, out var host);
|
_ = NetworkExtensions.TryParseHost(source, out var host);
|
||||||
|
@ -266,7 +266,7 @@ namespace Jellyfin.Networking.Tests
|
||||||
using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger<NetworkManager>());
|
using var nm = new NetworkManager(GetMockConfig(conf), new NullLogger<NetworkManager>());
|
||||||
NetworkManager.MockNetworkSettings = string.Empty;
|
NetworkManager.MockNetworkSettings = string.Empty;
|
||||||
|
|
||||||
if (nm.TryParseInterface(result, out List<IPData>? resultObj) && resultObj is not null)
|
if (nm.TryParseInterface(result, out IReadOnlyList<IPData>? resultObj) && resultObj is not null)
|
||||||
{
|
{
|
||||||
// Parse out IPAddresses so we can do a string comparison (ignore subnet masks).
|
// Parse out IPAddresses so we can do a string comparison (ignore subnet masks).
|
||||||
result = resultObj.First().Address.ToString();
|
result = resultObj.First().Address.ToString();
|
||||||
|
|
Loading…
Reference in New Issue