瀏覽代碼

Enforce interface bindings on SSDP, add Loopback to LAN if no LAN defined

Shadowghost 2 年之前
父節點
當前提交
f6e41269d9

+ 1 - 6
Emby.Dlna/Main/DlnaEntryPoint.cs

@@ -284,6 +284,7 @@ namespace Emby.Dlna.Main
             var udn = CreateUuid(_appHost.SystemId);
             var descriptorUri = "/dlna/" + udn + "/description.xml";
 
+            // Only get bind addresses in LAN
             var bindAddresses = _networkManager
                 .GetInternalBindAddresses()
                 .Where(i => i.Address.AddressFamily == AddressFamily.InterNetwork
@@ -304,12 +305,6 @@ namespace Emby.Dlna.Main
                     continue;
                 }
 
-                // Limit to LAN addresses only
-                if (!_networkManager.IsInLocalNetwork(address.Address))
-                {
-                    continue;
-                }
-
                 var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
 
                 _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address);

+ 8 - 5
Emby.Server.Implementations/Net/SocketFactory.cs

@@ -61,13 +61,18 @@ namespace Emby.Server.Implementations.Net
         }
 
         /// <inheritdoc />
-        public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort)
+        public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, IPAddress bindIpAddress, int multicastTimeToLive, int localPort)
         {
             if (ipAddress == null)
             {
                 throw new ArgumentNullException(nameof(ipAddress));
             }
 
+            if (bindIpAddress == null)
+            {
+                bindIpAddress = IPAddress.Any;
+            }
+
             if (multicastTimeToLive <= 0)
             {
                 throw new ArgumentException("multicastTimeToLive cannot be zero or less.", nameof(multicastTimeToLive));
@@ -98,12 +103,10 @@ namespace Emby.Server.Implementations.Net
                 // retVal.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true);
                 retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
 
-                var localIp = IPAddress.Any;
-
-                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, localIp));
+                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, bindIpAddress));
                 retVal.MulticastLoopback = true;
 
-                return new UdpSocket(retVal, localPort, localIp);
+                return new UdpSocket(retVal, localPort, bindIpAddress);
             }
             catch
             {

+ 10 - 6
Jellyfin.Networking/Manager/NetworkManager.cs

@@ -298,20 +298,22 @@ namespace Jellyfin.Networking.Manager
 
                 if (_lanSubnets.Count == 0)
                 {
-                    // If no LAN addresses are specified, all private subnets are deemed to be the LAN
+                    // If no LAN addresses are specified, all private subnets and Loopback are deemed to be the LAN
                     _logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
 
                     if (IsIpv6Enabled)
                     {
-                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7)); // ULA
-                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10)); // Site local
+                        _lanSubnets.Add(new IPNetwork(IPAddress.IPv6Loopback, 128)); // RFC 4291 (Loopback)
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10)); // RFC 4291 (Site local)
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7)); // RFC 4193 (Unique local)
                     }
 
                     if (IsIpv4Enabled)
                     {
-                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
-                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
-                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Loopback, 8)); // RFC 5735 (Loopback)
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8)); // RFC 1918 (private)
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12)); // RFC 1918 (private)
+                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16)); // RFC 1918 (private)
                     }
                 }
 
@@ -371,11 +373,13 @@ namespace Jellyfin.Networking.Manager
                     }
                 }
 
+                // Remove all IPv4 interfaces if IPv4 is disabled
                 if (!IsIpv4Enabled)
                 {
                     _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
                 }
 
+                // Remove all IPv6 interfaces if IPv6 is disabled
                 if (!IsIpv6Enabled)
                 {
                     _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);

+ 3 - 1
MediaBrowser.Model/Net/ISocketFactory.cs

@@ -1,5 +1,6 @@
 #pragma warning disable CS1591
 
+using System.Collections.Generic;
 using System.Net;
 
 namespace MediaBrowser.Model.Net
@@ -23,9 +24,10 @@ namespace MediaBrowser.Model.Net
         /// Creates a new multicast socket using the specified multicast IP address, multicast time to live and local port.
         /// </summary>
         /// <param name="ipAddress">The multicast IP address to bind to.</param>
+        /// <param name="bindIpAddress">The bind IP address.</param>
         /// <param name="multicastTimeToLive">The multicast time to live value. Actually a maximum number of network hops for UDP packets.</param>
         /// <param name="localPort">The local port to bind to.</param>
         /// <returns>A <see cref="ISocket"/> implementation.</returns>
