diff options
| author | Joshua M. Boniface <joshua@boniface.me> | 2023-07-03 13:16:21 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-07-03 13:16:21 -0400 |
| commit | 93b400343ebd2ef92e740d804ceaaedb01da30cf (patch) | |
| tree | 0190174ceb0df9c3bcd23647548d80be48425214 /Jellyfin.Server | |
| parent | 44cc3ee44286dd5b3a626df79a8a576ad4a0d34a (diff) | |
| parent | e233a3b074d7696e4c05846aaf04434dafaf4031 (diff) | |
Merge pull request #8147 from Shadowghost/network-rewrite
Diffstat (limited to 'Jellyfin.Server')
7 files changed, 221 insertions, 23 deletions
diff --git a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs index 463ca7321d..b6af9baec3 100644 --- a/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiApplicationBuilderExtensions.cs @@ -63,9 +63,9 @@ namespace Jellyfin.Server.Extensions /// </summary> /// <param name="appBuilder">The application builder.</param> /// <returns>The updated application builder.</returns> - public static IApplicationBuilder UseIpBasedAccessValidation(this IApplicationBuilder appBuilder) + public static IApplicationBuilder UseIPBasedAccessValidation(this IApplicationBuilder appBuilder) { - return appBuilder.UseMiddleware<IpBasedAccessValidationMiddleware>(); + return appBuilder.UseMiddleware<IPBasedAccessValidationMiddleware>(); } /// <summary> diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index 9867c9e47a..ea3c92011f 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -99,7 +99,7 @@ namespace Jellyfin.Server.Extensions } /// <summary> - /// Extension method for adding the jellyfin API to the service collection. + /// Extension method for adding the Jellyfin API to the service collection. /// </summary> /// <param name="serviceCollection">The service collection.</param> /// <param name="pluginAssemblies">An IEnumerable containing all plugin assemblies with API controllers.</param> @@ -260,7 +260,7 @@ namespace Jellyfin.Server.Extensions } /// <summary> - /// Sets up the proxy configuration based on the addresses in <paramref name="allowedProxies"/>. + /// Sets up the proxy configuration based on the addresses/subnets in <paramref name="allowedProxies"/>. /// </summary> /// <param name="config">The <see cref="NetworkConfiguration"/> containing the config settings.</param> /// <param name="allowedProxies">The string array to parse.</param> @@ -269,33 +269,37 @@ namespace Jellyfin.Server.Extensions { for (var i = 0; i < allowedProxies.Length; i++) { - if (IPNetAddress.TryParse(allowedProxies[i], out var addr)) + if (IPAddress.TryParse(allowedProxies[i], out var addr)) { - AddIpAddress(config, options, addr.Address, addr.PrefixLength); + AddIPAddress(config, options, addr, addr.AddressFamily == AddressFamily.InterNetwork ? 32 : 128); } - else if (IPHost.TryParse(allowedProxies[i], out var host)) + else if (NetworkExtensions.TryParseToSubnet(allowedProxies[i], out var subnet)) { - foreach (var address in host.GetAddresses()) + if (subnet != null) { - AddIpAddress(config, options, address, address.AddressFamily == AddressFamily.InterNetwork ? 32 : 128); + AddIPAddress(config, options, subnet.Prefix, subnet.PrefixLength); + } + } + else if (NetworkExtensions.TryParseHost(allowedProxies[i], out var addresses)) + { + foreach (var address in addresses) + { + AddIPAddress(config, options, address, address.AddressFamily == AddressFamily.InterNetwork ? 32 : 128); } } } } - private static void AddIpAddress(NetworkConfiguration config, ForwardedHeadersOptions options, IPAddress addr, int prefixLength) + private static void AddIPAddress(NetworkConfiguration config, ForwardedHeadersOptions options, IPAddress addr, int prefixLength) { - if ((!config.EnableIPV4 && addr.AddressFamily == AddressFamily.InterNetwork) || (!config.EnableIPV6 && addr.AddressFamily == AddressFamily.InterNetworkV6)) + if ((!config.EnableIPv4 && addr.AddressFamily == AddressFamily.InterNetwork) || (!config.EnableIPv6 && addr.AddressFamily == AddressFamily.InterNetworkV6)) { return; } - // In order for dual-mode sockets to be used, IP6 has to be enabled in JF and an interface has to have an IP6 address. - if (addr.AddressFamily == AddressFamily.InterNetwork && config.EnableIPV6) + if (addr.IsIPv4MappedToIPv6) { - // If the server is using dual-mode sockets, IPv4 addresses are supplied in an IPv6 format. - // https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-5.0 . - addr = addr.MapToIPv6(); + addr = addr.MapToIPv4(); } if (prefixLength == 32) diff --git a/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs index 58d3e1b2d9..3cb791b571 100644 --- a/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs +++ b/Jellyfin.Server/Extensions/WebHostBuilderExtensions.cs @@ -39,9 +39,9 @@ public static class WebHostBuilderExtensions var addresses = appHost.NetManager.GetAllBindInterfaces(); bool flagged = false; - foreach (IPObject netAdd in addresses) + foreach (var netAdd in addresses) { - logger.LogInformation("Kestrel listening on {Address}", IPAddress.IPv6Any.Equals(netAdd.Address) ? "All Addresses" : netAdd); + logger.LogInformation("Kestrel is listening on {Address}", IPAddress.IPv6Any.Equals(netAdd.Address) ? "All IPv6 addresses" : netAdd.Address); options.Listen(netAdd.Address, appHost.HttpPort); if (appHost.ListenWithHttps) { diff --git a/Jellyfin.Server/Migrations/MigrationRunner.cs b/Jellyfin.Server/Migrations/MigrationRunner.cs index abfdcd77d5..33c02f41c6 100644 --- a/Jellyfin.Server/Migrations/MigrationRunner.cs +++ b/Jellyfin.Server/Migrations/MigrationRunner.cs @@ -22,7 +22,8 @@ namespace Jellyfin.Server.Migrations private static readonly Type[] _preStartupMigrationTypes = { typeof(PreStartupRoutines.CreateNetworkConfiguration), - typeof(PreStartupRoutines.MigrateMusicBrainzTimeout) + typeof(PreStartupRoutines.MigrateMusicBrainzTimeout), + typeof(PreStartupRoutines.MigrateNetworkConfiguration) }; /// <summary> diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs index 5e601ca847..2c2715526f 100644 --- a/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs +++ b/Jellyfin.Server/Migrations/PreStartupRoutines/CreateNetworkConfiguration.cs @@ -114,9 +114,7 @@ public class CreateNetworkConfiguration : IMigrationRoutine public bool IgnoreVirtualInterfaces { get; set; } = true; - public string VirtualInterfaceNames { get; set; } = "vEthernet*"; - - public bool TrustAllIP6Interfaces { get; set; } + public string[] VirtualInterfaceNames { get; set; } = new string[] { "veth" }; public string[] PublishedServerUriBySubnet { get; set; } = Array.Empty<string>(); diff --git a/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateNetworkConfiguration.cs b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateNetworkConfiguration.cs new file mode 100644 index 0000000000..3b32e60437 --- /dev/null +++ b/Jellyfin.Server/Migrations/PreStartupRoutines/MigrateNetworkConfiguration.cs @@ -0,0 +1,195 @@ +using System; +using System.IO; +using System.Xml; +using System.Xml.Serialization; +using Emby.Server.Implementations; +using Jellyfin.Networking.Configuration; +using Microsoft.Extensions.Logging; + +namespace Jellyfin.Server.Migrations.PreStartupRoutines; + +/// <inheritdoc /> +public class MigrateNetworkConfiguration : IMigrationRoutine +{ + private readonly ServerApplicationPaths _applicationPaths; + private readonly ILogger<MigrateNetworkConfiguration> _logger; + + /// <summary> + /// Initializes a new instance of the <see cref="MigrateNetworkConfiguration"/> class. + /// </summary> + /// <param name="applicationPaths">An instance of <see cref="ServerApplicationPaths"/>.</param> + /// <param name="loggerFactory">An instance of the <see cref="ILoggerFactory"/> interface.</param> + public MigrateNetworkConfiguration(ServerApplicationPaths applicationPaths, ILoggerFactory loggerFactory) + { + _applicationPaths = applicationPaths; + _logger = loggerFactory.CreateLogger<MigrateNetworkConfiguration>(); + } + + /// <inheritdoc /> + public Guid Id => Guid.Parse("4FB5C950-1991-11EE-9B4B-0800200C9A66"); + + /// <inheritdoc /> + public string Name => nameof(MigrateNetworkConfiguration); + + /// <inheritdoc /> + public bool PerformOnNewInstall => false; + + /// <inheritdoc /> + public void Perform() + { + string path = Path.Combine(_applicationPaths.ConfigurationDirectoryPath, "network.xml"); + var oldNetworkConfigSerializer = new XmlSerializer(typeof(OldNetworkConfiguration), new XmlRootAttribute("NetworkConfiguration")); + using var xmlReader = XmlReader.Create(path); + var oldNetworkConfiguration = (OldNetworkConfiguration?)oldNetworkConfigSerializer.Deserialize(xmlReader); + + if (oldNetworkConfiguration is not null) + { + // Migrate network config values to new config schema + var networkConfiguration = new NetworkConfiguration(); + networkConfiguration.AutoDiscovery = oldNetworkConfiguration.AutoDiscovery; + networkConfiguration.BaseUrl = oldNetworkConfiguration.BaseUrl; + networkConfiguration.CertificatePassword = oldNetworkConfiguration.CertificatePassword; + networkConfiguration.CertificatePath = oldNetworkConfiguration.CertificatePath; + networkConfiguration.EnableHttps = oldNetworkConfiguration.EnableHttps; + networkConfiguration.EnableIPv4 = oldNetworkConfiguration.EnableIPV4; + networkConfiguration.EnableIPv6 = oldNetworkConfiguration.EnableIPV6; + networkConfiguration.EnablePublishedServerUriByRequest = oldNetworkConfiguration.EnablePublishedServerUriByRequest; + networkConfiguration.EnableRemoteAccess = oldNetworkConfiguration.EnableRemoteAccess; + networkConfiguration.EnableUPnP = oldNetworkConfiguration.EnableUPnP; + networkConfiguration.IgnoreVirtualInterfaces = oldNetworkConfiguration.IgnoreVirtualInterfaces; + networkConfiguration.InternalHttpPort = oldNetworkConfiguration.HttpServerPortNumber; + networkConfiguration.InternalHttpsPort = oldNetworkConfiguration.HttpsPortNumber; + networkConfiguration.IsRemoteIPFilterBlacklist = oldNetworkConfiguration.IsRemoteIPFilterBlacklist; + networkConfiguration.KnownProxies = oldNetworkConfiguration.KnownProxies; + networkConfiguration.LocalNetworkAddresses = oldNetworkConfiguration.LocalNetworkAddresses; + networkConfiguration.LocalNetworkSubnets = oldNetworkConfiguration.LocalNetworkSubnets; + networkConfiguration.PublicHttpPort = oldNetworkConfiguration.PublicPort; + networkConfiguration.PublicHttpsPort = oldNetworkConfiguration.PublicHttpsPort; + networkConfiguration.PublishedServerUriBySubnet = oldNetworkConfiguration.PublishedServerUriBySubnet; + networkConfiguration.RemoteIPFilter = oldNetworkConfiguration.RemoteIPFilter; + networkConfiguration.RequireHttps = oldNetworkConfiguration.RequireHttps; + + // Migrate old virtual interface name schema + var oldVirtualInterfaceNames = oldNetworkConfiguration.VirtualInterfaceNames; + if (oldVirtualInterfaceNames.Equals("vEthernet*", StringComparison.OrdinalIgnoreCase)) + { + networkConfiguration.VirtualInterfaceNames = new string[] { "veth" }; + } + else + { + networkConfiguration.VirtualInterfaceNames = oldVirtualInterfaceNames.Replace("*", string.Empty, StringComparison.OrdinalIgnoreCase).Split(','); + } + + var networkConfigSerializer = new XmlSerializer(typeof(NetworkConfiguration)); + var xmlWriterSettings = new XmlWriterSettings { Indent = true }; + using var xmlWriter = XmlWriter.Create(path, xmlWriterSettings); + networkConfigSerializer.Serialize(xmlWriter, networkConfiguration); + } + } + +#pragma warning disable + public sealed class OldNetworkConfiguration + { + public const int DefaultHttpPort = 8096; + + public const int DefaultHttpsPort = 8920; + + private string _baseUrl = string.Empty; + + public bool RequireHttps { get; set; } + + public string CertificatePath { get; set; } = string.Empty; + + public string CertificatePassword { get; set; } = string.Empty; + + public string BaseUrl + { + get => _baseUrl; + set + { + // Normalize the start of the string + if (string.IsNullOrWhiteSpace(value)) + { + // If baseUrl is empty, set an empty prefix string + _baseUrl = string.Empty; + return; + } + + if (value[0] != '/') + { + // If baseUrl was not configured with a leading slash, append one for consistency + value = "/" + value; + } + + // Normalize the end of the string + if (value[^1] == '/') + { + // If baseUrl was configured with a trailing slash, remove it for consistency + value = value.Remove(value.Length - 1); + } + + _baseUrl = value; + } + } + + public int PublicHttpsPort { get; set; } = DefaultHttpsPort; + + public int HttpServerPortNumber { get; set; } = DefaultHttpPort; + + public int HttpsPortNumber { get; set; } = DefaultHttpsPort; + + public bool EnableHttps { get; set; } + + public int PublicPort { get; set; } = DefaultHttpPort; + + public bool UPnPCreateHttpPortMap { get; set; } + + public string UDPPortRange { get; set; } = string.Empty; + + public bool EnableIPV6 { get; set; } + + public bool EnableIPV4 { get; set; } = true; + + public bool EnableSSDPTracing { get; set; } + + public string SSDPTracingFilter { get; set; } = string.Empty; + + public int UDPSendCount { get; set; } = 2; + + public int UDPSendDelay { get; set; } = 100; + + public bool IgnoreVirtualInterfaces { get; set; } = true; + + public string VirtualInterfaceNames { get; set; } = "vEthernet*"; + + public int GatewayMonitorPeriod { get; set; } = 60; + + public bool EnableMultiSocketBinding { get; } = true; + + public bool TrustAllIP6Interfaces { get; set; } + + public string HDHomerunPortRange { get; set; } = string.Empty; + + public string[] PublishedServerUriBySubnet { get; set; } = Array.Empty<string>(); + + public bool AutoDiscoveryTracing { get; set; } + + public bool AutoDiscovery { get; set; } = true; + + public string[] RemoteIPFilter { get; set; } = Array.Empty<string>(); + + public bool IsRemoteIPFilterBlacklist { get; set; } + + public bool EnableUPnP { get; set; } + + public bool EnableRemoteAccess { get; set; } = true; + + public string[] LocalNetworkSubnets { get; set; } = Array.Empty<string>(); + + public string[] LocalNetworkAddresses { get; set; } = Array.Empty<string>(); + public string[] KnownProxies { get; set; } = Array.Empty<string>(); + + public bool EnablePublishedServerUriByRequest { get; set; } = false; + } +#pragma warning restore +} diff --git a/Jellyfin.Server/Startup.cs b/Jellyfin.Server/Startup.cs index 6394800f75..b759b6bca5 100644 --- a/Jellyfin.Server/Startup.cs +++ b/Jellyfin.Server/Startup.cs @@ -213,7 +213,7 @@ namespace Jellyfin.Server mainApp.UseAuthorization(); mainApp.UseLanFiltering(); - mainApp.UseIpBasedAccessValidation(); + mainApp.UseIPBasedAccessValidation(); mainApp.UseWebSocketHandler(); mainApp.UseServerStartupMessage(); |
