I have a c# .NET app that receives TCP and UDP streams from other devices on the network.
When I run it as console app, the Windows Firewall prompts me: "Windows Firewall has blocked some features of this program" and it ask me to allow vshost32.exe to communicate on the network.
I agree and the app works fine.
However when I run the app as a service (I have a separate console and service wrappers) I get no such prompt and I can only get it to work if switch off the firewall.
Is this expected for services? ()
Also, I have read some code snippets that suggest you can manually add exceptions to Windows Firewall list. Is this just for console apps or will it work for services also?
Some my code that listens on the ports in case this is usefull...
//
// Setup UDP listening
//
if (protocol == "UDP")
{
m_udp = new UdpConn("RedwallReceiver UDP", m_local, new NetAddress());
m_udp.Receive(new VDataHandler(ReceiveData));
}
//
// Setup TCP listening
//
if (protocol == "TCP")
{
m_listener = new TcpListener(m_local);
m_listener.Start();
m_listener.BeginAcceptSocket(AcceptSocket, null);
}
Services execute under restricted environments and are allowed to have very little or no interaction with the UI. His answer covers all the reasoning and here is how to achieve the same.
I would recommend adding an additional project to your solution (let's call it Configurator) which can be launched as part of the installation process. As far as I remember, adding a rule to the firewall requires administrative privileges. Here are the steps:
- Create the
Configurator
project as a Console or WinForms application. No UI is needed here.
- Add an application manifest file to the
Configurator
project. right-click project, Add > New Item > Application Manifest File. Change the <requestedExecutionLevel>
tag to read <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
.
- Add the output of the
Configurator
project to your setup/deployment project.
- Select the deployment project and navigate to the
Custom Actions
tab. Add a new custom action under the Commit
node and make it point to the output of the Configurator
project.
- In the
Configurator
project, add a reference to NetFwTypeLib
from COM references.
- Add the code below to the
Configurator
project.
Modify the Main
method of the Configurator
project to return an int (0 for success, non-zero for failure) and use the following code. Note that I've pasted this from my project directly so you may need to fix some decleration errors, etc.
private static int Main (string [] args)
{
var application = new NetFwAuthorizedApplication()
{
Name = "MyService",
Enabled = true,
RemoteAddresses = "*",
Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL,
IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY,
ProcessImageFileName = "ServiceAssemblyName.dll",
};
return (FirewallUtilities.AddApplication(application, out exception) ? 0 : -1);
}
namespace MySolution.Configurator.Firewall
{
using System;
using System.Linq;
using NetFwTypeLib;
public sealed class NetFwAuthorizedApplication:
INetFwAuthorizedApplication
{
public string Name { get; set; }
public bool Enabled { get; set; }
public NET_FW_SCOPE_ Scope { get; set; }
public string RemoteAddresses { get; set; }
public string ProcessImageFileName { get; set; }
public NET_FW_IP_VERSION_ IpVersion { get; set; }
public NetFwAuthorizedApplication ()
{
this.Name = "";
this.Enabled = false;
this.RemoteAddresses = "";
this.ProcessImageFileName = "";
this.Scope = NET_FW_SCOPE_.NET_FW_SCOPE_ALL;
this.IpVersion = NET_FW_IP_VERSION_.NET_FW_IP_VERSION_ANY;
}
public NetFwAuthorizedApplication (string name, bool enabled, string remoteAddresses, NET_FW_SCOPE_ scope, NET_FW_IP_VERSION_ ipVersion, string processImageFileName)
{
this.Name = name;
this.Scope = scope;
this.Enabled = enabled;
this.IpVersion = ipVersion;
this.RemoteAddresses = remoteAddresses;
this.ProcessImageFileName = processImageFileName;
}
public static NetFwAuthorizedApplication FromINetFwAuthorizedApplication (INetFwAuthorizedApplication application)
{
return (new NetFwAuthorizedApplication(application.Name, application.Enabled, application.RemoteAddresses, application.Scope, application.IpVersion, application.ProcessImageFileName));
}
}
}
namespace MySolution.Configurator.Firewall
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using NetFwTypeLib;
public static class FirewallUtilities
{
public static bool GetApplication (string processImageFileName, out INetFwAuthorizedApplication application, out Exception exception)
{
var result = false;
var comObjects = new Stack<object>();
exception = null;
application = null;
if (processImageFileName == null) { throw (new ArgumentNullException("processImageFileName")); }
if (processImageFileName.Trim().Length == 0) { throw (new ArgumentException("The argument [processImageFileName] cannot be empty.", "processImageFileName")); }
try
{
var type = Type.GetTypeFromProgID("HNetCfg.FwMgr", true);
try
{
var manager = (INetFwMgr) Activator.CreateInstance(type);
comObjects.Push(manager);
try
{
var policy = manager.LocalPolicy;
comObjects.Push(policy);
var profile = policy.CurrentProfile;
comObjects.Push(profile);
var applications = profile.AuthorizedApplications;
comObjects.Push(applications);
foreach (INetFwAuthorizedApplication app in applications)
{
comObjects.Push(app);
if (string.Compare(app.ProcessImageFileName, processImageFileName, true, CultureInfo.InvariantCulture) == 0)
{
result = true;
application = NetFwAuthorizedApplication.FromINetFwAuthorizedApplication(app);
break;
}
}
if (!result) { throw (new Exception("The requested application was not found.")); }
}
catch (Exception e)
{
exception = e;
}
}
catch (Exception e)
{
exception = e;
}
finally
{
while (comObjects.Count > 0)
{
ComUtilities.ReleaseComObject(comObjects.Pop());
}
}
}
catch (Exception e)
{
exception = e;
}
finally
{
}
return (result);
}
public static bool AddApplication (INetFwAuthorizedApplication application, out Exception exception)
{
var result = false;
var comObjects = new Stack<object>();
exception = null;
if (application == null) { throw (new ArgumentNullException("application")); }
try
{
var type = Type.GetTypeFromProgID("HNetCfg.FwMgr", true);
try
{
var manager = (INetFwMgr) Activator.CreateInstance(type);
comObjects.Push(manager);
try
{
var policy = manager.LocalPolicy;
comObjects.Push(policy);
var profile = policy.CurrentProfile;
comObjects.Push(profile);
var applications = profile.AuthorizedApplications;
comObjects.Push(applications);
applications.Add(application);
result = true;
}
catch (Exception e)
{
exception = e;
}
}
catch (Exception e)
{
exception = e;
}
finally
{
while (comObjects.Count > 0)
{
ComUtilities.ReleaseComObject(comObjects.Pop());
}
}
}
catch (Exception e)
{
exception = e;
}
finally
{
}
return (result);
}
public static bool RemoveApplication (string processImageFileName, out Exception exception)
{
var result = false;
var comObjects = new Stack<object>();
exception = null;
if (processImageFileName == null) { throw (new ArgumentNullException("processImageFileName")); }
if (processImageFileName.Trim().Length == 0) { throw (new ArgumentException("The argument [processImageFileName] cannot be empty.", "processImageFileName")); }
try
{
var type = Type.GetTypeFromProgID("HNetCfg.FwMgr", true);
try
{
var manager = (INetFwMgr) Activator.CreateInstance(type);
comObjects.Push(manager);
try
{
var policy = manager.LocalPolicy;
comObjects.Push(policy);
var profile = policy.CurrentProfile;
comObjects.Push(profile);
var applications = profile.AuthorizedApplications;
comObjects.Push(applications);
applications.Remove(processImageFileName);
result = true;
}
catch (Exception e)
{
exception = e;
}
}
catch (Exception e)
{
exception = e;
}
finally
{
while (comObjects.Count > 0)
{
ComUtilities.ReleaseComObject(comObjects.Pop());
}
}
}
catch (Exception e)
{
exception = e;
}
finally
{
}
return (result);
}
}
}