-        ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort);
+        ISocket CreateUdpMulticastSocket(IPAddress ipAddress, IPAddress bindIpAddress, int multicastTimeToLive, int localPort);
     }
 }

+ 52 - 23
RSSDP/SsdpCommunicationsServer.cs

@@ -33,7 +33,7 @@ namespace Rssdp.Infrastructure
          */
 
         private object _BroadcastListenSocketSynchroniser = new object();
-        private ISocket _BroadcastListenSocket;
+        private List<ISocket> _BroadcastListenSockets;
 
         private object _SendSocketSynchroniser = new object();
         private List<ISocket> _sendSockets;
@@ -111,24 +111,21 @@ namespace Rssdp.Infrastructure
         {
             ThrowIfDisposed();
 
-            if (_BroadcastListenSocket == null)
+            lock (_BroadcastListenSocketSynchroniser)
             {
-                lock (_BroadcastListenSocketSynchroniser)
+                if (_BroadcastListenSockets == null)
                 {
-                    if (_BroadcastListenSocket == null)
+                    try
+                    {
+                        _BroadcastListenSockets = ListenForBroadcastsAsync();
+                    }
+                    catch (SocketException ex)
+                    {
+                        _logger.LogError("Failed to bind to port 1900: {Message}. DLNA will be unavailable", ex.Message);
+                    }
+                    catch (Exception ex)
                     {
-                        try
-                        {
-                            _BroadcastListenSocket = ListenForBroadcastsAsync();
-                        }
-                        catch (SocketException ex)
-                        {
-                            _logger.LogError("Failed to bind to port 1900: {Message}. DLNA will be unavailable", ex.Message);
-                        }
-                        catch (Exception ex)
-                        {
-                            _logger.LogError(ex, "Error in BeginListeningForBroadcasts");
-                        }
+                        _logger.LogError(ex, "Error in BeginListeningForBroadcasts");
                     }
                 }
             }
@@ -142,11 +139,15 @@ namespace Rssdp.Infrastructure
         {
             lock (_BroadcastListenSocketSynchroniser)
             {
-                if (_BroadcastListenSocket != null)
+                if (_BroadcastListenSockets != null)
                 {
                     _logger.LogInformation("{0} disposing _BroadcastListenSocket", GetType().Name);
-                    _BroadcastListenSocket.Dispose();
-                    _BroadcastListenSocket = null;
+                    foreach (var socket in _BroadcastListenSockets)
+                    {
+                        socket.Dispose();
+                    }
+
+                    _BroadcastListenSockets = null;
                 }
             }
         }
@@ -336,12 +337,40 @@ namespace Rssdp.Infrastructure
             return Task.CompletedTask;
         }
 
-        private ISocket ListenForBroadcastsAsync()
+        private List<ISocket> ListenForBroadcastsAsync()
         {
-            var socket = _SocketFactory.CreateUdpMulticastSocket(IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress), _MulticastTtl, SsdpConstants.MulticastPort);
-            _ = ListenToSocketInternal(socket);
+            var sockets = new List<ISocket>();
+            if (_enableMultiSocketBinding)
+            {
+                foreach (var address in _networkManager.GetInternalBindAddresses())
+                {
+                    if (address.AddressFamily == AddressFamily.InterNetworkV6)
+                    {
+                        // Not support IPv6 right now
+                        continue;
+                    }
 
-            return socket;
+                    try
+                    {
+                        sockets.Add(_SocketFactory.CreateUdpMulticastSocket(IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress), address.Address, _MulticastTtl, SsdpConstants.MulticastPort));
+                    }
+                    catch (Exception ex)
+                    {
+                        _logger.LogError(ex, "Error in ListenForBroadcastsAsync. IPAddress: {0}", address);
+                    }
+                }
+            }
+            else
+            {
+                sockets.Add(_SocketFactory.CreateUdpMulticastSocket(IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress), IPAddress.Any, _MulticastTtl, SsdpConstants.MulticastPort));
+            }
+
+            foreach (var socket in sockets)
+            {
+                _ = ListenToSocketInternal(socket);
+            }
+
+            return sockets;
         }
 
         private List<ISocket> CreateSocketAndListenForResponsesAsync()