Fixed IP6 host parsing
This commit is contained in:
parent
34e10622c6
commit
053063fd47
|
@ -128,62 +128,62 @@ namespace MediaBrowser.Common.Net
|
||||||
/// <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 TryParse(string host, out IPHost hostObj)
|
public static bool TryParse(string host, out IPHost hostObj)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(host))
|
if (string.IsNullOrWhiteSpace(host))
|
||||||
{
|
{
|
||||||
// See if it's an IPv6 with port address e.g. [::1]:120.
|
hostObj = IPHost.None;
|
||||||
int i = host.IndexOf("]:", StringComparison.OrdinalIgnoreCase);
|
return false;
|
||||||
if (i != -1)
|
}
|
||||||
|
|
||||||
|
// See if it's an IPv6 with port address e.g. [::1] or [::1]:120.
|
||||||
|
int i = host.IndexOf("]", StringComparison.OrdinalIgnoreCase);
|
||||||
|
if (i != -1)
|
||||||
|
{
|
||||||
|
return TryParse(host.Remove(i - 1).TrimStart(' ', '['), out hostObj);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IPNetAddress.TryParse(host, out var netAddress))
|
||||||
|
{
|
||||||
|
// Host name is an ip address, so fake resolve.
|
||||||
|
hostObj = new IPHost(host, netAddress.Address);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it a host, IPv4/6 with/out port?
|
||||||
|
string[] hosts = host.Split(':');
|
||||||
|
|
||||||
|
if (hosts.Length <= 2)
|
||||||
|
{
|
||||||
|
// This is either a hostname: port, or an IP4:port.
|
||||||
|
host = hosts[0];
|
||||||
|
|
||||||
|
if (string.Equals("localhost", host, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
return TryParse(host.Remove(i - 1).TrimStart(' ', '['), out hostObj);
|
hostObj = new IPHost(host);
|
||||||
}
|
return true;
|
||||||
else
|
|
||||||
{
|
|
||||||
// See if it's an IPv6 in [] with no port.
|
|
||||||
i = host.IndexOf(']', StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (i != -1)
|
|
||||||
{
|
|
||||||
return TryParse(host.Remove(i - 1).TrimStart(' ', '['), out hostObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Is it a host or IPv4 with port?
|
|
||||||
string[] hosts = host.Split(':');
|
|
||||||
|
|
||||||
if (hosts.Length > 2)
|
|
||||||
{
|
|
||||||
hostObj = new IPHost(string.Empty, IPAddress.None);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove port from IPv4 if it exists.
|
|
||||||
host = hosts[0];
|
|
||||||
|
|
||||||
if (string.Equals("localhost", host, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
hostObj = new IPHost(host, new IPAddress(Ipv4Loopback));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IPNetAddress.TryParse(host, out IPNetAddress netIP))
|
|
||||||
{
|
|
||||||
// Host name is an ip address, so fake resolve.
|
|
||||||
hostObj = new IPHost(host, netIP.Address);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only thing left is to see if it's a host string.
|
if (IPAddress.TryParse(host, out var netIP))
|
||||||
if (!string.IsNullOrEmpty(host))
|
|
||||||
{
|
{
|
||||||
// Use regular expression as CheckHostName isn't RFC5892 compliant.
|
// Host name is an ip address, so fake resolve.
|
||||||
// Modified from gSkinner's expression at https://stackoverflow.com/questions/11809631/fully-qualified-domain-name-validation
|
hostObj = new IPHost(host, netIP);
|
||||||
Regex re = new Regex(@"^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){0,127}(?![0-9]*$)[a-z0-9-]+\.?)$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
return true;
|
||||||
if (re.Match(host).Success)
|
|
||||||
{
|
|
||||||
hostObj = new IPHost(host);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid host name, as it cannot contain :
|
||||||
|
hostObj = new IPHost(string.Empty, IPAddress.None);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use regular expression as CheckHostName isn't RFC5892 compliant.
|
||||||
|
// Modified from gSkinner's expression at https://stackoverflow.com/questions/11809631/fully-qualified-domain-name-validation
|
||||||
|
Regex re = new Regex(@"^(?!:\/\/)(?=.{1,255}$)((.{1,63}\.){0,127}(?![0-9]*$)[a-z0-9-]+\.?)$", RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||||
|
if (re.Match(host).Success)
|
||||||
|
{
|
||||||
|
hostObj = new IPHost(host);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
hostObj = IPHost.None;
|
hostObj = IPHost.None;
|
||||||
return false;
|
return false;
|
||||||
|
@ -344,10 +344,14 @@ namespace MediaBrowser.Common.Net
|
||||||
{
|
{
|
||||||
output += "Any Address,";
|
output += "Any Address,";
|
||||||
}
|
}
|
||||||
else
|
else if (i.AddressFamily == AddressFamily.InterNetwork)
|
||||||
{
|
{
|
||||||
output += $"{i}/32,";
|
output += $"{i}/32,";
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output += $"{i}/128,";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
output = output[0..^1];
|
output = output[0..^1];
|
||||||
|
|
|
@ -13,34 +13,6 @@ namespace Jellyfin.Networking.Tests
|
||||||
{
|
{
|
||||||
public class NetworkParseTests
|
public class NetworkParseTests
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Tries to identify the string and return an object of that class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="addr">String to parse.</param>
|
|
||||||
/// <param name="result">IPObject to return.</param>
|
|
||||||
/// <returns>True if the value parsed successfully.</returns>
|
|
||||||
private static bool TryParse(string addr, out IPObject result)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(addr))
|
|
||||||
{
|
|
||||||
// Is it an IP address
|
|
||||||
if (IPNetAddress.TryParse(addr, out IPNetAddress nw))
|
|
||||||
{
|
|
||||||
result = nw;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IPHost.TryParse(addr, out IPHost h))
|
|
||||||
{
|
|
||||||
result = h;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = IPNetAddress.None;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IConfigurationManager GetMockConfig(NetworkConfiguration conf)
|
private static IConfigurationManager GetMockConfig(NetworkConfiguration conf)
|
||||||
{
|
{
|
||||||
var configManager = new Mock<IConfigurationManager>
|
var configManager = new Mock<IConfigurationManager>
|
||||||
|
@ -118,11 +90,33 @@ namespace Jellyfin.Networking.Tests
|
||||||
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]:124")]
|
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]:124")]
|
||||||
[InlineData("fe80::7add:12ff:febb:c67b%16")]
|
[InlineData("fe80::7add:12ff:febb:c67b%16")]
|
||||||
[InlineData("[fe80::7add:12ff:febb:c67b%16]:123")]
|
[InlineData("[fe80::7add:12ff:febb:c67b%16]:123")]
|
||||||
|
[InlineData("fe80::7add:12ff:febb:c67b%16:123")]
|
||||||
|
[InlineData("[fe80::7add:12ff:febb:c67b%16]")]
|
||||||
|
[InlineData("192.168.1.2/255.255.255.0")]
|
||||||
|
[InlineData("192.168.1.2/24")]
|
||||||
|
public void ValidHostStrings(string address)
|
||||||
|
{
|
||||||
|
Assert.True(IPHost.TryParse(address, out _));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks IP address formats.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="address"></param>
|
||||||
|
[Theory]
|
||||||
|
[InlineData("127.0.0.1")]
|
||||||
|
[InlineData("fd23:184f:2029:0:3139:7386:67d7:d517")]
|
||||||
|
[InlineData("fd23:184f:2029:0:3139:7386:67d7:d517/56")]
|
||||||
|
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517]")]
|
||||||
|
[InlineData("fe80::7add:12ff:febb:c67b%16")]
|
||||||
|
[InlineData("[fe80::7add:12ff:febb:c67b%16]:123")]
|
||||||
|
[InlineData("fe80::7add:12ff:febb:c67b%16:123")]
|
||||||
|
[InlineData("[fe80::7add:12ff:febb:c67b%16]")]
|
||||||
[InlineData("192.168.1.2/255.255.255.0")]
|
[InlineData("192.168.1.2/255.255.255.0")]
|
||||||
[InlineData("192.168.1.2/24")]
|
[InlineData("192.168.1.2/24")]
|
||||||
public void ValidIPStrings(string address)
|
public void ValidIPStrings(string address)
|
||||||
{
|
{
|
||||||
Assert.True(TryParse(address, out _));
|
Assert.True(IPNetAddress.TryParse(address, out _));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,7 +132,8 @@ namespace Jellyfin.Networking.Tests
|
||||||
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")]
|
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")]
|
||||||
public void InvalidAddressString(string address)
|
public void InvalidAddressString(string address)
|
||||||
{
|
{
|
||||||
Assert.False(TryParse(address, out _));
|
Assert.False(IPNetAddress.TryParse(address, out _));
|
||||||
|
Assert.False(IPHost.TryParse(address, out _));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -172,11 +167,11 @@ namespace Jellyfin.Networking.Tests
|
||||||
"[]")]
|
"[]")]
|
||||||
[InlineData(
|
[InlineData(
|
||||||
"192.158.1.2/16, localhost, fd23:184f:2029:0:3139:7386:67d7:d517, !10.10.10.10",
|
"192.158.1.2/16, localhost, fd23:184f:2029:0:3139:7386:67d7:d517, !10.10.10.10",
|
||||||
"[192.158.1.2/16,127.0.0.1/32,fd23:184f:2029:0:3139:7386:67d7:d517/128]",
|
"[192.158.1.2/16,[127.0.0.1/32,::1/128],fd23:184f:2029:0:3139:7386:67d7:d517/128]",
|
||||||
"[192.158.1.2/16,127.0.0.1/32]",
|
"[192.158.1.2/16,127.0.0.1/32]",
|
||||||
"[10.10.10.10/32]",
|
"[10.10.10.10/32]",
|
||||||
"[10.10.10.10/32]",
|
"[10.10.10.10/32]",
|
||||||
"[192.158.0.0/16,127.0.0.1/32,fd23:184f:2029:0:3139:7386:67d7:d517/128]")]
|
"[192.158.0.0/16,127.0.0.1/32,::1/128,fd23:184f:2029:0:3139:7386:67d7:d517/128]")]
|
||||||
[InlineData("192.158.1.2/255.255.0.0,192.169.1.2/8",
|
[InlineData("192.158.1.2/255.255.0.0,192.169.1.2/8",
|
||||||
"[192.158.1.2/16,192.169.1.2/8]",
|
"[192.158.1.2/16,192.169.1.2/8]",
|
||||||
"[192.158.1.2/16,192.169.1.2/8]",
|
"[192.158.1.2/16,192.169.1.2/8]",
|
||||||
|
@ -333,8 +328,8 @@ namespace Jellyfin.Networking.Tests
|
||||||
|
|
||||||
public void TestSubnetContains(string network, string ip)
|
public void TestSubnetContains(string network, string ip)
|
||||||
{
|
{
|
||||||
Assert.True(TryParse(network, out IPObject? networkObj));
|
Assert.True(IPNetAddress.TryParse(network, out var networkObj));
|
||||||
Assert.True(TryParse(ip, out IPObject? ipObj));
|
Assert.True(IPNetAddress.TryParse(ip, out var ipObj));
|
||||||
Assert.True(networkObj.Contains(ipObj));
|
Assert.True(networkObj.Contains(ipObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,7 +463,7 @@ namespace Jellyfin.Networking.Tests
|
||||||
// User on internal network, no binding specified - so result is the 1st internal.
|
// User on internal network, no binding specified - so result is the 1st internal.
|
||||||
[InlineData("192.168.1.1", "192.168.1.0/24", "", false, "0.0.0.0=http://helloworld.com", "eth16")]
|
[InlineData("192.168.1.1", "192.168.1.0/24", "", false, "0.0.0.0=http://helloworld.com", "eth16")]
|
||||||
|
|
||||||
// User on external network, internal binding only - so asumption is a proxy forward, return external override.
|
// User on external network, internal binding only - so assumption is a proxy forward, return external override.
|
||||||
[InlineData("jellyfin.org", "192.168.1.0/24", "eth16", false, "0.0.0.0=http://helloworld.com", "http://helloworld.com")]
|
[InlineData("jellyfin.org", "192.168.1.0/24", "eth16", false, "0.0.0.0=http://helloworld.com", "http://helloworld.com")]
|
||||||
|
|
||||||
// User on external network, no binding - so result is the 1st external which is overriden.
|
// User on external network, no binding - so result is the 1st external which is overriden.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user