fixed bug where urlacl wouldn't register if firewall port was already open.

pull/3113/head
kay.one 12 years ago
parent 8a6a64d104
commit 5730a67fb3

@ -0,0 +1,145 @@
using System;
using NLog;
using NetFwTypeLib;
namespace NzbDrone.Common
{
public interface IFirewallAdapter
{
void MakeAccessible();
bool IsNzbDronePortOpen();
}
public class FirewallAdapter : IFirewallAdapter
{
private readonly IConfigFileProvider _configFileProvider;
private readonly Logger _logger;
public FirewallAdapter(IConfigFileProvider configFileProvider, Logger logger)
{
_configFileProvider = configFileProvider;
_logger = logger;
}
public void MakeAccessible()
{
int port = 0;
if (IsFirewallEnabled())
{
if (IsNzbDronePortOpen())
{
_logger.Trace("NzbDrone port is already open, skipping.");
return;
}
CloseFirewallPort();
//Open the new port
OpenFirewallPort(_configFileProvider.Port);
}
}
public bool IsNzbDronePortOpen()
{
try
{
var netFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance(netFwMgrType);
if (!mgr.LocalPolicy.CurrentProfile.FirewallEnabled)
return false;
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
foreach (INetFwOpenPort p in ports)
{
if (p.Port == _configFileProvider.Port)
return true;
}
}
catch (Exception ex)
{
_logger.WarnException("Failed to check for open port in firewall", ex);
}
return false;
}
private void OpenFirewallPort(int portNumber)
{
try
{
var type = Type.GetTypeFromProgID("HNetCfg.FWOpenPort", false);
var port = Activator.CreateInstance(type) as INetFwOpenPort;
port.Port = portNumber;
port.Name = "NzbDrone";
port.Protocol = NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
port.Enabled = true;
var netFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance(netFwMgrType);
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
ports.Add(port);
}
catch (Exception ex)
{
_logger.WarnException("Failed to open port in firewall for NzbDrone " + portNumber, ex);
}
}
private int CloseFirewallPort()
{
try
{
var netFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance(netFwMgrType);
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
var portNumber = 8989;
foreach (INetFwOpenPort p in ports)
{
if (p.Name == "NzbDrone")
{
portNumber = p.Port;
break;
}
}
if (portNumber != _configFileProvider.Port)
{
ports.Remove(portNumber, NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
return portNumber;
}
}
catch (Exception ex)
{
_logger.WarnException("Failed to close port in firewall for NzbDrone", ex);
}
return 0;
}
private bool IsFirewallEnabled()
{
try
{
var netFwMgrType = Type.GetTypeFromProgID("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance(netFwMgrType);
return mgr.LocalPolicy.CurrentProfile.FirewallEnabled;
}
catch (Exception ex)
{
_logger.WarnException("Failed to check if the firewall is enabled", ex);
return false;
}
}
}
}

@ -2,12 +2,15 @@
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using System.Security.Principal;
using NLog;
namespace NzbDrone.Common namespace NzbDrone.Common
{ {
public interface IEnvironmentProvider public interface IEnvironmentProvider
{ {
bool IsUserInteractive { get; } bool IsUserInteractive { get; }
bool IsAdmin { get; }
string WorkingDirectory { get; } string WorkingDirectory { get; }
string SystemTemp { get; } string SystemTemp { get; }
Version Version { get; } Version Version { get; }
@ -18,10 +21,17 @@ namespace NzbDrone.Common
public class EnvironmentProvider : IEnvironmentProvider public class EnvironmentProvider : IEnvironmentProvider
{ {
private readonly Logger _logger;
private static readonly string ProcessName = Process.GetCurrentProcess().ProcessName.ToLower(); private static readonly string ProcessName = Process.GetCurrentProcess().ProcessName.ToLower();
private static readonly IEnvironmentProvider Instance = new EnvironmentProvider(); private static readonly IEnvironmentProvider Instance = new EnvironmentProvider();
public EnvironmentProvider()
{
_logger = LogManager.GetCurrentClassLogger();
}
public static bool IsProduction public static bool IsProduction
{ {
get get
@ -75,6 +85,23 @@ namespace NzbDrone.Common
get { return Environment.UserInteractive; } get { return Environment.UserInteractive; }
} }
public bool IsAdmin
{
get
{
try
{
var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
catch (Exception ex)
{
_logger.WarnException("Error checking if the current user is an administrator.", ex);
return false;
}
}
}
public virtual string WorkingDirectory public virtual string WorkingDirectory
{ {
get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NzbDrone"); } get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "NzbDrone"); }

@ -149,11 +149,12 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Properties\SharedAssemblyInfo.cs" /> <Compile Include="Properties\SharedAssemblyInfo.cs" />
<Compile Include="RestProvider.cs" /> <Compile Include="RestProvider.cs" />
<Compile Include="SecurityProvider.cs" /> <Compile Include="FirewallAdapter.cs" />
<Compile Include="IServiceProvider.cs" /> <Compile Include="IServiceProvider.cs" />
<Compile Include="TinyIoC.cs" /> <Compile Include="TinyIoC.cs" />
<Compile Include="TryParseExtension.cs" /> <Compile Include="TryParseExtension.cs" />
<Compile Include="UdpProvider.cs" /> <Compile Include="UdpProvider.cs" />
<Compile Include="UrlAclAdapter.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="packages.config"> <None Include="packages.config">

@ -1,253 +0,0 @@
using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using NLog;
#if __MonoCS__
#else
using NetFwTypeLib;
#endif
namespace NzbDrone.Common
{
public interface ISecurityProvider
{
void MakeAccessible();
bool IsCurrentUserAdmin();
bool IsNzbDronePortOpen();
bool IsNzbDroneUrlRegistered();
}
public class SecurityProvider : ISecurityProvider
{
private readonly IConfigFileProvider _configFileProvider;
private readonly IEnvironmentProvider _environmentProvider;
private readonly IProcessProvider _processProvider;
private readonly Logger _logger;
public SecurityProvider(IConfigFileProvider configFileProvider, IEnvironmentProvider environmentProvider,
IProcessProvider processProvider, Logger logger)
{
_configFileProvider = configFileProvider;
_environmentProvider = environmentProvider;
_processProvider = processProvider;
_logger = logger;
}
public void MakeAccessible()
{
if (!IsCurrentUserAdmin ())
{
_logger.Trace ("User is not an admin, skipping.");
return;
}
int port = 0;
if (IsFirewallEnabled ())
{
if (IsNzbDronePortOpen ())
{
_logger.Trace ("NzbDrone port is already open, skipping.");
return;
}
//Close any old ports
port = CloseFirewallPort ();
//Open the new port
OpenFirewallPort (_configFileProvider.Port);
}
//Skip Url Register if not Vista or 7
if (_environmentProvider.GetOsVersion ().Major < 6)
return;
//Unregister Url (if port != 0)
if (port != 0)
UnregisterUrl(port);
//Register Url
RegisterUrl(_configFileProvider.Port);
}
public bool IsCurrentUserAdmin()
{
try {
var principal = new WindowsPrincipal (WindowsIdentity.GetCurrent ());
return principal.IsInRole (WindowsBuiltInRole.Administrator);
} catch (Exception ex) {
_logger.WarnException ("Error checking if the current user is an administrator.", ex);
return false;
}
}
public bool IsNzbDronePortOpen()
{
#if __MonoCS__
#else
try {
var netFwMgrType = Type.GetTypeFromProgID ("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance (netFwMgrType);
if (!mgr.LocalPolicy.CurrentProfile.FirewallEnabled)
return false;
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
foreach (INetFwOpenPort p in ports) {
if (p.Port == _configFileProvider.Port)
return true;
}
}
catch (Exception ex) {
_logger.WarnException ("Failed to check for open port in firewall", ex);
}
#endif
return false;
}
public bool IsNzbDroneUrlRegistered()
{
return CheckIfUrlIsRegisteredUrl(_configFileProvider.Port);
}
private void OpenFirewallPort(int portNumber)
{
#if __MonoCS__
return true;
#else
try {
var type = Type.GetTypeFromProgID ("HNetCfg.FWOpenPort", false);
var port = Activator.CreateInstance (type) as INetFwOpenPort;
port.Port = portNumber;
port.Name = "NzbDrone";
port.Protocol = NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
port.Enabled = true;
var netFwMgrType = Type.GetTypeFromProgID ("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance (netFwMgrType);
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
ports.Add (port);
}
catch (Exception ex) {
_logger.WarnException ("Failed to open port in firewall for NzbDrone " + portNumber, ex);
}
#endif
}
private int CloseFirewallPort()
{
#if __MonoCS__
#else
try {
var netFwMgrType = Type.GetTypeFromProgID ("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance (netFwMgrType);
var ports = mgr.LocalPolicy.CurrentProfile.GloballyOpenPorts;
var portNumber = 8989;
foreach (INetFwOpenPort p in ports) {
if (p.Name == "NzbDrone") {
portNumber = p.Port;
break;
}
}
if (portNumber != _configFileProvider.Port)
{
ports.Remove (portNumber, NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP);
return portNumber;
}
}
catch (Exception ex)
{
_logger.WarnException ("Failed to close port in firewall for NzbDrone", ex);
}
#endif
return 0;
}
private bool IsFirewallEnabled()
{
#if __MonoCS__
return true;
#else
try {
var netFwMgrType = Type.GetTypeFromProgID ("HNetCfg.FwMgr", false);
var mgr = (INetFwMgr)Activator.CreateInstance (netFwMgrType);
return mgr.LocalPolicy.CurrentProfile.FirewallEnabled;
}
catch (Exception ex)
{
_logger.WarnException ("Failed to check if the firewall is enabled", ex);
return false;
}
#endif
}
private void RegisterUrl(int portNumber)
{
var arguments = String.Format("http add urlacl http://*:{0}/ user=EVERYONE", portNumber);
RunNetsh(arguments);
}
private void UnregisterUrl(int portNumber)
{
var arguments = String.Format("http delete urlacl http://*:{0}/", portNumber);
RunNetsh(arguments);
}
private bool CheckIfUrlIsRegisteredUrl(int portNumber)
{
var url = String.Format("http://*:{0}/", portNumber);
var arguments = String.Format("http show urlacl url=\"{0}\"", url);
var output = RunNetsh(arguments);
if(String.IsNullOrWhiteSpace(output))
{
_logger.Error("netsh output is invalid for arguments: {0}", arguments);
}
if(!output.Contains(url))
{
_logger.Trace("Url has not already been registered");
return false;
}
_logger.Trace("Url has already been registered!");
return true;
}
private string RunNetsh(string arguments)
{
try
{
var startInfo = new ProcessStartInfo()
{
RedirectStandardOutput = true,
UseShellExecute = false,
FileName = "netsh.exe",
Arguments = arguments
};
var process = _processProvider.Start(startInfo);
process.WaitForExit(5000);
return process.StandardOutput.ReadToEnd();
}
catch (Exception ex)
{
_logger.WarnException("Error executing netsh with arguments: " + arguments, ex);
}
return null;
}
}
}

@ -0,0 +1,66 @@
using System;
using System.Diagnostics;
using NLog;
namespace NzbDrone.Common
{
public interface IUrlAclAdapter
{
void RefreshRegistration();
}
public class UrlAclAdapter : IUrlAclAdapter
{
private readonly IProcessProvider _processProvider;
private readonly IConfigFileProvider _configFileProvider;
private readonly IEnvironmentProvider _environmentProvider;
private readonly Logger _logger;
public UrlAclAdapter(IProcessProvider processProvider, IConfigFileProvider configFileProvider, IEnvironmentProvider environmentProvider, Logger logger)
{
_processProvider = processProvider;
_configFileProvider = configFileProvider;
_environmentProvider = environmentProvider;
_logger = logger;
}
public void RefreshRegistration()
{
if (_environmentProvider.GetOsVersion().Major < 6)
return;
RegisterUrl(_configFileProvider.Port);
}
private void RegisterUrl(int portNumber)
{
var arguments = String.Format("http add urlacl http://*:{0}/ user=EVERYONE", portNumber);
RunNetsh(arguments);
}
private string RunNetsh(string arguments)
{
try
{
var startInfo = new ProcessStartInfo()
{
RedirectStandardOutput = true,
UseShellExecute = false,
FileName = "netsh.exe",
Arguments = arguments
};
var process = _processProvider.Start(startInfo);
process.WaitForExit(5000);
return process.StandardOutput.ReadToEnd();
}
catch (Exception ex)
{
_logger.WarnException("Error executing netsh with arguments: " + arguments, ex);
}
return null;
}
}
}

@ -76,6 +76,7 @@
<None Include="app.config" /> <None Include="app.config" />
<Content Include="NLog.config"> <Content Include="NLog.config">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
<SubType>Designer</SubType>
</Content> </Content>
<None Include="NLog.xsd"> <None Include="NLog.xsd">
<SubType>Designer</SubType> <SubType>Designer</SubType>

@ -19,20 +19,22 @@ namespace NzbDrone
private readonly IHostController _hostController; private readonly IHostController _hostController;
private readonly IProcessProvider _processProvider; private readonly IProcessProvider _processProvider;
private readonly PriorityMonitor _priorityMonitor; private readonly PriorityMonitor _priorityMonitor;
private readonly SecurityProvider _securityProvider; private readonly IFirewallAdapter _firewallAdapter;
private readonly IUrlAclAdapter _urlAclAdapter;
private readonly Logger _logger; private readonly Logger _logger;
public NzbDroneServiceFactory(IConfigFileProvider configFileProvider, IHostController hostController, public NzbDroneServiceFactory(IConfigFileProvider configFileProvider, IHostController hostController,
IEnvironmentProvider environmentProvider, IEnvironmentProvider environmentProvider,
IProcessProvider processProvider, PriorityMonitor priorityMonitor, IProcessProvider processProvider, PriorityMonitor priorityMonitor,
SecurityProvider securityProvider, Logger logger) IFirewallAdapter firewallAdapter, IUrlAclAdapter urlAclAdapter, Logger logger)
{ {
_configFileProvider = configFileProvider; _configFileProvider = configFileProvider;
_hostController = hostController; _hostController = hostController;
_environmentProvider = environmentProvider; _environmentProvider = environmentProvider;
_processProvider = processProvider; _processProvider = processProvider;
_priorityMonitor = priorityMonitor; _priorityMonitor = priorityMonitor;
_securityProvider = securityProvider; _firewallAdapter = firewallAdapter;
_urlAclAdapter = urlAclAdapter;
_logger = logger; _logger = logger;
} }
@ -43,8 +45,12 @@ namespace NzbDrone
public void Start() public void Start()
{ {
_securityProvider.MakeAccessible(); if (_environmentProvider.IsAdmin)
{
_urlAclAdapter.RefreshRegistration();
_firewallAdapter.MakeAccessible();
}
_hostController.StartServer(); _hostController.StartServer();
if (_environmentProvider.IsUserInteractive && _configFileProvider.LaunchBrowser) if (_environmentProvider.IsUserInteractive && _configFileProvider.LaunchBrowser)

@ -138,7 +138,7 @@
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="MainAppContainerBuilder.cs" /> <Compile Include="MainAppContainerBuilder.cs" />
<Compile Include="ApplicationMode.cs" /> <Compile Include="ApplicationModes.cs" />
<Compile Include="AppMain.cs" /> <Compile Include="AppMain.cs" />
<Compile Include="Owin\MiddleWare\NancyMiddleWare.cs" /> <Compile Include="Owin\MiddleWare\NancyMiddleWare.cs" />
<Compile Include="Owin\IHostController.cs" /> <Compile Include="Owin\IHostController.cs" />

Loading…
Cancel
Save