Create firewall rule to open port per application programmatically in c# - c#

I need to open specific port for my application.
I have tried using INetFwAuthorizedApplication rule per application for all ports.
fwMgr.LocalPolicy.CurrentProfile.AuthorizedApplications.Add(app)
Alternatively open one port for all appllications using INetFwOpenPort.
firewallManager.LocalPolicy.CurrentProfile.GloballyOpenPorts.Add(port)
Is there any way to programmatically open only single port per application programmatically?
I can do it manually through firewall settings.

There's a question about blocking connections with an answer with instructions for creating firewall rules in C#. You should be able to adapt this for any kind of firewall rule I imagine.
https://stackoverflow.com/a/1243026/12744
The following code creates a firewall rule that blocks any outgoing
connections on all of your network adapters:
using NetFwTypeLib; // Located in FirewallAPI.dll
...
INetFwRule firewallRule = (INetFwRule)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FWRule"));
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_BLOCK;
firewallRule.Description = "Used to block all internet access.";
firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_OUT;
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = "Block Internet";
INetFwPolicy2 firewallPolicy = (INetFwPolicy2)Activator.CreateInstance(
Type.GetTypeFromProgID("HNetCfg.FwPolicy2"));
firewallPolicy.Rules.Add(firewallRule);

You could also just use PowerShell.
using System.Management.Automation;
...
private void OpenPort(int port)
{
var powershell = PowerShell.Create();
var psCommand = $"New-NetFirewallRule -DisplayName \"<rule description>\" -Direction Inbound -LocalPort {port} -Protocol TCP -Action Allow";
powershell.Commands.AddScript(psCommand);
powershell.Invoke();
}

Related

C# Process "Persistence"

