mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	Enforce interface bindings on SSDP, add Loopback to LAN if no LAN defined
This commit is contained in:
		
							parent
							
								
									05458a4a42
								
							
						
					
					
						commit
						f6e41269d9
					
				@ -284,6 +284,7 @@ namespace Emby.Dlna.Main
 | 
				
			|||||||
            var udn = CreateUuid(_appHost.SystemId);
 | 
					            var udn = CreateUuid(_appHost.SystemId);
 | 
				
			||||||
            var descriptorUri = "/dlna/" + udn + "/description.xml";
 | 
					            var descriptorUri = "/dlna/" + udn + "/description.xml";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Only get bind addresses in LAN
 | 
				
			||||||
            var bindAddresses = _networkManager
 | 
					            var bindAddresses = _networkManager
 | 
				
			||||||
                .GetInternalBindAddresses()
 | 
					                .GetInternalBindAddresses()
 | 
				
			||||||
                .Where(i => i.Address.AddressFamily == AddressFamily.InterNetwork
 | 
					                .Where(i => i.Address.AddressFamily == AddressFamily.InterNetwork
 | 
				
			||||||
@ -304,12 +305,6 @@ namespace Emby.Dlna.Main
 | 
				
			|||||||
                    continue;
 | 
					                    continue;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Limit to LAN addresses only
 | 
					 | 
				
			||||||
                if (!_networkManager.IsInLocalNetwork(address.Address))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
 | 
					                var fullService = "urn:schemas-upnp-org:device:MediaServer:1";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address);
 | 
					                _logger.LogInformation("Registering publisher for {ResourceName} on {DeviceAddress}", fullService, address);
 | 
				
			||||||
 | 
				
			|||||||
@ -61,13 +61,18 @@ namespace Emby.Server.Implementations.Net
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /// <inheritdoc />
 | 
					        /// <inheritdoc />
 | 
				
			||||||
        public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, int multicastTimeToLive, int localPort)
 | 
					        public ISocket CreateUdpMulticastSocket(IPAddress ipAddress, IPAddress bindIpAddress, int multicastTimeToLive, int localPort)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            if (ipAddress == null)
 | 
					            if (ipAddress == null)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                throw new ArgumentNullException(nameof(ipAddress));
 | 
					                throw new ArgumentNullException(nameof(ipAddress));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (bindIpAddress == null)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                bindIpAddress = IPAddress.Any;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (multicastTimeToLive <= 0)
 | 
					            if (multicastTimeToLive <= 0)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                throw new ArgumentException("multicastTimeToLive cannot be zero or less.", nameof(multicastTimeToLive));
 | 
					                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.Socket, SocketOptionName.Broadcast, true);
 | 
				
			||||||
                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
 | 
					                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, multicastTimeToLive);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                var localIp = IPAddress.Any;
 | 
					                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, bindIpAddress));
 | 
				
			||||||
 | 
					 | 
				
			||||||
                retVal.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ipAddress, localIp));
 | 
					 | 
				
			||||||
                retVal.MulticastLoopback = true;
 | 
					                retVal.MulticastLoopback = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                return new UdpSocket(retVal, localPort, localIp);
 | 
					                return new UdpSocket(retVal, localPort, bindIpAddress);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            catch
 | 
					            catch
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
 | 
				
			|||||||
@ -298,20 +298,22 @@ namespace Jellyfin.Networking.Manager
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                if (_lanSubnets.Count == 0)
 | 
					                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.");
 | 
					                    _logger.LogDebug("Using LAN interface addresses as user provided no LAN details.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (IsIpv6Enabled)
 | 
					                    if (IsIpv6Enabled)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fc00::"), 7)); // ULA
 | 
					                        _lanSubnets.Add(new IPNetwork(IPAddress.IPv6Loopback, 128)); // RFC 4291 (Loopback)
 | 
				
			||||||
                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("fe80::"), 10)); // Site local
 | 
					                        _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)
 | 
					                    if (IsIpv4Enabled)
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8));
 | 
					                        _lanSubnets.Add(new IPNetwork(IPAddress.Loopback, 8)); // RFC 5735 (Loopback)
 | 
				
			||||||
                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("172.16.0.0"), 12));
 | 
					                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("10.0.0.0"), 8)); // RFC 1918 (private)
 | 
				
			||||||
                        _lanSubnets.Add(new IPNetwork(IPAddress.Parse("192.168.0.0"), 16));
 | 
					                        _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)
 | 
					                if (!IsIpv4Enabled)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
 | 
					                    _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetwork);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Remove all IPv6 interfaces if IPv6 is disabled
 | 
				
			||||||
                if (!IsIpv6Enabled)
 | 
					                if (!IsIpv6Enabled)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);
 | 
					                    _interfaces.RemoveAll(x => x.AddressFamily == AddressFamily.InterNetworkV6);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
