< Summary - Jellyfin

Information
Class: Jellyfin.Networking.Manager.NetworkManager
Assembly: Jellyfin.Networking
File(s): /srv/git/jellyfin/src/Jellyfin.Networking/Manager/NetworkManager.cs
Line coverage
75%
Covered lines: 361
Uncovered lines: 116
Coverable lines: 477
Total lines: 1177
Line coverage: 75.6%
Branch coverage
66%
Covered branches: 174
Total branches: 260
Branch coverage: 66.9%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Coverage history

Coverage history 0 25 50 75 100 10/18/2025 - 12:10:13 AM Line coverage: 75.9% (366/482) Branch coverage: 67.1% (176/262) Total lines: 11831/19/2026 - 12:13:54 AM Line coverage: 75.6% (361/477) Branch coverage: 66.9% (174/260) Total lines: 1177 10/18/2025 - 12:10:13 AM Line coverage: 75.9% (366/482) Branch coverage: 67.1% (176/262) Total lines: 11831/19/2026 - 12:13:54 AM Line coverage: 75.6% (361/477) Branch coverage: 66.9% (174/260) Total lines: 1177

Metrics

File(s)

/srv/git/jellyfin/src/Jellyfin.Networking/Manager/NetworkManager.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Diagnostics.CodeAnalysis;
 4using System.Globalization;
 5using System.Linq;
 6using System.Net;
 7using System.Net.NetworkInformation;
 8using System.Net.Sockets;
 9using System.Threading;
 10using J2N.Collections.Generic.Extensions;
 11using MediaBrowser.Common.Configuration;
 12using MediaBrowser.Common.Net;
 13using MediaBrowser.Model.Net;
 14using Microsoft.AspNetCore.Http;
 15using Microsoft.Extensions.Configuration;
 16using Microsoft.Extensions.Logging;
 17using static MediaBrowser.Controller.Extensions.ConfigurationExtensions;
 18using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager;
 19
 20namespace Jellyfin.Networking.Manager;
 21
 22/// <summary>
 23/// Class to take care of network interface management.
 24/// </summary>
 25public class NetworkManager : INetworkManager, IDisposable
 26{
 27    /// <summary>
 28    /// Threading lock for network properties.
 29    /// </summary>
 30    private readonly Lock _initLock;
 31
 32    private readonly ILogger<NetworkManager> _logger;
 33
 34    private readonly IConfigurationManager _configurationManager;
 35
 36    private readonly IConfiguration _startupConfig;
 37
 38    private readonly Lock _networkEventLock;
 39
 40    /// <summary>
 41    /// Holds the published server URLs and the IPs to use them on.
 42    /// </summary>
 43    private IReadOnlyList<PublishedServerUriOverride> _publishedServerUrls;
 44
 45    private IReadOnlyList<IPNetwork> _remoteAddressFilter;
 46
 47    /// <summary>
 48    /// Used to stop "event-racing conditions".
 49    /// </summary>
 50    private bool _eventfire;
 51
 52    /// <summary>
 53    /// Dictionary containing interface addresses and their subnets.
 54    /// </summary>
 55    private List<IPData> _interfaces;
 56
 57    /// <summary>
 58    /// Unfiltered user defined LAN subnets (<see cref="NetworkConfiguration.LocalNetworkSubnets"/>)
 59    /// or internal interface network subnets if undefined by user.
 60    /// </summary>
 61    private IReadOnlyList<IPNetwork> _lanSubnets;
 62
 63    /// <summary>
 64    /// User defined list of subnets to excluded from the LAN.
 65    /// </summary>
 66    private IReadOnlyList<IPNetwork> _excludedSubnets;
 67
 68    /// <summary>
 69    /// True if this object is disposed.
 70    /// </summary>
 71    private bool _disposed;
 72
 73    /// <summary>
 74    /// Initializes a new instance of the <see cref="NetworkManager"/> class.
 75    /// </summary>
 76    /// <param name="configurationManager">The <see cref="IConfigurationManager"/> instance.</param>
 77    /// <param name="startupConfig">The <see cref="IConfiguration"/> instance holding startup parameters.</param>
 78    /// <param name="logger">Logger to use for messages.</param>
 79    public NetworkManager(IConfigurationManager configurationManager, IConfiguration startupConfig, ILogger<NetworkManag
 80    {
 7981        ArgumentNullException.ThrowIfNull(logger);
 7982        ArgumentNullException.ThrowIfNull(configurationManager);
 83
 7984        _logger = logger;
 7985        _configurationManager = configurationManager;
 7986        _startupConfig = startupConfig;
 7987        _initLock = new();
 7988        _interfaces = new List<IPData>();
 7989        _publishedServerUrls = new List<PublishedServerUriOverride>();
 7990        _networkEventLock = new();
 7991        _remoteAddressFilter = new List<IPNetwork>();
 92
 7993        _ = bool.TryParse(startupConfig[DetectNetworkChangeKey], out var detectNetworkChange);
 94
 7995        UpdateSettings(_configurationManager.GetNetworkConfiguration());
 96
 7997        if (detectNetworkChange)
 98        {
 2199            NetworkChange.NetworkAddressChanged += OnNetworkAddressChanged;
 21100            NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
 101        }
 102
 79103        _configurationManager.NamedConfigurationUpdated += ConfigurationUpdated;
 79104    }
 105
 106    /// <summary>
 107    /// Event triggered on network changes.
 108    /// </summary>
 109    public event EventHandler? NetworkChanged;
 110
 111    /// <summary>
 112    /// Gets or sets a value indicating whether testing is taking place.
 113    /// </summary>
 3114    public static string MockNetworkSettings { get; set; } = string.Empty;
 115
 116    /// <summary>
 117    /// Gets a value indicating whether IPv4 is enabled.
 118    /// </summary>
 249119    public bool IsIPv4Enabled => _configurationManager.GetNetworkConfiguration().EnableIPv4;
 120
 121    /// <summary>
 122    /// Gets a value indicating whether IP6 is enabled.
 123    /// </summary>
 221124    public bool IsIPv6Enabled => _configurationManager.GetNetworkConfiguration().EnableIPv6;
 125
 126    /// <summary>
 127    /// Gets a value indicating whether is all IPv6 interfaces are trusted as internal.
 128    /// </summary>
 129    public bool TrustAllIPv6Interfaces { get; private set; }
 130
 131    /// <summary>
 132    /// Gets the Published server override list.
 133    /// </summary>
 0134    public IReadOnlyList<PublishedServerUriOverride> PublishedServerUrls => _publishedServerUrls;
 135
 136    /// <inheritdoc/>
 137    public void Dispose()
 138    {
 58139        Dispose(true);
 58140        GC.SuppressFinalize(this);
 58141    }
 142
 143    /// <summary>
 144    /// Handler for network change events.
 145    /// </summary>
 146    /// <param name="sender">Sender.</param>
 147    /// <param name="e">A <see cref="NetworkAvailabilityEventArgs"/> containing network availability information.</param
 148    private void OnNetworkAvailabilityChanged(object? sender, NetworkAvailabilityEventArgs e)
 149    {
 0150        _logger.LogDebug("Network availability changed.");
 0151        HandleNetworkChange();
 0152    }
 153
 154    /// <summary>
 155    /// Handler for network change events.
 156    /// </summary>
 157    /// <param name="sender">Sender.</param>
 158    /// <param name="e">An <see cref="EventArgs"/>.</param>
 159    private void OnNetworkAddressChanged(object? sender, EventArgs e)
 160    {
 0161        _logger.LogDebug("Network address change detected.");
 0162        HandleNetworkChange();
 0163    }
 164
 165    /// <summary>
 166    /// Triggers our event, and re-loads interface information.
 167    /// </summary>
 168    private void HandleNetworkChange()
 0169    {
 170        lock (_networkEventLock)
 171        {
 0172            if (!_eventfire)
 173            {
 174                // As network events tend to fire one after the other only fire once every second.
 0175                _eventfire = true;
 0176                OnNetworkChange();
 177            }
 0178        }
 0179    }
 180
 181    /// <summary>
 182    /// Waits for 2 seconds before re-initialising the settings, as typically these events fire multiple times in succes
 183    /// </summary>
 184    private void OnNetworkChange()
 185    {
 186        try
 187        {
 0188            Thread.Sleep(2000);
 0189            var networkConfig = _configurationManager.GetNetworkConfiguration();
 0190            if (IsIPv6Enabled && !Socket.OSSupportsIPv6)
 191            {
 0192                UpdateSettings(networkConfig);
 193            }
 194            else
 195            {
 0196                InitializeInterfaces();
 0197                InitializeLan(networkConfig);
 0198                EnforceBindSettings(networkConfig);
 199            }
 200
 0201            PrintNetworkInformation(networkConfig);
 0202            NetworkChanged?.Invoke(this, EventArgs.Empty);
 0203        }
 204        finally
 205        {
 0206            _eventfire = false;
 0207        }
 0208    }
 209
 210    /// <summary>
 211    /// Generate a list of all the interface ip addresses and submasks where that are in the active/unknown state.
 212    /// </summary>
 213    private void InitializeInterfaces()
 34214    {
 215        lock (_initLock)
 216        {
 34217            _interfaces = GetInterfacesCore(_logger, IsIPv4Enabled, IsIPv6Enabled).ToList();
 34218        }
 34219    }
 220
 221    /// <summary>
 222    /// Generate a list of all the interface ip addresses and submasks where that are in the active/unknown state.
 223    /// </summary>
 224    /// <param name="logger">The logger.</param>
 225    /// <param name="isIPv4Enabled">If true evaluates IPV4 type ip addresses.</param>
 226    /// <param name="isIPv6Enabled">If true evaluates IPV6 type ip addresses.</param>
 227    /// <returns>A list of all locally known up addresses and submasks that are to be considered usable.</returns>
 228    public static IReadOnlyList<IPData> GetInterfacesCore(ILogger logger, bool isIPv4Enabled, bool isIPv6Enabled)
 229    {
 34230        logger.LogDebug("Refreshing interfaces.");
 231
 34232        var interfaces = new List<IPData>();
 233
 234        try
 235        {
 34236            var nics = NetworkInterface.GetAllNetworkInterfaces()
 34237                .Where(i => i.OperationalStatus == OperationalStatus.Up);
 238
 204239            foreach (NetworkInterface adapter in nics)
 240            {
 241                try
 242                {
 68243                    var ipProperties = adapter.GetIPProperties();
 244
 245                    // Populate interface list
 408246                    foreach (var info in ipProperties.UnicastAddresses)
 247                    {
 136248                        if (isIPv4Enabled && info.Address.AddressFamily == AddressFamily.InterNetwork)
 249                        {
 68250                            var interfaceObject = new IPData(info.Address, new IPNetwork(info.Address, info.PrefixLength
 68251                            {
 68252                                Index = ipProperties.GetIPv4Properties().Index,
 68253                                Name = adapter.Name,
 68254                                SupportsMulticast = adapter.SupportsMulticast
 68255                            };
 256
 68257                            interfaces.Add(interfaceObject);
 258                        }
 68259                        else if (isIPv6Enabled && info.Address.AddressFamily == AddressFamily.InterNetworkV6)
 260                        {
 14261                            var interfaceObject = new IPData(info.Address, new IPNetwork(info.Address, info.PrefixLength
 14262                            {
 14263                                Index = ipProperties.GetIPv6Properties().Index,
 14264                                Name = adapter.Name,
 14265                                SupportsMulticast = adapter.SupportsMulticast
 14266                            };
 267
 14268                            interfaces.Add(interfaceObject);
 269                        }
 270                    }
 68271                }
 0272                catch (Exception ex)
 273                {
 274                    // Ignore error, and attempt to continue.
 0275                    logger.LogError(ex, "Error encountered parsing interfaces.");
 0276                }
 277            }
 34278        }
 0279        catch (Exception ex)
 280        {
 0281            logger.LogError(ex, "Error obtaining interfaces.");
 0282        }
 283
 284        // If no interfaces are found, fallback to loopback interfaces.
 34285        if (interfaces.Count == 0)
 286        {
 0287            logger.LogWarning("No interface information available. Using loopback interface(s).");
 288
 0289            if (isIPv4Enabled)
 290            {
 0291                interfaces.Add(new IPData(IPAddress.Loopback, NetworkConstants.IPv4RFC5735Loopback, "lo"));
 292            }
 293
 0294            if (isIPv6Enabled)
 295            {
 0296                interfaces.Add(new IPData(IPAddress.IPv6Loopback, NetworkConstants.IPv6RFC4291Loopback, "lo"));
 297            }
 298        }
 299
 34300        logger.LogDebug("Discovered {NumberOfInterfaces} interfaces.", interfaces.Count);
 34301        logger.LogDebug("Interfaces addresses: {Addresses}", interfaces.OrderByDescending(s => s.AddressFamily == Addres
 34302        return interfaces;
 303    }
 304
 305    /// <summary>
 306    /// Initializes internal LAN cache.
 307    /// </summary>
 308    [MemberNotNull(nameof(_lanSubnets), nameof(_excludedSubnets))]
 309    private void InitializeLan(NetworkConfiguration config)
 79310    {
 311        lock (_initLock)
 312        {
 79313            _logger.LogDebug("Refreshing LAN information.");
 314
 315            // Get configuration options
 79316            var subnets = config.LocalNetworkSubnets;
 317
 318            // If no LAN addresses are specified, all private subnets and Loopback are deemed to be the LAN
 79319            if (!NetworkUtils.TryParseToSubnets(subnets, out var lanSubnets, false) || lanSubnets.Count == 0)
 320            {
 45321                _logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
 322
 45323                var fallbackLanSubnets = new List<IPNetwork>();
 45324                if (IsIPv6Enabled)
 325                {
 7326                    fallbackLanSubnets.Add(NetworkConstants.IPv6RFC4291Loopback); // RFC 4291 (Loopback)
 7327                    fallbackLanSubnets.Add(NetworkConstants.IPv6RFC4291SiteLocal); // RFC 4291 (Site local)
 7328                    fallbackLanSubnets.Add(NetworkConstants.IPv6RFC4193UniqueLocal); // RFC 4193 (Unique local)
 329                }
 330
 45331                if (IsIPv4Enabled)
 332                {
 45333                    fallbackLanSubnets.Add(NetworkConstants.IPv4RFC5735Loopback); // RFC 5735 (Loopback)
 45334                    fallbackLanSubnets.Add(NetworkConstants.IPv4RFC1918PrivateClassA); // RFC 1918 (private Class A)
 45335                    fallbackLanSubnets.Add(NetworkConstants.IPv4RFC1918PrivateClassB); // RFC 1918 (private Class B)
 45336                    fallbackLanSubnets.Add(NetworkConstants.IPv4RFC1918PrivateClassC); // RFC 1918 (private Class C)
 337                }
 338
 45339                _lanSubnets = fallbackLanSubnets;
 340            }
 341            else
 342            {
 34343                _lanSubnets = lanSubnets.Select(x => x.Subnet).ToArray();
 344            }
 345
 79346            _excludedSubnets = NetworkUtils.TryParseToSubnets(subnets, out var excludedSubnets, true)
 79347                ? excludedSubnets.Select(x => x.Subnet).ToArray()
 79348                : Array.Empty<IPNetwork>();
 79349        }
 79350    }
 351
 352    /// <summary>
 353    /// Enforce bind addresses and exclusions on available interfaces.
 354    /// </summary>
 355    private void EnforceBindSettings(NetworkConfiguration config)
 79356    {
 357        lock (_initLock)
 358        {
 79359           _interfaces = FilterBindSettings(config, _interfaces, IsIPv4Enabled, IsIPv6Enabled).ToList();
 79360        }
 79361    }
 362
 363    /// <summary>
 364    /// Filters a list of bind addresses and exclusions on available interfaces.
 365    /// </summary>
 366    /// <param name="config">The network config to be filtered by.</param>
 367    /// <param name="interfaces">A list of possible interfaces to be filtered.</param>
 368    /// <param name="isIPv4Enabled">If true evaluates IPV4 type ip addresses.</param>
 369    /// <param name="isIPv6Enabled">If true evaluates IPV6 type ip addresses.</param>
 370    /// <returns>A list of all locally known up addresses and submasks that are to be considered usable.</returns>
 371    public static IReadOnlyList<IPData> FilterBindSettings(NetworkConfiguration config, IList<IPData> interfaces, bool i
 372    {
 373        // Respect explicit bind addresses
 79374        var localNetworkAddresses = config.LocalNetworkAddresses;
 79375        if (localNetworkAddresses.Length > 0 && !string.IsNullOrWhiteSpace(localNetworkAddresses[0]))
 376        {
 12377            var bindAddresses = localNetworkAddresses.Select(p => NetworkUtils.TryParseToSubnet(p, out var network)
 12378                    ? network.Address
 12379                    : (interfaces.Where(x => x.Name.Equals(p, StringComparison.OrdinalIgnoreCase))
 12380                        .Select(x => x.Address)
 12381                        .FirstOrDefault() ?? IPAddress.None))
 12382                .Where(x => x != IPAddress.None)
 12383                .ToHashSet();
 12384            interfaces = interfaces.Where(x => bindAddresses.Contains(x.Address)).ToList();
 385
 12386            if (bindAddresses.Contains(IPAddress.Loopback) && !interfaces.Any(i => i.Address.Equals(IPAddress.Loopback))
 387            {
 0388                interfaces.Add(new IPData(IPAddress.Loopback, NetworkConstants.IPv4RFC5735Loopback, "lo"));
 389            }
 390
 12391            if (bindAddresses.Contains(IPAddress.IPv6Loopback) && !interfaces.Any(i => i.Address.Equals(IPAddress.IPv6Lo
 392            {
 0393                interfaces.Add(new IPData(IPAddress.IPv6Loopback, NetworkConstants.IPv6RFC4291Loopback, "lo"));
 394            }
 395        }
 396
 397        // Remove all interfaces matching any virtual machine interface prefix
 79398        if (config.IgnoreVirtualInterfaces)
 399        {
 400            // Remove potentially existing * and split config string into prefixes
 79401            var virtualInterfacePrefixes = config.VirtualInterfaceNames
 79402                .Select(i => i.Replace("*", string.Empty, StringComparison.OrdinalIgnoreCase));
 403
 404            // Check all interfaces for matches against the prefixes and remove them
 79405            if (interfaces.Count > 0)
 406            {
 316407                foreach (var virtualInterfacePrefix in virtualInterfacePrefixes)
 408                {
 79409                    interfaces.RemoveAll(x => x.Name.StartsWith(virtualInterfacePrefix, StringComparison.OrdinalIgnoreCa
 410                }
 411            }
 412        }
 413
 414        // Remove all IPv4 interfaces if IPv4 is disabled
 79415        if (!isIPv4Enabled)
 416        {
 0417            interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
 418        }
 419
 420        // Remove all IPv6 interfaces if IPv6 is disabled
 79421        if (!isIPv6Enabled)
 422        {
 55423            interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);
 424        }
 425
 426        // Users may have complex networking configuration that multiple interfaces sharing the same IP address
 427        // Only return one IP for binding, and let the OS handle the rest
 79428        return interfaces.DistinctBy(iface => iface.Address).ToList();
 429    }
 430
 431    /// <summary>
 432    /// Initializes the remote address values.
 433    /// </summary>
 434    private void InitializeRemote(NetworkConfiguration config)
 79435    {
 436        lock (_initLock)
 437        {
 438            // Parse config values into filter collection
 79439            var remoteIPFilter = config.RemoteIPFilter;
 79440            if (remoteIPFilter.Length != 0 && !string.IsNullOrWhiteSpace(remoteIPFilter[0]))
 441            {
 442                // Parse all IPs with netmask to a subnet
 6443                var remoteAddressFilter = new List<IPNetwork>();
 6444                var remoteFilteredSubnets = remoteIPFilter.Where(x => x.Contains('/', StringComparison.OrdinalIgnoreCase
 6445                if (NetworkUtils.TryParseToSubnets(remoteFilteredSubnets, out var remoteAddressFilterResult, false))
 446                {
 0447                    remoteAddressFilter = remoteAddressFilterResult.Select(x => x.Subnet).ToList();
 448                }
 449
 450                // Parse everything else as an IP and construct subnet with a single IP
 6451                var remoteFilteredIPs = remoteIPFilter.Where(x => !x.Contains('/', StringComparison.OrdinalIgnoreCase));
 28452                foreach (var ip in remoteFilteredIPs)
 453                {
 8454                    if (IPAddress.TryParse(ip, out var ipp))
 455                    {
 8456                        remoteAddressFilter.Add(new IPNetwork(ipp, ipp.AddressFamily == AddressFamily.InterNetwork ? Net
 457                    }
 458                }
 459
 6460                _remoteAddressFilter = remoteAddressFilter;
 461            }
 79462        }
 79463    }
 464
 465    /// <summary>
 466    /// Parses the user defined overrides into the dictionary object.
 467    /// Overrides are the equivalent of localised publishedServerUrl, enabling
 468    /// different addresses to be advertised over different subnets.
 469    /// format is subnet=ipaddress|host|uri
 470    /// when subnet = 0.0.0.0, any external address matches.
 471    /// </summary>
 472    private void InitializeOverrides(NetworkConfiguration config)
 79473    {
 474        lock (_initLock)
 475        {
 79476            var publishedServerUrls = new List<PublishedServerUriOverride>();
 477
 478            // Prefer startup configuration.
 79479            var startupOverrideKey = _startupConfig[AddressOverrideKey];
 79480            if (!string.IsNullOrEmpty(startupOverrideKey))
 481            {
 0482                publishedServerUrls.Add(
 0483                    new PublishedServerUriOverride(
 0484                        new IPData(IPAddress.Any, NetworkConstants.IPv4Any),
 0485                        startupOverrideKey,
 0486                        true,
 0487                        true));
 0488                publishedServerUrls.Add(
 0489                    new PublishedServerUriOverride(
 0490                        new IPData(IPAddress.IPv6Any, NetworkConstants.IPv6Any),
 0491                        startupOverrideKey,
 0492                        true,
 0493                        true));
 0494                _publishedServerUrls = publishedServerUrls;
 0495                return;
 496            }
 497
 79498            var overrides = config.PublishedServerUriBySubnet;
 172499            foreach (var entry in overrides)
 500            {
 8501                var parts = entry.Split('=');
 8502                if (parts.Length != 2)
 503                {
 0504                    _logger.LogError("Unable to parse bind override: {Entry}", entry);
 0505                    return;
 506                }
 507
 8508                var replacement = parts[1].Trim();
 8509                var identifier = parts[0];
 8510                if (string.Equals(identifier, "all", StringComparison.OrdinalIgnoreCase))
 511                {
 512                    // Drop any other overrides in case an "all" override exists
 2513                    publishedServerUrls.Clear();
 2514                    publishedServerUrls.Add(
 2515                        new PublishedServerUriOverride(
 2516                            new IPData(IPAddress.Any, NetworkConstants.IPv4Any),
 2517                            replacement,
 2518                            true,
 2519                            true));
 2520                    publishedServerUrls.Add(
 2521                        new PublishedServerUriOverride(
 2522                            new IPData(IPAddress.IPv6Any, NetworkConstants.IPv6Any),
 2523                            replacement,
 2524                            true,
 2525                            true));
 2526                    break;
 527                }
 6528                else if (string.Equals(identifier, "external", StringComparison.OrdinalIgnoreCase))
 529                {
 4530                    publishedServerUrls.Add(
 4531                        new PublishedServerUriOverride(
 4532                            new IPData(IPAddress.Any, NetworkConstants.IPv4Any),
 4533                            replacement,
 4534                            false,
 4535                            true));
 4536                    publishedServerUrls.Add(
 4537                        new PublishedServerUriOverride(
 4538                            new IPData(IPAddress.IPv6Any, NetworkConstants.IPv6Any),
 4539                            replacement,
 4540                            false,
 4541                            true));
 542                }
 2543                else if (string.Equals(identifier, "internal", StringComparison.OrdinalIgnoreCase))
 544                {
 0545                    foreach (var lan in _lanSubnets)
 546                    {
 0547                        var lanPrefix = lan.BaseAddress;
 0548                        publishedServerUrls.Add(
 0549                            new PublishedServerUriOverride(
 0550                                new IPData(lanPrefix, new IPNetwork(lanPrefix, lan.PrefixLength)),
 0551                                replacement,
 0552                                true,
 0553                                false));
 554                    }
 555                }
 2556                else if (NetworkUtils.TryParseToSubnet(identifier, out var result))
 557                {
 1558                    publishedServerUrls.Add(
 1559                        new PublishedServerUriOverride(
 1560                            result,
 1561                            replacement,
 1562                            true,
 1563                            true));
 564                }
 1565                else if (TryParseInterface(identifier, out var ifaces))
 566                {
 4567                    foreach (var iface in ifaces)
 568                    {
 1569                        publishedServerUrls.Add(
 1570                            new PublishedServerUriOverride(
 1571                                iface,
 1572                                replacement,
 1573                                true,
 1574                                true));
 575                    }
 576                }
 577                else
 578                {
 0579                    _logger.LogError("Unable to parse bind override: {Entry}", entry);
 580                }
 581            }
 582
 79583            _publishedServerUrls = publishedServerUrls;
 79584        }
 79585    }
 586
 587    private void ConfigurationUpdated(object? sender, ConfigurationUpdateEventArgs evt)
 588    {
 22589        if (evt.Key.Equals(NetworkConfigurationStore.StoreKey, StringComparison.Ordinal))
 590        {
 0591            UpdateSettings((NetworkConfiguration)evt.NewConfiguration);
 592        }
 22593    }
 594
 595    /// <summary>
 596    /// Reloads all settings and re-Initializes the instance.
 597    /// </summary>
 598    /// <param name="configuration">The <see cref="NetworkConfiguration"/> to use.</param>
 599    [MemberNotNull(nameof(_lanSubnets), nameof(_excludedSubnets))]
 600    public void UpdateSettings(object configuration)
 601    {
 79602        ArgumentNullException.ThrowIfNull(configuration);
 603
 79604        var config = (NetworkConfiguration)configuration;
 79605        HappyEyeballs.HttpClientExtension.UseIPv6 = config.EnableIPv6;
 606
 79607        InitializeLan(config);
 79608        InitializeRemote(config);
 609
 79610        if (string.IsNullOrEmpty(MockNetworkSettings))
 611        {
 34612            InitializeInterfaces();
 613        }
 614        else // Used in testing only.
 615        {
 616            // Format is <IPAddress>,<Index>,<Name>: <next interface>. Set index to -ve to simulate a gateway.
 45617            var interfaceList = MockNetworkSettings.Split('|');
 45618            var interfaces = new List<IPData>();
 272619            foreach (var details in interfaceList)
 620            {
 91621                var parts = details.Split(',');
 91622                if (NetworkUtils.TryParseToSubnet(parts[0], out var data))
 623                {
 91624                    data.Index = int.Parse(parts[1], CultureInfo.InvariantCulture);
 91625                    if (data.AddressFamily == AddressFamily.InterNetwork || data.AddressFamily == AddressFamily.InterNet
 626                    {
 91627                        data.Name = parts[2];
 91628                        interfaces.Add(data);
 629                    }
 630                }
 631                else
 632                {
 0633                    _logger.LogWarning("Could not parse mock interface settings: {Part}", details);
 634                }
 635            }
 636
 45637            _interfaces = interfaces;
 638        }
 639
 79640        EnforceBindSettings(config);
 79641        InitializeOverrides(config);
 642
 79643        PrintNetworkInformation(config, false);
 79644    }
 645
 646    /// <summary>
 647    /// Protected implementation of Dispose pattern.
 648    /// </summary>
 649    /// <param name="disposing"><c>True</c> to dispose the managed state.</param>
 650    protected virtual void Dispose(bool disposing)
 651    {
 58652        if (!_disposed)
 653        {
 58654            if (disposing)
 655            {
 58656                _configurationManager.NamedConfigurationUpdated -= ConfigurationUpdated;
 58657                NetworkChange.NetworkAddressChanged -= OnNetworkAddressChanged;
 58658                NetworkChange.NetworkAvailabilityChanged -= OnNetworkAvailabilityChanged;
 659            }
 660
 58661            _disposed = true;
 662        }
 58663    }
 664
 665    /// <inheritdoc/>
 666    public bool TryParseInterface(string intf, [NotNullWhen(true)] out IReadOnlyList<IPData>? result)
 667    {
 15668        if (string.IsNullOrEmpty(intf)
 15669            || _interfaces is null
 15670            || _interfaces.Count == 0)
 671        {
 0672            result = null;
 0673            return false;
 674        }
 675
 676        // Match all interfaces starting with names starting with token
 15677        result = _interfaces
 15678            .Where(i => i.Name.Equals(intf, StringComparison.OrdinalIgnoreCase)
 15679                        && ((IsIPv4Enabled && i.Address.AddressFamily == AddressFamily.InterNetwork)
 15680                            || (IsIPv6Enabled && i.Address.AddressFamily == AddressFamily.InterNetworkV6)))
 15681            .OrderBy(x => x.Index)
 15682            .ToArray();
 15683        return result.Count > 0;
 684    }
 685
 686    /// <inheritdoc/>
 687    public RemoteAccessPolicyResult ShouldAllowServerAccess(IPAddress remoteIP)
 688    {
 9689        var config = _configurationManager.GetNetworkConfiguration();
 9690        if (IsInLocalNetwork(remoteIP))
 691        {
 1692            return RemoteAccessPolicyResult.Allow;
 693        }
 694
 8695        if (!config.EnableRemoteAccess)
 696        {
 697            // Remote not enabled. So everyone should be LAN.
 2698            return RemoteAccessPolicyResult.RejectDueToRemoteAccessDisabled;
 699        }
 700
 6701        if (!_remoteAddressFilter.Any())
 702        {
 703            // No filter on remote addresses, allow any of them.
 2704            return RemoteAccessPolicyResult.Allow;
 705        }
 706
 707        // Comma separated list of IP addresses or IP/netmask entries for networks that will be allowed to connect remot
 708        // If left blank, all remote addresses will be allowed.
 709
 710        // remoteAddressFilter is a whitelist or blacklist.
 4711        var anyMatches = _remoteAddressFilter.Any(remoteNetwork => NetworkUtils.SubnetContainsAddress(remoteNetwork, rem
 4712        if (config.IsRemoteIPFilterBlacklist)
 713        {
 2714            return anyMatches
 2715                ? RemoteAccessPolicyResult.RejectDueToIPBlocklist
 2716                : RemoteAccessPolicyResult.Allow;
 717        }
 718
 719        // Allow-list
 2720        return anyMatches
 2721            ? RemoteAccessPolicyResult.Allow
 2722            : RemoteAccessPolicyResult.RejectDueToNotAllowlistedRemoteIP;
 723    }
 724
 725    /// <inheritdoc/>
 726    public IReadOnlyList<IPData> GetLoopbacks()
 727    {
 0728        if (!IsIPv4Enabled && !IsIPv6Enabled)
 729        {
 0730            return Array.Empty<IPData>();
 731        }
 732
 0733        var loopbackNetworks = new List<IPData>();
 0734        if (IsIPv4Enabled)
 735        {
 0736            loopbackNetworks.Add(new IPData(IPAddress.Loopback, NetworkConstants.IPv4RFC5735Loopback, "lo"));
 737        }
 738
 0739        if (IsIPv6Enabled)
 740        {
 0741            loopbackNetworks.Add(new IPData(IPAddress.IPv6Loopback, NetworkConstants.IPv6RFC4291Loopback, "lo"));
 742        }
 743
 0744        return loopbackNetworks;
 745    }
 746
 747    /// <inheritdoc/>
 748    public IReadOnlyList<IPData> GetAllBindInterfaces(bool individualInterfaces = false)
 749    {
 21750        return NetworkManager.GetAllBindInterfaces(individualInterfaces, _configurationManager, _interfaces, IsIPv4Enabl
 751    }
 752
 753    /// <summary>
 754    /// Reads the jellyfin configuration of the configuration manager and produces a list of interfaces that should be b
 755    /// </summary>
 756    /// <param name="individualInterfaces">Defines that only known interfaces should be used.</param>
 757    /// <param name="configurationManager">The ConfigurationManager.</param>
 758    /// <param name="knownInterfaces">The known interfaces that gets returned if possible or instructed.</param>
 759    /// <param name="readIpv4">Include IPV4 type interfaces.</param>
 760    /// <param name="readIpv6">Include IPV6 type interfaces.</param>
 761    /// <returns>A list of ip address of which jellyfin should bind to.</returns>
 762    public static IReadOnlyList<IPData> GetAllBindInterfaces(
 763        bool individualInterfaces,
 764        IConfigurationManager configurationManager,
 765        IReadOnlyList<IPData> knownInterfaces,
 766        bool readIpv4,
 767        bool readIpv6)
 768    {
 21769        var config = configurationManager.GetNetworkConfiguration();
 21770        var localNetworkAddresses = config.LocalNetworkAddresses;
 21771        if ((localNetworkAddresses.Length > 0 && !string.IsNullOrWhiteSpace(localNetworkAddresses[0]) && knownInterfaces
 772        {
 0773            return knownInterfaces;
 774        }
 775
 776        // No bind address and no exclusions, so listen on all interfaces.
 21777        var result = new List<IPData>();
 21778        if (readIpv4 && readIpv6)
 779        {
 780            // Kestrel source code shows it uses Sockets.DualMode - so this also covers IPAddress.Any by default
 0781            result.Add(new IPData(IPAddress.IPv6Any, NetworkConstants.IPv6Any));
 782        }
 21783        else if (readIpv4)
 784        {
 21785            result.Add(new IPData(IPAddress.Any, NetworkConstants.IPv4Any));
 786        }
 0787        else if (readIpv6)
 788        {
 789            // Cannot use IPv6Any as Kestrel will bind to IPv4 addresses too.
 0790            foreach (var iface in knownInterfaces)
 791            {
 0792                if (iface.AddressFamily == AddressFamily.InterNetworkV6)
 793                {
 0794                    result.Add(iface);
 795                }
 796            }
 797        }
 798
 21799        return result;
 800    }
 801
 802    /// <inheritdoc/>
 803    public string GetBindAddress(string source, out int? port)
 804    {
 23805        if (!NetworkUtils.TryParseHost(source, out var addresses, IsIPv4Enabled, IsIPv6Enabled))
 806        {
 4807            addresses = Array.Empty<IPAddress>();
 808        }
 809
 23810        var result = GetBindAddress(addresses.FirstOrDefault(), out port);
 23811        return result;
 812    }
 813
 814    /// <inheritdoc/>
 815    public string GetBindAddress(HttpRequest source, out int? port)
 816    {
 0817        var result = GetBindAddress(source.Host.Host, out port);
 0818        port ??= source.Host.Port;
 819
 0820        return result;
 821    }
 822
 823    /// <inheritdoc/>
 824    public string GetBindAddress(IPAddress? source, out int? port, bool skipOverrides = false)
 825    {
 23826        port = null;
 827
 828        string result;
 829
 23830        if (source is not null)
 831        {
 19832            if (IsIPv4Enabled && !IsIPv6Enabled && source.AddressFamily == AddressFamily.InterNetworkV6)
 833            {
 0834                _logger.LogWarning("IPv6 is disabled in Jellyfin, but enabled in the OS. This may affect how the interfa
 835            }
 836
 19837            if (!IsIPv4Enabled && IsIPv6Enabled && source.AddressFamily == AddressFamily.InterNetwork)
 838            {
 0839                _logger.LogWarning("IPv4 is disabled in Jellyfin, but enabled in the OS. This may affect how the interfa
 840            }
 841
 19842            bool isExternal = !IsInLocalNetwork(source);
 19843            _logger.LogDebug("Trying to get bind address for source {Source} - External: {IsExternal}", source, isExtern
 844
 19845            if (!skipOverrides && MatchesPublishedServerUrl(source, isExternal, out result))
 846            {
 6847                return result;
 848            }
 849
 850            // No preference given, so move on to bind addresses.
 13851            if (MatchesBindInterface(source, isExternal, out result))
 852            {
 11853                return result;
 854            }
 855
 2856            if (isExternal && MatchesExternalInterface(source, out result))
 857            {
 0858                return result;
 859            }
 860        }
 861
 862        // Get the first LAN interface address that's not excluded and not a loopback address.
 863        // Get all available interfaces, prefer local interfaces
 6864        var availableInterfaces = _interfaces.Where(x => !IPAddress.IsLoopback(x.Address))
 6865            .OrderByDescending(x => IsInLocalNetwork(x.Address))
 6866            .ThenBy(x => x.Index)
 6867            .ToList();
 868
 6869        if (availableInterfaces.Count == 0)
 870        {
 871            // There isn't any others, so we'll use the loopback.
 0872            result = IsIPv4Enabled && !IsIPv6Enabled ? "127.0.0.1" : "::1";
 0873            _logger.LogWarning("{Source}: Only loopback {Result} returned, using that as bind address.", source, result)
 0874            return result;
 875        }
 876
 877        // If no source address is given, use the preferred (first) interface
 6878        if (source is null)
 879        {
 4880            result = NetworkUtils.FormatIPString(availableInterfaces.First().Address);
 4881            _logger.LogDebug("{Source}: Using first internal interface as bind address: {Result}", source, result);
 4882            return result;
 883        }
 884
 885        // Does the request originate in one of the interface subnets?
 886        // (For systems with multiple internal network cards, and multiple subnets)
 8887        foreach (var intf in availableInterfaces)
 888        {
 2889            if (NetworkUtils.SubnetContainsAddress(intf.Subnet, source))
 890            {
 0891                result = NetworkUtils.FormatIPString(intf.Address);
 0892                _logger.LogDebug("{Source}: Found interface with matching subnet, using it as bind address: {Result}", s
 0893                return result;
 894            }
 895        }
 896
 897        // Fallback to first available interface
 2898        result = NetworkUtils.FormatIPString(availableInterfaces[0].Address);
 2899        _logger.LogDebug("{Source}: No matching interfaces found, using preferred interface as bind address: {Result}", 
 2900        return result;
 0901    }
 902
 903    /// <inheritdoc/>
 904    public IReadOnlyList<IPData> GetInternalBindAddresses()
 905    {
 906        // Select all local bind addresses
 6907        return _interfaces.Where(x => IsInLocalNetwork(x.Address))
 6908            .OrderBy(x => x.Index)
 6909            .ToList();
 910    }
 911
 912    /// <inheritdoc/>
 913    public bool IsInLocalNetwork(string address)
 914    {
 0915        if (NetworkUtils.TryParseToSubnet(address, out var subnet))
 916        {
 0917            return IsInLocalNetwork(subnet.Address);
 918        }
 919
 0920        return NetworkUtils.TryParseHost(address, out var addresses, IsIPv4Enabled, IsIPv6Enabled)
 0921               && addresses.Any(IsInLocalNetwork);
 922    }
 923
 924    /// <summary>
 925    ///  Get if the IPAddress is Link-local.
 926    /// </summary>
 927    /// <param name="address">The IP Address.</param>
 928    /// <returns>Bool indicates if the address is link-local.</returns>
 929    public bool IsLinkLocalAddress(IPAddress address)
 930    {
 4931        ArgumentNullException.ThrowIfNull(address);
 4932        return NetworkConstants.IPv4RFC3927LinkLocal.Contains(address) || address.IsIPv6LinkLocal;
 933    }
 934
 935    /// <inheritdoc/>
 936    public bool IsInLocalNetwork(IPAddress address)
 937    {
 160938        ArgumentNullException.ThrowIfNull(address);
 939
 940        // Map IPv6 mapped IPv4 back to IPv4 (happens if Kestrel runs in dual-socket mode)
 160941        if (address.IsIPv4MappedToIPv6)
 942        {
 0943            address = address.MapToIPv4();
 944        }
 945
 160946        if ((TrustAllIPv6Interfaces && address.AddressFamily == AddressFamily.InterNetworkV6)
 160947            || IPAddress.IsLoopback(address))
 948        {
 84949            return true;
 950        }
 951
 952        // As private addresses can be redefined by Configuration.LocalNetworkAddresses
 76953        return CheckIfLanAndNotExcluded(address);
 954    }
 955
 956    /// <summary>
 957    /// Check if the address is in the LAN and not excluded.
 958    /// </summary>
 959    /// <param name="address">The IP address to check. The caller should make sure this is not an IPv4MappedToIPv6 addre
 960    /// <returns>Boolean indicates whether the address is in LAN.</returns>
 961    private bool CheckIfLanAndNotExcluded(IPAddress address)
 962    {
 416963        foreach (var lanSubnet in _lanSubnets)
 964        {
 151965            if (lanSubnet.Contains(address))
 966            {
 82967                foreach (var excludedSubnet in _excludedSubnets)
 968                {
 4969                    if (excludedSubnet.Contains(address))
 970                    {
 2971                        return false;
 972                    }
 973                }
 974
 36975                return true;
 976            }
 977        }
 978
 38979        return false;
 38980    }
 981
 982    /// <summary>
 983    /// Attempts to match the source against the published server URL overrides.
 984    /// </summary>
 985    /// <param name="source">IP source address to use.</param>
 986    /// <param name="isInExternalSubnet">True if the source is in an external subnet.</param>
 987    /// <param name="bindPreference">The published server URL that matches the source address.</param>
 988    /// <returns><c>true</c> if a match is found, <c>false</c> otherwise.</returns>
 989    private bool MatchesPublishedServerUrl(IPAddress source, bool isInExternalSubnet, out string bindPreference)
 990    {
 19991        bindPreference = string.Empty;
 19992        int? port = null;
 993
 994        // Only consider subnets including the source IP, preferring specific overrides
 995        List<PublishedServerUriOverride> validPublishedServerUrls;
 19996        if (!isInExternalSubnet)
 997        {
 998            // Only use matching internal subnets
 999            // Prefer more specific (bigger subnet prefix) overrides
 101000            validPublishedServerUrls = _publishedServerUrls.Where(x => x.IsInternalOverride && NetworkUtils.SubnetContai
 101001                .OrderByDescending(x => x.Data.Subnet.PrefixLength)
 101002                .ToList();
 1003        }
 1004        else
 1005        {
 1006            // Only use matching external subnets
 1007            // Prefer more specific (bigger subnet prefix) overrides
 91008            validPublishedServerUrls = _publishedServerUrls.Where(x => x.IsExternalOverride && NetworkUtils.SubnetContai
 91009                .OrderByDescending(x => x.Data.Subnet.PrefixLength)
 91010                .ToList();
 1011        }
 1012
 441013        foreach (var data in validPublishedServerUrls)
 1014        {
 1015            // Get interface matching override subnet
 61016            var intf = _interfaces.OrderBy(x => x.Index).FirstOrDefault(x => NetworkUtils.SubnetContainsAddress(data.Dat
 1017
 61018            if (intf?.Address is not null
 61019                || (data.Data.AddressFamily == AddressFamily.InterNetwork && data.Data.Address.Equals(IPAddress.Any))
 61020                || (data.Data.AddressFamily == AddressFamily.InterNetworkV6 && data.Data.Address.Equals(IPAddress.IPv6An
 1021            {
 1022                // If matching interface is found, use override
 61023                bindPreference = data.OverrideUri;
 61024                break;
 1025            }
 1026        }
 1027
 191028        if (string.IsNullOrEmpty(bindPreference))
 1029        {
 131030            _logger.LogDebug("{Source}: No matching bind address override found", source);
 131031            return false;
 1032        }
 1033
 1034        // Handle override specifying port
 61035        var parts = bindPreference.Split(':');
 61036        if (parts.Length > 1)
 1037        {
 51038            if (int.TryParse(parts[1], out int p))
 1039            {
 01040                bindPreference = parts[0];
 01041                port = p;
 01042                _logger.LogDebug("{Source}: Matching bind address override found: {Address}:{Port}", source, bindPrefere
 01043                return true;
 1044            }
 1045        }
 1046
 61047        _logger.LogDebug("{Source}: Matching bind address override found: {Address}", source, bindPreference);
 1048
 61049        return true;
 1050    }
 1051
 1052    /// <summary>
 1053    /// Attempts to match the source against the user defined bind interfaces.
 1054    /// </summary>
 1055    /// <param name="source">IP source address to use.</param>
 1056    /// <param name="isInExternalSubnet">True if the source is in the external subnet.</param>
 1057    /// <param name="result">The result, if a match is found.</param>
 1058    /// <returns><c>true</c> if a match is found, <c>false</c> otherwise.</returns>
 1059    private bool MatchesBindInterface(IPAddress source, bool isInExternalSubnet, out string result)
 1060    {
 131061        result = string.Empty;
 1062
 131063        int count = _interfaces.Count;
 131064        if (count == 1 && (_interfaces[0].Address.Equals(IPAddress.Any) || _interfaces[0].Address.Equals(IPAddress.IPv6A
 1065        {
 1066            // Ignore IPAny addresses.
 01067            count = 0;
 1068        }
 1069
 131070        if (count == 0)
 1071        {
 01072            return false;
 1073        }
 1074
 131075        IPAddress? bindAddress = null;
 131076        if (isInExternalSubnet)
 1077        {
 51078            var externalInterfaces = _interfaces.Where(x => !IsInLocalNetwork(x.Address))
 51079                .Where(x => !IsLinkLocalAddress(x.Address))
 51080                .OrderBy(x => x.Index)
 51081                .ToList();
 51082            if (externalInterfaces.Count > 0)
 1083            {
 1084                // Check to see if any of the external bind interfaces are in the same subnet as the source.
 1085                // If none exists, this will select the first external interface if there is one.
 41086                bindAddress = externalInterfaces
 41087                    .OrderByDescending(x => NetworkUtils.SubnetContainsAddress(x.Subnet, source))
 41088                    .ThenByDescending(x => x.Subnet.PrefixLength)
 41089                    .ThenBy(x => x.Index)
 41090                    .Select(x => x.Address)
 41091                    .First();
 1092
 41093                result = NetworkUtils.FormatIPString(bindAddress);
 41094                _logger.LogDebug("{Source}: External request received, matching external bind address found: {Result}", 
 41095                return true;
 1096            }
 1097
 11098            _logger.LogDebug("{Source}: External request received, no matching external bind address found, trying inter
 1099        }
 1100        else
 1101        {
 1102            // Check to see if any of the internal bind interfaces are in the same subnet as the source.
 1103            // If none exists, this will select the first internal interface if there is one.
 81104            bindAddress = _interfaces.Where(x => IsInLocalNetwork(x.Address))
 81105                .OrderByDescending(x => NetworkUtils.SubnetContainsAddress(x.Subnet, source))
 81106                .ThenByDescending(x => x.Subnet.PrefixLength)
 81107                .ThenBy(x => x.Index)
 81108                .Select(x => x.Address)
 81109                .FirstOrDefault();
 1110
 81111            if (bindAddress is not null)
 1112            {
 71113                result = NetworkUtils.FormatIPString(bindAddress);
 71114                _logger.LogDebug("{Source}: Internal request received, matching internal bind address found: {Result}", 
 71115                return true;
 1116            }
 1117        }
 1118
 21119        return false;
 1120    }
 1121
 1122    /// <summary>
 1123    /// Attempts to match the source against external interfaces.
 1124    /// </summary>
 1125    /// <param name="source">IP source address to use.</param>
 1126    /// <param name="result">The result, if a match is found.</param>
 1127    /// <returns><c>true</c> if a match is found, <c>false</c> otherwise.</returns>
 1128    private bool MatchesExternalInterface(IPAddress source, out string result)
 1129    {
 1130        // Get the first external interface address that isn't a loopback.
 11131        var extResult = _interfaces
 11132            .Where(p => !IsInLocalNetwork(p.Address))
 11133            .Where(p => p.Address.AddressFamily.Equals(source.AddressFamily))
 11134            .Where(p => !IsLinkLocalAddress(p.Address))
 11135            .OrderBy(x => x.Index).ToArray();
 1136
 1137        // No external interface found
 11138        if (extResult.Length == 0)
 1139        {
 11140            result = string.Empty;
 11141            _logger.LogDebug("{Source}: External request received, but no external interface found. Need to route throug
 11142            return false;
 1143        }
 1144
 1145        // Does the request originate in one of the interface subnets?
 1146        // (For systems with multiple network cards and/or multiple subnets)
 01147        foreach (var intf in extResult)
 1148        {
 01149            if (NetworkUtils.SubnetContainsAddress(intf.Subnet, source))
 1150            {
 01151                result = NetworkUtils.FormatIPString(intf.Address);
 01152                _logger.LogDebug("{Source}: Found external interface with matching subnet, using it as bind address: {Re
 01153                return true;
 1154            }
 1155        }
 1156
 1157        // Fallback to first external interface.
 01158        result = NetworkUtils.FormatIPString(extResult[0].Address);
 01159        _logger.LogDebug("{Source}: Using first external interface as bind address: {Result}", source, result);
 01160        return true;
 1161    }
 1162
 1163    private void PrintNetworkInformation(NetworkConfiguration config, bool debug = true)
 1164    {
 791165        var logLevel = debug ? LogLevel.Debug : LogLevel.Information;
 791166        if (_logger.IsEnabled(logLevel))
 1167        {
 211168            _logger.Log(logLevel, "Defined LAN subnets: {Subnets}", _lanSubnets.Select(s => s.BaseAddress + "/" + s.Pref
 211169            _logger.Log(logLevel, "Defined LAN exclusions: {Subnets}", _excludedSubnets.Select(s => s.BaseAddress + "/" 
 211170            _logger.Log(logLevel, "Used LAN subnets: {Subnets}", _lanSubnets.Where(s => !_excludedSubnets.Contains(s)).S
 211171            _logger.Log(logLevel, "Filtered interface addresses: {Addresses}", _interfaces.OrderByDescending(x => x.Addr
 211172            _logger.Log(logLevel, "Bind Addresses {Addresses}", GetAllBindInterfaces(false).OrderByDescending(x => x.Add
 211173            _logger.Log(logLevel, "Remote IP filter is {Type}", config.IsRemoteIPFilterBlacklist ? "Blocklist" : "Allowl
 211174            _logger.Log(logLevel, "Filtered subnets: {Subnets}", _remoteAddressFilter.Select(s => s.BaseAddress + "/" + 
 1175        }
 791176    }
 1177}

Methods/Properties

.ctor(MediaBrowser.Common.Configuration.IConfigurationManager,Microsoft.Extensions.Configuration.IConfiguration,Microsoft.Extensions.Logging.ILogger`1<Jellyfin.Networking.Manager.NetworkManager>)
.cctor()
get_IsIPv4Enabled()
get_IsIPv6Enabled()
get_PublishedServerUrls()
Dispose()
OnNetworkAvailabilityChanged(System.Object,System.Net.NetworkInformation.NetworkAvailabilityEventArgs)
OnNetworkAddressChanged(System.Object,System.EventArgs)
HandleNetworkChange()
OnNetworkChange()
InitializeInterfaces()
GetInterfacesCore(Microsoft.Extensions.Logging.ILogger,System.Boolean,System.Boolean)
InitializeLan(MediaBrowser.Common.Net.NetworkConfiguration)
EnforceBindSettings(MediaBrowser.Common.Net.NetworkConfiguration)
FilterBindSettings(MediaBrowser.Common.Net.NetworkConfiguration,System.Collections.Generic.IList`1<MediaBrowser.Model.Net.IPData>,System.Boolean,System.Boolean)
InitializeRemote(MediaBrowser.Common.Net.NetworkConfiguration)
InitializeOverrides(MediaBrowser.Common.Net.NetworkConfiguration)
ConfigurationUpdated(System.Object,MediaBrowser.Common.Configuration.ConfigurationUpdateEventArgs)
UpdateSettings(System.Object)
Dispose(System.Boolean)
TryParseInterface(System.String,System.Collections.Generic.IReadOnlyList`1<MediaBrowser.Model.Net.IPData>&)
ShouldAllowServerAccess(System.Net.IPAddress)
GetLoopbacks()
GetAllBindInterfaces(System.Boolean)
GetAllBindInterfaces(System.Boolean,MediaBrowser.Common.Configuration.IConfigurationManager,System.Collections.Generic.IReadOnlyList`1<MediaBrowser.Model.Net.IPData>,System.Boolean,System.Boolean)
GetBindAddress(System.String,System.Nullable`1<System.Int32>&)
GetBindAddress(Microsoft.AspNetCore.Http.HttpRequest,System.Nullable`1<System.Int32>&)
GetBindAddress(System.Net.IPAddress,System.Nullable`1<System.Int32>&,System.Boolean)
GetInternalBindAddresses()
IsInLocalNetwork(System.String)
IsLinkLocalAddress(System.Net.IPAddress)
IsInLocalNetwork(System.Net.IPAddress)
CheckIfLanAndNotExcluded(System.Net.IPAddress)
MatchesPublishedServerUrl(System.Net.IPAddress,System.Boolean,System.String&)
MatchesBindInterface(System.Net.IPAddress,System.Boolean,System.String&)
MatchesExternalInterface(System.Net.IPAddress,System.String&)
PrintNetworkInformation(MediaBrowser.Common.Net.NetworkConfiguration,System.Boolean)