I've been working on a System.Diagnostics.Process project (interractive powershell through network).
I want to be able to send a command from one host to another, so that the second runs it and sends the stdout + stderr to the first host.
The problem is, for example if i want to connect to a FTP server, list all files and get something for example, this should be done in one liner, because every time i send a command to another host, the Process start a new and no ftp connection "in this session of powershell" is present. Therefore "no persistence".
I'd like to run a powershell process on a user's instance once, redirect stdin, stdout and stderr to a variable, and from those be able to recieve command strings and send the output from that to the "main host".
P.S. All solutions i've found were just to run for every command a new instance of a Process and lose the "persistence" of that.
Unless your goal is to re-invent PowerShell Remoting, I'd strongly suggest just using a remote runspace instead, see this (oversimplified) example:
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Linq;
public class PersistentCommandRunner
{
private Runspace remoteRunspace;
public PersistentCommandRunner(string remoteMachine)
{
# Connect to remote machine using a runspace, save the runspace reference
var connectionInfo = new WSManConnectionInfo(new Uri("http://remoteMachine:5985/WSMan"));
remoteRunspace = RunspaceFactory.CreateRunspace(connectionInfo);
}
public IEnumerable<PSObject> RunScript(string script)
{
# Make sure runspace is ready to execute remote commands
EnsureConnection();
using(var shell = PowerShell.Create())
{
# Make sure our script runs in the remote runspace
shell.Runspace = remoteRunspace;
shell.AddScript(script);
foreach(var result in shell.Invoke())
{
yield return result;
}
}
}
private void EnsureConnection()
{
if(remoteRunspace.RunspaceStateInfo.State != RunspaceState.Open)
{
if(remoteRunspace.RunspaceStateInfo.State == RunspaceState.BeforeOpen)
{
remoteRunspace.Open();
return;
}
throw new Exception("Runspace is in an unusable state...");
}
}
}
Re-using the same runspace for subsequent scripts allows you to maintain state on the remote endpoint, ie.:
var serverRunner = new PersistentCommandRunner();
# Stage variable in the remote session
serverRunner.InvokeScript(#"$remoteVariable = 123");
# Retrieve it again, should print "123"
Console.WriteLine(serverRunner.InvokeScript("$remoteVariable").First()?.Base as int)

Auto Detect The Application on LAN using C#.net

I have an Open Source Voice Chatting application which works fine on LAN.
But the problem is with connecting two PCs Manually.
Let's suppose there are two PCs (Application instances), PC A and PC B.
To make a connection I have to put the IP Address of the PC A into PC B and IP Address of the PC B into PC A.
I want to make the small code change where if the application is running on two PCs and they both are connected via LAN then both sides get the IP address automatically. Like auto-detection.
So my logic was to first know the IP Address on the LAN using arp -a command then writes the output in a text file and only obtain the IP addresses that start with 192... and check the instance of the application on each address using This Solution.
Unfortunately, I end up getting an error which states that.
Unhandled Exception: System.Runtime.InteropServices.COMException: The
RPC server is unavailable.
at
System.Runtime.InteropServices.Marshal.ThrowExceptionForHRInternal(Int32
errorCode, IntPtr errorInfo) at
System.Management.ManagementScope.InitializeGuts(Object o) at
System.Management.ManagementScope.Initialize() at
System.Management.ManagementObjectSearcher.Initialize() at
System.Management.ManagementObjectSearcher.Get()
This is the code which i used to accomplish this task.
//Write the cmd Output in a text file
string strCmdText;
strCmdText = #"/K arp -a > C:\Test\Result.txt";
System.Diagnostics.Process.Start("CMD.exe", strCmdText);
//To get the IP address which starts with the 192.
const string ipPattern = #"^\s*(192\.168\.\d{1,3}\.\d{1,3}\b)";
var ipRegex = new Regex(ipPattern);
var ipAddresses192168 = File.ReadAllLines(#"C:\Test\Result.txt")
.Skip(3) // Skip 3 lines
.Where(line => ipRegex.IsMatch(line))
.Select(line => ipRegex.Match(line).Groups[1].Value);
foreach (var ipAddress in ipAddresses192168)
{
Console.WriteLine(ipAddress);
// Check for the running instance of the application on LAN network.
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2");
string query = "SELECT * FROM Win32_Process WHERE Name='WavPlayer.exe'";
var searcher = new ManagementObjectSearcher(query);
searcher.Scope = scope;
bool isRunning = searcher.Get().Count > 0;
}
So my question is, Is there any other straight forward process to accomplish this task using C#.net?
I am available to provide more info about this question so any help is appreciated.

Multi hop SSH through SSH.NET in C#

I am doing SSH to a Linux machine and again from there want to SSH to another Linux machine to carry out few Perforce tasks.
using (SshClient ssh = new SshClient("ip address","username", "pwd"))
{
ssh.Connect();
command = ssh.CreateCommand("ssh hostname");
result = command.Execute();
Console.WriteLine(result);
}
Where the ssh hostname is a password less ssh. How can I control the second SSH session and pass commands to it?
Even explored the CreateShell function, but seems like it is not suggested for automation.
In general, trying to automate ssh command is a bad design.
You better use a port forwarding (aka SSH tunnel) to implement the "hop".
var firstClient =
new SshClient(firstHostName, firstUserName, firstPassword);
firstClient.Connect();
var port = new ForwardedPortLocal("127.0.0.1", secondHostName, 22);
firstClient.AddForwardedPort(port);
port.Start();
var secondClient =
new SshClient(port.BoundHost, (int)port.BoundPort, secondUserName, secondPassword);
secondClient.Connect();
var command = secondClient.CreateCommand("ls");
var result = command.Execute();
Console.WriteLine(result);
There are some cases, when automating the ssh is acceptable (while still not ideal). E.g. because there's an authentication to the second host set up on the first one. I.e. there might be private key in the .ssh folder and you are not allowed to transfer that key to your client machine.
Even then, try talking to the system Administrator to find a better solution. The private key is still accessible using the credentials contained in your application, so it's not protected any better, had the private key itself been contained directly in the application.
Anyway, ssh can accept a command on its command line, like:
command = ssh.CreateCommand("ssh hostname command");
result = command.Execute();
Console.WriteLine(result);

Check if a port is assigned to any program or added in firewall - C#

We have Windows Service which will be installed by installer. We have an option to allow user to provide a port number and select whether the service must start on completion of installation. We are having a check on installer itself for checking whether the port is open/available.
TcpClient TcpScan = new TcpClient();
TcpScan.Connect("localhost", portno);
if (TcpScan.Connected == true)
{
TcpScan.Close();
}
My problem is if the user selects the option of not to start the service on installation and then we install another instance on the same machine with the same port as used in first one, then if we start both the services then one of the service will not work.
So is there any way I can check whether the port provided by user is already there in firewall or is already assigned to some other windows service? (Also assume the service can be in stopped state)
I think no, because any app could open a port at runtime.
You can (for example) use a Mutex to avoid multiple instances of your service on the same port (giving the mutex a name like String.Format(MyMutex_{0},my_port}.
And you could/should check if that port is free during service startup and close it gracefully if it's not.
Finally got the answer by doing some R&D
string OP = #"C:\Windows\Temp\ExceptionList.txt";
ProcessStartInfo procStartInfo = null;
string command = "netsh advfirewall firewall show rule name=all > " + OP;
procStartInfo = new ProcessStartInfo("cmd", "/c " + command);
procStartInfo.CreateNoWindow = true;
procStartInfo.WindowStyle = ProcessWindowStyle.Hidden;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
proc.WaitForExit();
if (File.Exists(OP))
{
StreamReader SR = new StreamReader(OP);
string FileData = SR.ReadToEnd();
SR.Close();
//Logic to read the output and then fetch only records which are enabled and have LocalPort
}
Output (ExceptionList.txt) file contains data in this format
Rule Name: NETTCP
---------------------------------------------
Enabled: Yes
Direction: In
Profiles: Domain
Grouping:
LocalIP: Any
RemoteIP: Any
Protocol: TCP
LocalPort: 8080
RemotePort: Any
Edge traversal: No
Action: Allow

How to execute process on remote machine, in C#

How can I start a process on a remote computer in c#, say computer name = "someComputer", using System.Diagnostics.Process class?
I created a small console app on that remote computer that just writes "Hello world" to a txt file, and I would like to call it remotely.
Console app path: c:\MyAppFolder\MyApp.exe
Currently I have this:
ProcessStartInfo startInfo = new ProcessStartInfo(string.Format(#"\\{0}\{1}", someComputer, somePath);
startInfo.UserName = "MyUserName";
SecureString sec = new SecureString();
string pwd = "MyPassword";
foreach (char item in pwd)
{
sec.AppendChar(item);
}
sec.MakeReadOnly();
startInfo.Password = sec;
startInfo.UseShellExecute = false;
Process.Start(startInfo);
I keep getting "Network path was not found".
Can can use PsExec from http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx
Or WMI:
object theProcessToRun() = { "YourFileHere" };
ManagementClass theClass = new ManagementClass(#"\\server\root\cimv2:Win32_Process");
theClass.InvokeMethod("Create", theProcessToRun);
Use one of the following:
(EDIT) Remote Powershell
WMI (see Ivan G's answer)
Task Scheduler API (http://msdn.microsoft.com/en-us/library/windows/desktop/aa383606%28v=vs.85%29.aspx)
PsExec
WshRemote object with a dummy script. Chances are, it works via DCOM, activating some of scripting objects remotely.
Or if you feel like it, inject your own service or COM component. That would be very close to what PsExec does.
Of all these methods, I prefer task scheduler. The cleanest API of them all, I think. Connect to the remote task scheduler, create a new task for the executable, run it. Note: the executable name should be local to that machine. Not \servername\path\file.exe, but c:\path\file.exe. Delete the task if you feel like it.
All those methods require that you have administrative access to the target machine.
ProcessStartInfo is not capable of launching remote processes.
According to MSDN, a Process object only allows access to remote processes not the ability to start or stop remote processes. So to answer your question with respect to using this class, you can't.
An example with WMI and other credentials as the current process, on default it used the same user as the process runs.
var hostname = "server"; //hostname or a IpAddress
var connection = new ConnectionOptions();
//The '.\' is for a local user on the remote machine
//Or 'mydomain\user' for a domain user
connection.Username = #".\Administrator";
connection.Password = "passwordOfAdministrator";
object[] theProcessToRun = { "YourFileHere" }; //for example notepad.exe
var wmiScope = new ManagementScope($#"\\{hostname}\root\cimv2", connection);
wmiScope.Connect();
using (var managementClass = new ManagementClass(wmiScope, new ManagementPath("Win32_Process"), new ObjectGetOptions()))
{
managementClass.InvokeMethod("Create", theProcessToRun);
}
I don't believe you can start a process through a UNC path directly; that is, if System.Process uses the windows comspec to launch the application... how about you test this theory by mapping a drive to "\someComputer\somePath", then changing your creation of the ProcessStartInfo to that? If it works that way, then you may want to consider temporarily mapping a drive programmatically, launch your app, then remove the mapping (much like pushd/popd works from a command window).

Categories

Resources