mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-13 04:06:31 +01:00
Print warning on invalid Subnets in Network/Proxy configuration (#16793)
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Tests / run-tests (macos-latest) (push) Has been cancelled
Tests / run-tests (ubuntu-latest) (push) Has been cancelled
Tests / run-tests (windows-latest) (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Artifact (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Unstable Spec (push) Has been cancelled
OpenAPI Publish / OpenAPI - Publish Stable Spec (push) Has been cancelled
Project Automation / Project board (push) Has been cancelled
Merge Conflict Labeler / Labeling (push) Has been cancelled
Print warning on invalid Subnets in Network/Proxy configuration
This commit is contained in:
@@ -7,6 +7,7 @@ using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace MediaBrowser.Common.Net;
|
||||
|
||||
@@ -166,8 +167,9 @@ public static partial class NetworkUtils
|
||||
/// <param name="values">Input string array to be parsed.</param>
|
||||
/// <param name="result">Collection of <see cref="IPNetwork"/>.</param>
|
||||
/// <param name="negated">Boolean signaling if negated or not negated values should be parsed.</param>
|
||||
/// <param name="logger">Optional logger used to warn about entries that fail to parse.</param>
|
||||
/// <returns><c>True</c> if parsing was successful.</returns>
|
||||
public static bool TryParseToSubnets(string[] values, [NotNullWhen(true)] out IReadOnlyList<IPData>? result, bool negated = false)
|
||||
public static bool TryParseToSubnets(string[] values, [NotNullWhen(true)] out IReadOnlyList<IPData>? result, bool negated = false, ILogger? logger = null)
|
||||
{
|
||||
if (values is null || values.Length == 0)
|
||||
{
|
||||
@@ -182,12 +184,45 @@ public static partial class NetworkUtils
|
||||
{
|
||||
(tmpResult ??= new()).Add(innerResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogInvalidSubnet(logger, values[a]);
|
||||
}
|
||||
}
|
||||
|
||||
result = tmpResult;
|
||||
return result is not null;
|
||||
}
|
||||
|
||||
private static void LogInvalidSubnet(ILogger? logger, string value)
|
||||
{
|
||||
if (logger is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var trimmed = value.AsSpan().Trim();
|
||||
if (trimmed.StartsWith('!'))
|
||||
{
|
||||
trimmed = trimmed[1..];
|
||||
}
|
||||
|
||||
var slash = trimmed.IndexOf('/');
|
||||
if (slash != -1
|
||||
&& trimmed.Contains(':')
|
||||
&& trimmed.IndexOf("::", StringComparison.Ordinal) == -1)
|
||||
{
|
||||
logger.LogWarning(
|
||||
"Invalid IPv6 subnet '{Subnet}': IPv6 prefix-only notation is not supported. Use the full notation including '::' (e.g. '{Example}::/{Prefix}').",
|
||||
value,
|
||||
trimmed[..slash].ToString(),
|
||||
trimmed[(slash + 1)..].ToString());
|
||||
return;
|
||||
}
|
||||
|
||||
logger.LogWarning("Invalid subnet '{Subnet}' will be ignored.", value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try parsing a string into an <see cref="IPData"/>, respecting exclusions.
|
||||
/// Inputs without a subnet mask will be represented as <see cref="IPData"/> with a single IP.
|
||||
|
||||
@@ -316,7 +316,7 @@ public class NetworkManager : INetworkManager, IDisposable
|
||||
var subnets = config.LocalNetworkSubnets;
|
||||
|
||||
// If no LAN addresses are specified, all private subnets and Loopback are deemed to be the LAN
|
||||
if (!NetworkUtils.TryParseToSubnets(subnets, out var lanSubnets, false) || lanSubnets.Count == 0)
|
||||
if (!NetworkUtils.TryParseToSubnets(subnets, out var lanSubnets, false, _logger) || lanSubnets.Count == 0)
|
||||
{
|
||||
_logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
|
||||
|
||||
@@ -343,7 +343,7 @@ public class NetworkManager : INetworkManager, IDisposable
|
||||
_lanSubnets = lanSubnets.Select(x => x.Subnet).ToArray();
|
||||
}
|
||||
|
||||
_excludedSubnets = NetworkUtils.TryParseToSubnets(subnets, out var excludedSubnets, true)
|
||||
_excludedSubnets = NetworkUtils.TryParseToSubnets(subnets, out var excludedSubnets, true, _logger)
|
||||
? excludedSubnets.Select(x => x.Subnet).ToArray()
|
||||
: Array.Empty<IPNetwork>();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using MediaBrowser.Common.Configuration;
|
||||
using MediaBrowser.Common.Net;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
@@ -94,9 +95,46 @@ namespace Jellyfin.Networking.Tests
|
||||
[InlineData("256.128.0.0.0.1")]
|
||||
[InlineData("fd23:184f:2029:0:3139:7386:67d7:d517:1231")]
|
||||
[InlineData("[fd23:184f:2029:0:3139:7386:67d7:d517:1231]")]
|
||||
[InlineData("fd23:184f:2029:0100/56")]
|
||||
public static void TryParseInvalidIPStringsFalse(string address)
|
||||
=> Assert.False(NetworkUtils.TryParseToSubnet(address, out _));
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that <see cref="NetworkUtils.TryParseToSubnets"/> emits a targeted warning
|
||||
/// for IPv6 prefix-only notation and a generic warning for other malformed entries.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TryParseToSubnets_InvalidEntries_LogsWarnings()
|
||||
{
|
||||
var logger = new Mock<ILogger>();
|
||||
|
||||
var values = new[] { "10.0.0.0/8", "fd23:184f:2029:0100/56", "not-an-address" };
|
||||
Assert.True(NetworkUtils.TryParseToSubnets(values, out var result, false, logger.Object));
|
||||
Assert.NotNull(result);
|
||||
Assert.Single(result);
|
||||
|
||||
// IPv6 prefix-only notation should produce a specific, actionable warning.
|
||||
logger.Verify(
|
||||
l => l.Log(
|
||||
LogLevel.Warning,
|
||||
It.IsAny<EventId>(),
|
||||
It.Is<It.IsAnyType>((state, _) => state.ToString()!.Contains("IPv6 prefix-only", StringComparison.Ordinal)
|
||||
&& state.ToString()!.Contains("fd23:184f:2029:0100/56", StringComparison.Ordinal)),
|
||||
It.IsAny<Exception>(),
|
||||
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
|
||||
Times.Once);
|
||||
|
||||
// Other malformed entries should still produce a generic warning.
|
||||
logger.Verify(
|
||||
l => l.Log(
|
||||
LogLevel.Warning,
|
||||
It.IsAny<EventId>(),
|
||||
It.Is<It.IsAnyType>((state, _) => state.ToString()!.Contains("not-an-address", StringComparison.Ordinal)),
|
||||
It.IsAny<Exception>(),
|
||||
It.IsAny<Func<It.IsAnyType, Exception?, string>>()),
|
||||
Times.Once);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if IPv4 address is within a defined subnet.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user