From 124bd4c2c03874f5b4de241e3d89ac95f6048b9a Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 21 Nov 2020 12:59:14 +0000 Subject: Networking: 1 - Network Manager (#4124) * NetworkManager * Config file with additional options. * Update Jellyfin.Networking/Manager/INetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/INetworkManager.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Model/Configuration/ServerConfiguration.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Model/Configuration/ServerConfiguration.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Model/Configuration/ServerConfiguration.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Split function. * Update Jellyfin.Networking/Manager/INetworkManager.cs Co-authored-by: Cody Robibero * fixed iterations * Update Jellyfin.Networking.csproj * Update NetworkManager.cs * Updated to NetCollection 1.03. * Update ServerConfiguration.cs * Update StartupController.cs * Update INetworkManager.cs Removed public * Update INetworkManager.cs * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Updated comment * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update Jellyfin.Networking/Manager/INetworkManager.cs Co-authored-by: Claus Vium * Remove mono code. Removed forced chromecast option * Inverted if * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Moved config into a separate container * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Changed sortedList to dictionary. * Update INetworkManager.cs Changed UpdateSettings param type * Update NetworkManager.cs * Update NetworkManager.cs * Update NetworkManager.cs * Update NetworkConfiguration.cs * Update INetworkManager.cs * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update MediaBrowser.Model/Configuration/ServerConfiguration.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Model/Configuration/ServerConfiguration.cs Co-authored-by: Cody Robibero * Updated changes github didn't update. * Fixed compilation. * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Removed read locking. * Update NetworkManager.cs Changed configuration event to NamedConfigurationUpdated * updated comment * removed whitespace * Updated NetCollection to 1.0.6 Updated DXCopAnalyser to 3.3.1 * removed NetCollection * Update NetworkManager.cs * Update NetworkExtensions.cs * Update NetworkExtensions.cs Removed function. * Update NetworkExtensions.cs * Update NetworkManager.cs Changed ToString() to AsString() as native collection formats incorrectly. * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update NetworkExtensions.cs * Update Jellyfin.Networking/Configuration/NetworkConfiguration.cs Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> * Update Jellyfin.Networking/Configuration/NetworkConfiguration.cs Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> * Update Jellyfin.Networking/Configuration/NetworkConfiguration.cs Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> * updated * Replaced NetCollection with Collection * Update MediaBrowser.Common/Net/NetworkExtensions.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Model/Configuration/PathSubstitution.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/NetworkExtensions.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPHost.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: Cody Robibero * Update MediaBrowser.Common/Net/IPObject.cs Co-authored-by: Cody Robibero * updated comments. * Updated comments / changes as suggested by @crobibero. * Split function as suggested * Fixed null ref. * Updated comment. * Updated cs to .net5 * Fixed issue with PublishedServerUrl * Fixes * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Restored locking * optimisation * Added comment * updates. * updated. * updates * updated. * Update IPHost.cs * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Claus Vium * Update NetworkManager.cs * Removed whitespace. * Added debug logging * Added debug. * Update Jellyfin.Networking/Manager/NetworkManager.cs Co-authored-by: Bond-009 * Replaced GetAddressBytes Co-authored-by: Cody Robibero Co-authored-by: Claus Vium Co-authored-by: h1dden-da3m0n <33120068+h1dden-da3m0n@users.noreply.github.com> Co-authored-by: Bond-009 --- MediaBrowser.Common/Net/NetworkExtensions.cs | 262 +++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) create mode 100644 MediaBrowser.Common/Net/NetworkExtensions.cs (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs new file mode 100644 index 000000000..d07bba249 --- /dev/null +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -0,0 +1,262 @@ +#pragma warning disable CA1062 // Validate arguments of public methods +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Net; +using System.Runtime.CompilerServices; +using System.Text; + +namespace MediaBrowser.Common.Net +{ + /// + /// Defines the . + /// + public static class NetworkExtensions + { + /// + /// Add an address to the collection. + /// + /// The . + /// Item to add. + public static void AddItem(this Collection source, IPAddress ip) + { + if (!source.ContainsAddress(ip)) + { + source.Add(new IPNetAddress(ip, 32)); + } + } + + /// + /// Adds a network to the collection. + /// + /// The . + /// Item to add. + public static void AddItem(this Collection source, IPObject item) + { + if (!source.ContainsAddress(item)) + { + source.Add(item); + } + } + + /// + /// Converts this object to a string. + /// + /// The . + /// Returns a string representation of this object. + public static string AsString(this Collection source) + { + return $"[{string.Join(',', source)}]"; + } + + /// + /// Returns true if the collection contains an item with the ip address, + /// or the ip address falls within any of the collection's network ranges. + /// + /// The . + /// The item to look for. + /// True if the collection contains the item. + public static bool ContainsAddress(this Collection source, IPAddress item) + { + if (source.Count == 0) + { + return false; + } + + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + if (item.IsIPv4MappedToIPv6) + { + item = item.MapToIPv4(); + } + + foreach (var i in source) + { + if (i.Contains(item)) + { + return true; + } + } + + return false; + } + + /// + /// Returns true if the collection contains an item with the ip address, + /// or the ip address falls within any of the collection's network ranges. + /// + /// The . + /// The item to look for. + /// True if the collection contains the item. + public static bool ContainsAddress(this Collection source, IPObject item) + { + if (source.Count == 0) + { + return false; + } + + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + + foreach (var i in source) + { + if (i.Contains(item)) + { + return true; + } + } + + return false; + } + + /// + /// Compares two Collection{IPObject} objects. The order is ignored. + /// + /// The . + /// Item to compare to. + /// True if both are equal. + public static bool Compare(this Collection source, Collection dest) + { + if (dest == null || source.Count != dest.Count) + { + return false; + } + + foreach (var sourceItem in source) + { + bool found = false; + foreach (var destItem in dest) + { + if (sourceItem.Equals(destItem)) + { + found = true; + break; + } + } + + if (!found) + { + return false; + } + } + + return true; + } + + /// + /// Returns a collection containing the subnets of this collection given. + /// + /// The . + /// Collection{IPObject} object containing the subnets. + public static Collection AsNetworks(this Collection source) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + Collection res = new Collection(); + + foreach (IPObject i in source) + { + if (i is IPNetAddress nw) + { + // Add the subnet calculated from the interface address/mask. + var na = nw.NetworkAddress; + na.Tag = i.Tag; + res.AddItem(na); + } + else if (i is IPHost ipHost) + { + // Flatten out IPHost and add all its ip addresses. + foreach (var addr in ipHost.GetAddresses()) + { + IPNetAddress host = new IPNetAddress(addr) + { + Tag = i.Tag + }; + + res.AddItem(host); + } + } + } + + return res; + } + + /// + /// Excludes all the items from this list that are found in excludeList. + /// + /// The . + /// Items to exclude. + /// A new collection, with the items excluded. + public static Collection Exclude(this Collection source, Collection excludeList) + { + if (source.Count == 0 || excludeList == null) + { + return new Collection(source); + } + + Collection results = new Collection(); + + bool found; + foreach (var outer in source) + { + found = false; + + foreach (var inner in excludeList) + { + if (outer.Equals(inner)) + { + found = true; + break; + } + } + + if (!found) + { + results.AddItem(outer); + } + } + + return results; + } + + /// + /// Returns all items that co-exist in this object and target. + /// + /// The . + /// Collection to compare with. + /// A collection containing all the matches. + public static Collection Union(this Collection source, Collection target) + { + if (source.Count == 0) + { + return new Collection(); + } + + if (target == null) + { + throw new ArgumentNullException(nameof(target)); + } + + Collection nc = new Collection(); + + foreach (IPObject i in source) + { + if (target.ContainsAddress(i)) + { + nc.AddItem(i); + } + } + + return nc; + } + } +} -- cgit v1.2.3 From eba859e33e7bf611e5b4d63acd4df81038154be8 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 21 Feb 2021 02:49:52 +0100 Subject: Minor improvements --- .../LiveTv/Listings/SchedulesDirect.cs | 1 - .../Session/WebSocketController.cs | 1 - Jellyfin.Api/Extensions/DtoExtensions.cs | 9 ----- Jellyfin.Api/Helpers/DynamicHlsHelper.cs | 11 ++++-- Jellyfin.Api/Helpers/StreamingHelpers.cs | 2 +- MediaBrowser.Common/Extensions/StringExtensions.cs | 37 ------------------- MediaBrowser.Common/Net/NetworkExtensions.cs | 5 --- tests/Jellyfin.Api.Tests/ParseNetworkTests.cs | 16 ++++---- .../Extensions/StringExtensionsTests.cs | 43 ---------------------- 9 files changed, 16 insertions(+), 109 deletions(-) delete mode 100644 MediaBrowser.Common/Extensions/StringExtensions.cs delete mode 100644 tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index c641b760b..6d7c5ac6e 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -10,7 +10,6 @@ using System.Net.Http; using System.Net.Mime; using System.Text; using System.Text.Json; -using System.Text.Json.Serialization; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; diff --git a/Emby.Server.Implementations/Session/WebSocketController.cs b/Emby.Server.Implementations/Session/WebSocketController.cs index f9c6a13c6..a653b58c2 100644 --- a/Emby.Server.Implementations/Session/WebSocketController.cs +++ b/Emby.Server.Implementations/Session/WebSocketController.cs @@ -8,7 +8,6 @@ using System.Linq; using System.Net.WebSockets; using System.Threading; using System.Threading.Tasks; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Session; using MediaBrowser.Model.Net; diff --git a/Jellyfin.Api/Extensions/DtoExtensions.cs b/Jellyfin.Api/Extensions/DtoExtensions.cs index f2abd515d..e0c744325 100644 --- a/Jellyfin.Api/Extensions/DtoExtensions.cs +++ b/Jellyfin.Api/Extensions/DtoExtensions.cs @@ -113,14 +113,5 @@ namespace Jellyfin.Api.Extensions return dtoOptions; } - - /// - /// Check if DtoOptions contains field. - /// - /// DtoOptions object. - /// Field to check. - /// Field existence. - internal static bool ContainsField(this DtoOptions dtoOptions, ItemFields field) - => dtoOptions.Fields != null && dtoOptions.Fields.Contains(field); } } diff --git a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs index 8a47f7461..16380f0bb 100644 --- a/Jellyfin.Api/Helpers/DynamicHlsHelper.cs +++ b/Jellyfin.Api/Helpers/DynamicHlsHelper.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Net; +using System.Net.Mime; using System.Security.Claims; using System.Text; using System.Threading; @@ -171,13 +172,15 @@ namespace Jellyfin.Api.Helpers var queryString = _httpContextAccessor.HttpContext.Request.QueryString.ToString(); // from universal audio service - if (queryString.IndexOf("SegmentContainer", StringComparison.OrdinalIgnoreCase) == -1 && !string.IsNullOrWhiteSpace(state.Request.SegmentContainer)) + if (!string.IsNullOrWhiteSpace(state.Request.SegmentContainer) + && !queryString.Contains("SegmentContainer", StringComparison.OrdinalIgnoreCase)) { queryString += "&SegmentContainer=" + state.Request.SegmentContainer; } // from universal audio service - if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) && queryString.IndexOf("TranscodeReasons=", StringComparison.OrdinalIgnoreCase) == -1) + if (!string.IsNullOrWhiteSpace(state.Request.TranscodeReasons) + && !queryString.Contains("TranscodeReasons=", StringComparison.OrdinalIgnoreCase)) { queryString += "&TranscodeReasons=" + state.Request.TranscodeReasons; } @@ -560,13 +563,13 @@ namespace Jellyfin.Api.Helpers profileString = state.GetRequestedProfiles(codec).FirstOrDefault() ?? string.Empty; if (string.Equals(state.ActualOutputVideoCodec, "h264", StringComparison.OrdinalIgnoreCase)) { - profileString = profileString ?? "high"; + profileString ??= "high"; } if (string.Equals(state.ActualOutputVideoCodec, "h265", StringComparison.OrdinalIgnoreCase) || string.Equals(state.ActualOutputVideoCodec, "hevc", StringComparison.OrdinalIgnoreCase)) { - profileString = profileString ?? "main"; + profileString ??= "main"; } } diff --git a/Jellyfin.Api/Helpers/StreamingHelpers.cs b/Jellyfin.Api/Helpers/StreamingHelpers.cs index 4957ee8b8..153ec3175 100644 --- a/Jellyfin.Api/Helpers/StreamingHelpers.cs +++ b/Jellyfin.Api/Helpers/StreamingHelpers.cs @@ -245,7 +245,7 @@ namespace Jellyfin.Api.Helpers var ext = string.IsNullOrWhiteSpace(state.OutputContainer) ? GetOutputFileExtension(state) - : ('.' + state.OutputContainer); + : ("." + state.OutputContainer); state.OutputFilePath = GetOutputFilePath(state, ext!, serverConfigurationManager, streamingRequest.DeviceId, streamingRequest.PlaySessionId); diff --git a/MediaBrowser.Common/Extensions/StringExtensions.cs b/MediaBrowser.Common/Extensions/StringExtensions.cs deleted file mode 100644 index 764301741..000000000 --- a/MediaBrowser.Common/Extensions/StringExtensions.cs +++ /dev/null @@ -1,37 +0,0 @@ -#nullable enable - -using System; - -namespace MediaBrowser.Common.Extensions -{ - /// - /// Extensions methods to simplify string operations. - /// - public static class StringExtensions - { - /// - /// Returns the part on the left of the needle. - /// - /// The string to seek. - /// The needle to find. - /// The part left of the . - public static ReadOnlySpan LeftPart(this ReadOnlySpan haystack, char needle) - { - var pos = haystack.IndexOf(needle); - return pos == -1 ? haystack : haystack[..pos]; - } - - /// - /// Returns the part on the left of the needle. - /// - /// The string to seek. - /// The needle to find. - /// One of the enumeration values that specifies the rules for the search. - /// The part left of the needle. - public static ReadOnlySpan LeftPart(this ReadOnlySpan haystack, ReadOnlySpan needle, StringComparison stringComparison = default) - { - var pos = haystack.IndexOf(needle, stringComparison); - return pos == -1 ? haystack : haystack[..pos]; - } - } -} diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs index d07bba249..9c1a0cf49 100644 --- a/MediaBrowser.Common/Net/NetworkExtensions.cs +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -1,11 +1,6 @@ -#pragma warning disable CA1062 // Validate arguments of public methods using System; -using System.Collections; -using System.Collections.Generic; using System.Collections.ObjectModel; using System.Net; -using System.Runtime.CompilerServices; -using System.Text; namespace MediaBrowser.Common.Net { diff --git a/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs b/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs index 6c3fd0ee1..3984407ee 100644 --- a/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs +++ b/tests/Jellyfin.Api.Tests/ParseNetworkTests.cs @@ -37,28 +37,28 @@ namespace Jellyfin.Api.Tests EnableIPV6 = ip6 }; - var result = match + ','; + var result = match + ","; ForwardedHeadersOptions options = new ForwardedHeadersOptions(); // Need this here as ::1 and 127.0.0.1 are in them by default. options.KnownProxies.Clear(); options.KnownNetworks.Clear(); - ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(","), options); + ApiServiceCollectionExtensions.AddProxyAddresses(settings, hostList.Split(','), options); var sb = new StringBuilder(); foreach (var item in options.KnownProxies) { - sb.Append(item); - sb.Append(','); + sb.Append(item) + .Append(','); } foreach (var item in options.KnownNetworks) { - sb.Append(item.Prefix); - sb.Append('/'); - sb.Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture)); - sb.Append(','); + sb.Append(item.Prefix) + .Append('/') + .Append(item.PrefixLength.ToString(CultureInfo.InvariantCulture)) + .Append(','); } Assert.Equal(sb.ToString(), result); diff --git a/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs b/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs deleted file mode 100644 index 8bf613f05..000000000 --- a/tests/Jellyfin.Common.Tests/Extensions/StringExtensionsTests.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using MediaBrowser.Common.Extensions; -using Xunit; - -namespace Jellyfin.Common.Tests.Extensions -{ - public class StringExtensionsTests - { - [Theory] - [InlineData("", 'q', "")] - [InlineData("Banana split", ' ', "Banana")] - [InlineData("Banana split", 'q', "Banana split")] - public void LeftPart_ValidArgsCharNeedle_Correct(string str, char needle, string expectedResult) - { - var result = str.AsSpan().LeftPart(needle).ToString(); - Assert.Equal(expectedResult, result); - } - - [Theory] - [InlineData("", "", "")] - [InlineData("", "q", "")] - [InlineData("Banana split", "", "")] - [InlineData("Banana split", " ", "Banana")] - [InlineData("Banana split test", " split", "Banana")] - public void LeftPart_ValidArgsWithoutStringComparison_Correct(string str, string needle, string expectedResult) - { - var result = str.AsSpan().LeftPart(needle).ToString(); - Assert.Equal(expectedResult, result); - } - - [Theory] - [InlineData("", "", StringComparison.Ordinal, "")] - [InlineData("Banana split", " ", StringComparison.Ordinal, "Banana")] - [InlineData("Banana split test", " split", StringComparison.Ordinal, "Banana")] - [InlineData("Banana split test", " Split", StringComparison.Ordinal, "Banana split test")] - [InlineData("Banana split test", " Splït", StringComparison.InvariantCultureIgnoreCase, "Banana split test")] - public void LeftPart_ValidArgs_Correct(string str, string needle, StringComparison stringComparison, string expectedResult) - { - var result = str.AsSpan().LeftPart(needle, stringComparison).ToString(); - Assert.Equal(expectedResult, result); - } - } -} -- cgit v1.2.3 From a031f7e410f7b599e1a50b2c54a7bd78f4187301 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Tue, 9 Mar 2021 00:07:21 +0000 Subject: Fix for multiple ip's in the same subnet per interface. --- Jellyfin.Networking/Manager/NetworkManager.cs | 37 ++++++++++++---------- MediaBrowser.Common/Net/NetworkExtensions.cs | 5 +-- .../NetworkTesting/NetworkParseTests.cs | 2 ++ 3 files changed, 25 insertions(+), 19 deletions(-) (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index 51fcb6d9a..17bbf9633 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -157,15 +157,16 @@ namespace Jellyfin.Networking.Manager /// Creates a new network collection. /// /// Items to assign the collection, or null. + /// True if subnets that overlap should be merged (default). /// The collection created. - public static Collection CreateCollection(IEnumerable? source = null) + public static Collection CreateCollection(IEnumerable? source = null, bool unique = true) { var result = new Collection(); if (source != null) { foreach (var item in source) { - result.AddItem(item); + result.AddItem(item, unique); } } @@ -386,10 +387,12 @@ namespace Jellyfin.Networking.Manager } // Get the first LAN interface address that isn't a loopback. - var interfaces = CreateCollection(_interfaceAddresses - .Exclude(_bindExclusions) - .Where(IsInLocalNetwork) - .OrderBy(p => p.Tag)); + var interfaces = CreateCollection( + _interfaceAddresses + .Exclude(_bindExclusions) + .Where(IsInLocalNetwork) + .OrderBy(p => p.Tag), + false); if (interfaces.Count > 0) { @@ -429,11 +432,11 @@ namespace Jellyfin.Networking.Manager if (_bindExclusions.Count > 0) { // Return all the internal interfaces except the ones excluded. - return CreateCollection(_internalInterfaces.Where(p => !_bindExclusions.ContainsAddress(p))); + return CreateCollection(_internalInterfaces.Where(p => !_bindExclusions.ContainsAddress(p)), false); } // No bind address, so return all internal interfaces. - return CreateCollection(_internalInterfaces.Where(p => !p.IsLoopback())); + return CreateCollection(_internalInterfaces.Where(p => !p.IsLoopback()), false); } return new Collection(_bindAddresses); @@ -555,7 +558,7 @@ namespace Jellyfin.Networking.Manager && ((IsIP4Enabled && iface.Address.AddressFamily == AddressFamily.InterNetwork) || (IsIP6Enabled && iface.Address.AddressFamily == AddressFamily.InterNetworkV6))) { - result.AddItem(iface); + result.AddItem(iface, false); } } @@ -599,8 +602,8 @@ namespace Jellyfin.Networking.Manager var address = IPNetAddress.Parse(parts[0]); var index = int.Parse(parts[1], CultureInfo.InvariantCulture); address.Tag = index; - _interfaceAddresses.AddItem(address); - _interfaceNames.Add(parts[2], Math.Abs(index)); + _interfaceAddresses.AddItem(address, false); + _interfaceNames[parts[2]] = Math.Abs(index); } } @@ -977,7 +980,7 @@ namespace Jellyfin.Networking.Manager { _logger.LogDebug("Using LAN interface addresses as user provided no LAN details."); // Internal interfaces must be private and not excluded. - _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsPrivateAddressRange(i) && !_excludedSubnets.ContainsAddress(i))); + _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsPrivateAddressRange(i) && !_excludedSubnets.ContainsAddress(i)), false); // Subnets are the same as the calculated internal interface. _lanSubnets = new Collection(); @@ -1012,7 +1015,7 @@ namespace Jellyfin.Networking.Manager } // Internal interfaces must be private, not excluded and part of the LocalNetworkSubnet. - _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsInLocalNetwork(i))); + _internalInterfaces = CreateCollection(_interfaceAddresses.Where(i => IsInLocalNetwork(i)), false); } _logger.LogInformation("Defined LAN addresses : {0}", _lanSubnets.AsString()); @@ -1071,7 +1074,7 @@ namespace Jellyfin.Networking.Manager nw.Tag *= -1; } - _interfaceAddresses.AddItem(nw); + _interfaceAddresses.AddItem(nw, false); // Store interface name so we can use the name in Collections. _interfaceNames[adapter.Description.ToLower(CultureInfo.InvariantCulture)] = tag; @@ -1092,7 +1095,7 @@ namespace Jellyfin.Networking.Manager nw.Tag *= -1; } - _interfaceAddresses.AddItem(nw); + _interfaceAddresses.AddItem(nw, false); // Store interface name so we can use the name in Collections. _interfaceNames[adapter.Description.ToLower(CultureInfo.InvariantCulture)] = tag; @@ -1126,10 +1129,10 @@ namespace Jellyfin.Networking.Manager { _logger.LogWarning("No interfaces information available. Using loopback."); // Last ditch attempt - use loopback address. - _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback); + _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback, false); if (IsIP6Enabled) { - _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback); + _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback, false); } } } diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs index 9c1a0cf49..cd0c2ea24 100644 --- a/MediaBrowser.Common/Net/NetworkExtensions.cs +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -27,9 +27,10 @@ namespace MediaBrowser.Common.Net /// /// The . /// Item to add. - public static void AddItem(this Collection source, IPObject item) + /// True if subnets that overlap should be merged (default). + public static void AddItem(this Collection source, IPObject item, bool unique = true) { - if (!source.ContainsAddress(item)) + if (!source.ContainsAddress(item) || !unique) { source.Add(item); } diff --git a/tests/Jellyfin.Networking.Tests/NetworkTesting/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkTesting/NetworkParseTests.cs index 9f928ded1..a13822fcb 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkTesting/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkTesting/NetworkParseTests.cs @@ -38,6 +38,8 @@ namespace Jellyfin.Networking.Tests [InlineData("192.168.1.208/24,-16,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[]")] // vEthernet1 and vEthernet212 should be excluded. [InlineData("192.168.1.200/24,-20,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.200/24", "[200.200.200.200/24]")] + // Overlapping interface, + [InlineData("192.168.1.110/24,-20,br0|192.168.1.10/24,-16,br0|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[192.168.1.110/24,192.168.1.10/24]")] public void IgnoreVirtualInterfaces(string interfaces, string lan, string value) { var conf = new NetworkConfiguration() -- cgit v1.2.3 From b1f0c5eb4935904bea3a784e147d403b9d43097d Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sat, 13 Mar 2021 22:16:12 +0000 Subject: Update NetworkExtensions.cs changed description --- MediaBrowser.Common/Net/NetworkExtensions.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs index cd0c2ea24..26f21b5f1 100644 --- a/MediaBrowser.Common/Net/NetworkExtensions.cs +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -27,10 +27,11 @@ namespace MediaBrowser.Common.Net /// /// The . /// Item to add. - /// True if subnets that overlap should be merged (default). - public static void AddItem(this Collection source, IPObject item, bool unique = true) + /// If true the values are treated as subnets. + /// If false items are addresses. + public static void AddItem(this Collection source, IPObject item, bool itemsAreNetworks = true) { - if (!source.ContainsAddress(item) || !unique) + if (!source.ContainsAddress(item) || !itemsAreNetworks) { source.Add(item); } -- cgit v1.2.3 From 6087831aa65398a6305570c4dc84f0bc2613b842 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Sun, 14 Mar 2021 17:30:25 +0000 Subject: Fixed selection of correct interface ip --- Jellyfin.Networking/Manager/NetworkManager.cs | 26 ++++++++++++++++++-------- MediaBrowser.Common/Net/NetworkExtensions.cs | 7 ++++--- 2 files changed, 22 insertions(+), 11 deletions(-) (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index bf121737b..9ce3b7e49 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -274,7 +274,7 @@ namespace Jellyfin.Networking.Manager if (_bindExclusions.Count > 0) { // Return all the interfaces except the ones specifically excluded. - return _interfaceAddresses.Exclude(_bindExclusions); + return _interfaceAddresses.Exclude(_bindExclusions, false); } if (individualInterfaces) @@ -299,7 +299,7 @@ namespace Jellyfin.Networking.Manager } // Remove any excluded bind interfaces. - return _bindAddresses.Exclude(_bindExclusions); + return _bindAddresses.Exclude(_bindExclusions, false); } /// @@ -388,7 +388,7 @@ namespace Jellyfin.Networking.Manager // Get the first LAN interface address that isn't a loopback. var interfaces = CreateCollection( _interfaceAddresses - .Exclude(_bindExclusions) + .Exclude(_bindExclusions, false) .Where(IsInLocalNetwork) .OrderBy(p => p.Tag)); @@ -396,6 +396,16 @@ namespace Jellyfin.Networking.Manager { if (haveSource) { + foreach (var intf in interfaces) + { + if (intf.Address.Equals(source.Address)) + { + result = FormatIP6String(intf.Address); + _logger.LogDebug("{Source}: GetBindInterface: Has found matching interface. {Result}", source, result); + return result; + } + } + // Does the request originate in one of the interface subnets? // (For systems with multiple internal network cards, and multiple subnets) foreach (var intf in interfaces) @@ -522,10 +532,10 @@ namespace Jellyfin.Networking.Manager { if (filter == null) { - return _lanSubnets.Exclude(_excludedSubnets).AsNetworks(); + return _lanSubnets.Exclude(_excludedSubnets, true).AsNetworks(); } - return _lanSubnets.Exclude(filter); + return _lanSubnets.Exclude(filter, true); } /// @@ -1018,7 +1028,7 @@ namespace Jellyfin.Networking.Manager _logger.LogInformation("Defined LAN addresses : {0}", _lanSubnets.AsString()); _logger.LogInformation("Defined LAN exclusions : {0}", _excludedSubnets.AsString()); - _logger.LogInformation("Using LAN addresses: {0}", _lanSubnets.Exclude(_excludedSubnets).AsNetworks().AsString()); + _logger.LogInformation("Using LAN addresses: {0}", _lanSubnets.Exclude(_excludedSubnets, true).AsNetworks().AsString()); } } @@ -1207,7 +1217,7 @@ namespace Jellyfin.Networking.Manager private bool MatchesBindInterface(IPObject source, bool isInExternalSubnet, out string result) { result = string.Empty; - var addresses = _bindAddresses.Exclude(_bindExclusions); + var addresses = _bindAddresses.Exclude(_bindExclusions, false); int count = addresses.Count; if (count == 1 && (_bindAddresses[0].Equals(IPAddress.Any) || _bindAddresses[0].Equals(IPAddress.IPv6Any))) @@ -1292,7 +1302,7 @@ namespace Jellyfin.Networking.Manager result = string.Empty; // Get the first WAN interface address that isn't a loopback. var extResult = _interfaceAddresses - .Exclude(_bindExclusions) + .Exclude(_bindExclusions, false) .Where(p => !IsInLocalNetwork(p)) .OrderBy(p => p.Tag); diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs index 26f21b5f1..93cfb4817 100644 --- a/MediaBrowser.Common/Net/NetworkExtensions.cs +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -27,7 +27,7 @@ namespace MediaBrowser.Common.Net /// /// The . /// Item to add. - /// If true the values are treated as subnets. + /// If true the values are treated as subnets. /// If false items are addresses. public static void AddItem(this Collection source, IPObject item, bool itemsAreNetworks = true) { @@ -192,8 +192,9 @@ namespace MediaBrowser.Common.Net /// /// The . /// Items to exclude. + /// Collection is a network collection. /// A new collection, with the items excluded. - public static Collection Exclude(this Collection source, Collection excludeList) + public static Collection Exclude(this Collection source, Collection excludeList, bool isNetwork) { if (source.Count == 0 || excludeList == null) { @@ -218,7 +219,7 @@ namespace MediaBrowser.Common.Net if (!found) { - results.AddItem(outer); + results.AddItem(outer, isNetwork); } } -- cgit v1.2.3 From 0b774eac12a882fbdc1ed402f36aaf6e4341e2c2 Mon Sep 17 00:00:00 2001 From: BaronGreenback Date: Wed, 14 Apr 2021 10:26:05 +0100 Subject: Enables the ability to bind to loopback address. (#5773) --- Jellyfin.Networking/Manager/NetworkManager.cs | 62 +++++++++++++--------- MediaBrowser.Common/Net/NetworkExtensions.cs | 2 +- .../Jellyfin.Networking.Tests/NetworkParseTests.cs | 10 ++-- 3 files changed, 44 insertions(+), 30 deletions(-) (limited to 'MediaBrowser.Common/Net/NetworkExtensions.cs') diff --git a/Jellyfin.Networking/Manager/NetworkManager.cs b/Jellyfin.Networking/Manager/NetworkManager.cs index 2f5a5b6e3..73e8b2cd7 100644 --- a/Jellyfin.Networking/Manager/NetworkManager.cs +++ b/Jellyfin.Networking/Manager/NetworkManager.cs @@ -647,6 +647,16 @@ namespace Jellyfin.Networking.Manager _interfaceAddresses.AddItem(address, false); _interfaceNames[parts[2]] = Math.Abs(index); } + + if (IsIP4Enabled) + { + _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback); + } + + if (IsIP6Enabled) + { + _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback); + } } InitialiseLAN(config); @@ -978,8 +988,8 @@ namespace Jellyfin.Networking.Manager } // Read and parse bind addresses and exclusions, removing ones that don't exist. - _bindAddresses = CreateIPCollection(lanAddresses).Union(_interfaceAddresses); - _bindExclusions = CreateIPCollection(lanAddresses, true).Union(_interfaceAddresses); + _bindAddresses = CreateIPCollection(lanAddresses).ThatAreContainedInNetworks(_interfaceAddresses); + _bindExclusions = CreateIPCollection(lanAddresses, true).ThatAreContainedInNetworks(_interfaceAddresses); _logger.LogInformation("Using bind addresses: {0}", _bindAddresses.AsString()); _logger.LogInformation("Using bind exclusions: {0}", _bindExclusions.AsString()); } @@ -1153,36 +1163,40 @@ namespace Jellyfin.Networking.Manager } #pragma warning restore CA1031 // Do not catch general exception types } + } + catch (Exception ex) + { + _logger.LogError(ex, "Error in InitialiseInterfaces."); + } - _logger.LogDebug("Discovered {0} interfaces.", _interfaceAddresses.Count); - _logger.LogDebug("Interfaces addresses : {0}", _interfaceAddresses.AsString()); + // If for some reason we don't have an interface info, resolve our DNS name. + if (_interfaceAddresses.Count == 0) + { + _logger.LogError("No interfaces information available. Resolving DNS name."); + IPHost host = new IPHost(Dns.GetHostName()); + foreach (var a in host.GetAddresses()) + { + _interfaceAddresses.AddItem(a); + } - // If for some reason we don't have an interface info, resolve our DNS name. if (_interfaceAddresses.Count == 0) { - _logger.LogError("No interfaces information available. Resolving DNS name."); - IPHost host = new IPHost(Dns.GetHostName()); - foreach (var a in host.GetAddresses()) - { - _interfaceAddresses.AddItem(a); - } - - if (_interfaceAddresses.Count == 0) - { - _logger.LogWarning("No interfaces information available. Using loopback."); - // Last ditch attempt - use loopback address. - _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback, false); - if (IsIP6Enabled) - { - _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback, false); - } - } + _logger.LogWarning("No interfaces information available. Using loopback."); } } - catch (NetworkInformationException ex) + + if (IsIP4Enabled) { - _logger.LogError(ex, "Error in InitialiseInterfaces."); + _interfaceAddresses.AddItem(IPNetAddress.IP4Loopback); + } + + if (IsIP6Enabled) + { + _interfaceAddresses.AddItem(IPNetAddress.IP6Loopback); } + + _logger.LogDebug("Discovered {0} interfaces.", _interfaceAddresses.Count); + _logger.LogDebug("Interfaces addresses : {0}", _interfaceAddresses.AsString()); } } diff --git a/MediaBrowser.Common/Net/NetworkExtensions.cs b/MediaBrowser.Common/Net/NetworkExtensions.cs index 93cfb4817..264bfacb4 100644 --- a/MediaBrowser.Common/Net/NetworkExtensions.cs +++ b/MediaBrowser.Common/Net/NetworkExtensions.cs @@ -232,7 +232,7 @@ namespace MediaBrowser.Common.Net /// The . /// Collection to compare with. /// A collection containing all the matches. - public static Collection Union(this Collection source, Collection target) + public static Collection ThatAreContainedInNetworks(this Collection source, Collection target) { if (source.Count == 0) { diff --git a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs index 2d3356998..9b0da2b3c 100644 --- a/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs +++ b/tests/Jellyfin.Networking.Tests/NetworkParseTests.cs @@ -34,10 +34,10 @@ namespace Jellyfin.Networking.Tests [InlineData("192.168.1.208/24,-16,eth16|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.0/24", "[192.168.1.208/24,200.200.200.200/24]")] // eth16 only [InlineData("192.168.1.208/24,-16,eth16|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[192.168.1.208/24]")] - // All interfaces excluded. - [InlineData("192.168.1.208/24,-16,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[]")] + // All interfaces excluded. (including loopbacks) + [InlineData("192.168.1.208/24,-16,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[127.0.0.1/8,::1/128]")] // vEthernet1 and vEthernet212 should be excluded. - [InlineData("192.168.1.200/24,-20,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.200/24", "[200.200.200.200/24]")] + [InlineData("192.168.1.200/24,-20,vEthernet1|192.168.2.208/24,-16,vEthernet212|200.200.200.200/24,11,eth11", "192.168.1.0/24;200.200.200.200/24", "[200.200.200.200/24,127.0.0.1/8,::1/128]")] // Overlapping interface, [InlineData("192.168.1.110/24,-20,br0|192.168.1.10/24,-16,br0|200.200.200.200/24,11,eth11", "192.168.1.0/24", "[192.168.1.110/24,192.168.1.10/24]")] public void IgnoreVirtualInterfaces(string interfaces, string lan, string value) @@ -241,7 +241,7 @@ namespace Jellyfin.Networking.Tests Collection nc1 = nm.CreateIPCollection(settings.Split(','), false); Collection nc2 = nm.CreateIPCollection(compare.Split(','), false); - Assert.Equal(nc1.Union(nc2).AsString(), result); + Assert.Equal(nc1.ThatAreContainedInNetworks(nc2).AsString(), result); } [Theory] @@ -350,7 +350,7 @@ namespace Jellyfin.Networking.Tests // Test included, IP6. Collection ncSource = nm.CreateIPCollection(source.Split(',')); Collection ncDest = nm.CreateIPCollection(dest.Split(',')); - Collection ncResult = ncSource.Union(ncDest); + Collection ncResult = ncSource.ThatAreContainedInNetworks(ncDest); Collection resultCollection = nm.CreateIPCollection(result.Split(',')); Assert.True(ncResult.Compare(resultCollection)); } -- cgit v1.2.3