#pragma warning disable CS1591
 | 
					#pragma warning disable CS1591
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Net;
 | 
					using System.Net;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MediaBrowser.Model.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.
 | 
					        /// Creates a new multicast socket using the specified multicast IP address, multicast time to live and local port.
 | 
				
			||||||
        /// </summary>
 | 
					        /// </summary>
 | 
				
			||||||
        /// <param name="ipAddress">The multicast IP address to bind to.</param>
 | 
					        /// <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="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>
 | 
					        /// <param name="localPort">The local port to bind to.</param>
 | 
				
			||||||
        /// <returns>A <see cref="ISocket"/> implementation.</returns>
 | 
					        /// <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);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -33,7 +33,7 @@ namespace Rssdp.Infrastructure
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private object _BroadcastListenSocketSynchroniser = new object();
 | 
					        private object _BroadcastListenSocketSynchroniser = new object();
 | 
				
			||||||
        private ISocket _BroadcastListenSocket;
 | 
					        private List<ISocket> _BroadcastListenSockets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private object _SendSocketSynchroniser = new object();
 | 
					        private object _SendSocketSynchroniser = new object();
 | 
				
			||||||
        private List<ISocket> _sendSockets;
 | 
					        private List<ISocket> _sendSockets;
 | 
				
			||||||
@ -111,24 +111,21 @@ namespace Rssdp.Infrastructure
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            ThrowIfDisposed();
 | 
					            ThrowIfDisposed();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (_BroadcastListenSocket == null)
 | 
					            lock (_BroadcastListenSocketSynchroniser)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                lock (_BroadcastListenSocketSynchroniser)
 | 
					                if (_BroadcastListenSockets == null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    if (_BroadcastListenSocket == null)
 | 
					                    try
 | 
				
			||||||
                    {
 | 
					                    {
 | 
				
			||||||
                        try
 | 
					                        _BroadcastListenSockets = ListenForBroadcastsAsync();
 | 
				
			||||||
                        {
 | 
					                    }
 | 
				
			||||||
                            _BroadcastListenSocket = ListenForBroadcastsAsync();
 | 
					                    catch (SocketException ex)
 | 
				
			||||||
                        }
 | 
					                    {
 | 
				
			||||||
                        catch (SocketException ex)
 | 
					                        _logger.LogError("Failed to bind to port 1900: {Message}. DLNA will be unavailable", ex.Message);
 | 
				
			||||||
                        {
 | 
					                    }
 | 
				
			||||||
                            _logger.LogError("Failed to bind to port 1900: {Message}. DLNA will be unavailable", ex.Message);
 | 
					                    catch (Exception ex)
 | 
				
			||||||
                        }
 | 
					                    {
 | 
				
			||||||
                        catch (Exception ex)
 | 
					                        _logger.LogError(ex, "Error in BeginListeningForBroadcasts");
 | 
				
			||||||
                        {
 | 
					 | 
				
			||||||
                            _logger.LogError(ex, "Error in BeginListeningForBroadcasts");
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -142,11 +139,15 @@ namespace Rssdp.Infrastructure
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            lock (_BroadcastListenSocketSynchroniser)
 | 
					            lock (_BroadcastListenSocketSynchroniser)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                if (_BroadcastListenSocket != null)
 | 
					                if (_BroadcastListenSockets != null)
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    _logger.LogInformation("{0} disposing _BroadcastListenSocket", GetType().Name);
 | 
					                    _logger.LogInformation("{0} disposing _BroadcastListenSocket", GetType().Name);
 | 
				
			||||||
                    _BroadcastListenSocket.Dispose();
 | 
					                    foreach (var socket in _BroadcastListenSockets)
 | 
				
			||||||
                    _BroadcastListenSocket = null;
 | 
					                    {
 | 
				
			||||||
 | 
					                        socket.Dispose();
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    _BroadcastListenSockets = null;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -336,12 +337,40 @@ namespace Rssdp.Infrastructure
 | 
				
			|||||||
            return Task.CompletedTask;
 | 
					            return Task.CompletedTask;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private ISocket ListenForBroadcastsAsync()
 | 
					        private List<ISocket> ListenForBroadcastsAsync()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            var socket = _SocketFactory.CreateUdpMulticastSocket(IPAddress.Parse(SsdpConstants.MulticastLocalAdminAddress), _MulticastTtl, SsdpConstants.MulticastPort);
 | 
					            var sockets = new List<ISocket>();
 | 
				
			||||||
            _ = ListenToSocketInternal(socket);
 | 
					            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()
 | 
					        private List<ISocket> CreateSocketAndListenForResponsesAsync()
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user