Fix host and port handling for published server URI overrides
This commit is contained in:
@@ -965,8 +965,9 @@ namespace Emby.Server.Implementations
|
||||
/// <inheritdoc/>
|
||||
public string GetLocalApiUrl(string hostname, string scheme = null, int? port = null)
|
||||
{
|
||||
// If the smartAPI doesn't start with http then treat it as a host or ip.
|
||||
if (hostname.StartsWith("http", StringComparison.OrdinalIgnoreCase))
|
||||
// If the smartAPI isn't already a complete URL then treat it as a host or ip.
|
||||
if (hostname.StartsWith("http://", StringComparison.OrdinalIgnoreCase)
|
||||
|| hostname.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return hostname.TrimEnd('/');
|
||||
}
|
||||
|
||||
@@ -851,7 +851,7 @@ public class NetworkManager : INetworkManager, IDisposable
|
||||
bool isExternal = !IsInLocalNetwork(source);
|
||||
_logger.LogDebug("Trying to get bind address for source {Source} - External: {IsExternal}", source, isExternal);
|
||||
|
||||
if (!skipOverrides && MatchesPublishedServerUrl(source, isExternal, out result))
|
||||
if (!skipOverrides && MatchesPublishedServerUrl(source, isExternal, out result, out port))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
@@ -1017,11 +1017,12 @@ public class NetworkManager : INetworkManager, IDisposable
|
||||
/// <param name="source">IP source address to use.</param>
|
||||
/// <param name="isInExternalSubnet">True if the source is in an external subnet.</param>
|
||||
/// <param name="bindPreference">The published server URL that matches the source address.</param>
|
||||
/// <param name="port">The explicit port parsed from the override, if any.</param>
|
||||
/// <returns><c>true</c> if a match is found, <c>false</c> otherwise.</returns>
|
||||
private bool MatchesPublishedServerUrl(IPAddress source, bool isInExternalSubnet, out string bindPreference)
|
||||
private bool MatchesPublishedServerUrl(IPAddress source, bool isInExternalSubnet, out string bindPreference, out int? port)
|
||||
{
|
||||
bindPreference = string.Empty;
|
||||
int? port = null;
|
||||
port = null;
|
||||
|
||||
// Only consider subnets including the source IP, preferring specific overrides
|
||||
List<PublishedServerUriOverride> validPublishedServerUrls;
|
||||
@@ -1063,24 +1064,42 @@ public class NetworkManager : INetworkManager, IDisposable
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle override specifying port
|
||||
var parts = bindPreference.Split(':');
|
||||
if (parts.Length > 1)
|
||||
// Handle override specifying an explicit port.
|
||||
(bindPreference, port) = ParseHostAndPort(bindPreference);
|
||||
|
||||
if (port.HasValue)
|
||||
{
|
||||
if (int.TryParse(parts[1], out int p))
|
||||
{
|
||||
bindPreference = parts[0];
|
||||
port = p;
|
||||
_logger.LogDebug("{Source}: Matching bind address override found: {Address}:{Port}", source, bindPreference, port);
|
||||
return true;
|
||||
}
|
||||
_logger.LogDebug("{Source}: Matching bind address override found: {Address}:{Port}", source, bindPreference, port);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug("{Source}: Matching bind address override found: {Address}", source, bindPreference);
|
||||
}
|
||||
|
||||
_logger.LogDebug("{Source}: Matching bind address override found: {Address}", source, bindPreference);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits a published server URL override into its host and explicit port, if any.
|
||||
/// Full URLs (containing "://") are returned whole, with any port left embedded.
|
||||
/// </summary>
|
||||
/// <param name="value">The override value, e.g. "host:port", "[::1]:port", or a full URL.</param>
|
||||
/// <returns>The parsed host (or the original value if not split) and the explicit port, if any.</returns>
|
||||
private static (string Host, int? Port) ParseHostAndPort(string value)
|
||||
{
|
||||
if (value.Contains("://", StringComparison.Ordinal))
|
||||
{
|
||||
return (value, null);
|
||||
}
|
||||
|
||||
if (Uri.TryCreate("any://" + value, UriKind.Absolute, out var parsed) && parsed.Port != -1)
|
||||
{
|
||||
return (parsed.DnsSafeHost, parsed.Port);
|
||||
}
|
||||
|
||||
return (value, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to match the source against the user defined bind interfaces.
|
||||
/// </summary>
|
||||
|
||||
@@ -493,5 +493,39 @@ namespace Jellyfin.Networking.Tests
|
||||
|
||||
Assert.Equal(result, interfaceToUse);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Internal override with an explicit port.
|
||||
[InlineData("192.168.1.1", "192.168.1.0/24=internal.jellyfin:8097", "internal.jellyfin", 8097)]
|
||||
// External/all override with an explicit port.
|
||||
[InlineData("8.8.8.8", "all=external.jellyfin:8097", "external.jellyfin", 8097)]
|
||||
// Bracketed IPv6 override with an explicit port.
|
||||
[InlineData("8.8.8.8", "all=[fd00:1234::1]:8097", "fd00:1234::1", 8097)]
|
||||
// Bare IPv6 override without a port - must remain whole, not mangled by the extra colons.
|
||||
[InlineData("8.8.8.8", "all=fd00:1234::1", "fd00:1234::1", null)]
|
||||
// Full HTTPS URL override with an explicit port - the URL stays whole, port stays embedded.
|
||||
[InlineData("8.8.8.8", "all=https://secure.jellyfin.org:8920", "https://secure.jellyfin.org:8920", null)]
|
||||
// Hostname beginning with "http" is a hostname, not a URL scheme.
|
||||
[InlineData("8.8.8.8", "all=http-proxy.lan:8097", "http-proxy.lan", 8097)]
|
||||
public void GetBindAddress_PublishedServerOverride_ParsesHostAndPort(string source, string publishedServers, string expectedHost, int? expectedPort)
|
||||
{
|
||||
var conf = new NetworkConfiguration
|
||||
{
|
||||
LocalNetworkSubnets = new[] { "192.168.1.0/24" },
|
||||
LocalNetworkAddresses = new[] { "eth16", "eth11" },
|
||||
EnableIPv4 = true,
|
||||
PublishedServerUriBySubnet = new[] { publishedServers }
|
||||
};
|
||||
|
||||
NetworkManager.MockNetworkSettings = "192.168.1.208/24,-16,eth16|200.200.200.200/24,11,eth11";
|
||||
var startupConf = new Mock<IConfiguration>();
|
||||
using var nm = new NetworkManager(NetworkParseTests.GetMockConfig(conf), startupConf.Object, new NullLogger<NetworkManager>());
|
||||
NetworkManager.MockNetworkSettings = string.Empty;
|
||||
|
||||
var intf = nm.GetBindAddress(IPAddress.Parse(source), out int? port);
|
||||
|
||||
Assert.Equal(expectedHost, intf);
|
||||
Assert.Equal(expectedPort, port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user