I inherited a C# application and working on it. It creates some firewall rules programmatically. By default it disables everything on a specific interface, then allows a few specified TCP ports access, which is fine. I can't figure out how to modify the code to allow that port to respond to ping commands. However, and couldn't find any code online in other searches that would do that.
Does anyone know how to use C# to create a firewall rule to allow a port to respond to ping commands? The app will be deployed in Windows 7 embedded, 64 bit.
Here is some existing code which creates a rule to open a TCP port, which works OK:
private void SetupFirewallAllowIncomingRule(int port)
{
try
{
_log.Debug("Creating instance of Windows Firewall policy (HNetCfg.FwPolicy2)...");
INetFwPolicy2 firewallPolicy = Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FwPolicy2")) as INetFwPolicy2;
if (null == firewallPolicy)
{
_log.Error("HNetCfg.FwPolicy2 instance could not be created!");
return;
}
string name = "Rule Port " + port.ToString();
foreach (INetFwRule2 rule in firewallPolicy.Rules)
{
if (name.Equals(rule.Name))
{
_log.WarnFormat("Windows Firewall Rule ({0}) already exists. It will not be created again.", rule.Name);
return;
}
}
_log.Debug("Creating new Windows Firewall Rule (HNetCfg.FWRule)...");
INetFwRule firewallRule = Activator.CreateInstance(Type.GetTypeFromProgID("HNetCfg.FWRule")) as INetFwRule;
if (null == firewallRule)
{
_log.Error("HNetCfg.FWRule instance could not be created!");
return;
}
firewallRule.Action = NET_FW_ACTION_.NET_FW_ACTION_ALLOW;
firewallRule.Direction = NET_FW_RULE_DIRECTION_.NET_FW_RULE_DIR_IN;
firewallRule.Enabled = true;
firewallRule.InterfaceTypes = "All";
firewallRule.Name = name;
firewallRule.Protocol = (int)NET_FW_IP_PROTOCOL_.NET_FW_IP_PROTOCOL_TCP;
//NOTE: Must do this after setting the Protocol!
firewallRule.LocalPorts = port.ToString();
_log.DebugFormat("Adding Windows Firewall Rule {0}...", firewallRule.Name);
firewallPolicy.Rules.Add(firewallRule);
_log.InfoFormat("Windows Firewall Rule {0} added.", firewallRule.Name);
}
catch (Exception ex)
{
_log.Error("Windows Firewall Rule could not be added for port " + port.ToString() + "!", ex);
}
}
Related
I need to copy and/or move files across servers to the other side of my
firewall. I was wondering if anyone can tell me what port(s) I will need to
open to run these methods in my C# program?
class MoveIt
{
public static void Main()
{
var localPath = #"c:\temp\";
var remotePath = #"\\MyRemoteServer\MyShare\MyPath\"
try
{
if (File.Exists(localPath + "MyTestFile.txt") &&
Directory.Exists(remotePath))
{
File.Move(localPath + "MyTestFile.txt", remotePath +
"MyTestFile.txt");
}
}
catch (Exception e)
{
Console.WriteLine("The process failed: {0}", e.ToString());
}
}
}
You need at least TCP 445, and to be sure you also want TCP 137-139, though this latter group is only if you're still stuck using NetBIOS for smb name resolution.
I am working on a bit of code that uses a custom DHCP protocol to get an ip. The code then needs to set one of the machines NICs to that ip.
The code i have for that is below.
private void SetIp(IPAddress ipAddress, IPAddress subnetMask, IPAddress gatewayAddress)
{
try
{
ManagementBaseObject objNewIP = null;
ManagementBaseObject objSetIP = null;
ManagementBaseObject objNewGate = null;
objNewIP = networkInterface.GetMethodParameters("EnableStatic");
objNewGate = networkInterface.GetMethodParameters("SetGateways");
//Set DefaultGateway
objNewGate["DefaultIPGateway"] = new string[] { gatewayAddress.ToString() };
objNewGate["GatewayCostMetric"] = new int[] { 1 };
//Set IPAddress and Subnet Mask
objNewIP["IPAddress"] = new string[] { ipAddress.ToString() };
objNewIP["SubnetMask"] = new string[] { subnetMask.ToString() };
objSetIP = networkInterface.InvokeMethod("EnableStatic", objNewIP, null);
objSetIP = networkInterface.InvokeMethod("SetGateways", objNewGate, null);
Console.WriteLine(
"Updated IPAddress, SubnetMask and Default Gateway!");
}
catch (Exception ex)
{
}
// throw new System.NotImplementedException();
}
I keep on getting 2147749891 on the EnableStatic call. This post Machine IP reset does nothing suggests i need admin priviledges on the machine which I do.
The microsoft page https://msdn.microsoft.com/en-us/library/aa390383(v=vs.85).aspx suggests i need to acquire a write lock which requires com code which i would rather avoid.
Is there a better way to achieve this, perhaps using netsh and maybe in a way that doesn't require admin priviledges? All i have the mac address of the NIC to set and the details to set for it
Thanks
I got the same error when calling EnableStatic.
Elevating the running user to an admin (run as admin) solved my problem, which seems normal: only admin can change the NIC parameters.
I have yet to determine why a user with admin access cannot run the same code, possibly an UAC problem, investigation is on-going.
As for the microsoft page (https://msdn.microsoft.com/en-us/library/aa390383(v=vs.85).aspx), the "Write lock not enabled" is 2147786788.
Not 2147749891.
I'm making a program that needs to set a static IP to a computer's wired NIC, and the program can't perform the next part (querying an SNMP string from another IP on the same network) until it's positively set and usable, which experience has taught me isn't always instant. This program is written in C# on VS2013 as a WinForms application, and the function is below. The actual setting of the IP address works perfectly, the problem is trying to poll for when the change completes. I can run the program, have it set an IP address (never more than a single IP/Subnet/Gateway), and while it's still polling for the change, pop open a command prompt, run ipconfig, and see that the change has already gone through. The program will continue to hang until it times out. I have tried several different methods of querying and checking the IP addresses, including reassigning NICConfig every time through the loop and checking to see if any IP addresses in either string[] match, nothing works. I have not yet piped currentIPs[0] into a file or command line to see what it contains, but I strongly suspect it will contain the previous IP address. I also tried setting the IP address in the registry, per this post: Why does applying a static IP address via WMI work just once? but all that did for me was give me a second IP address on that interface in ipconfig with the program still hanging.
Actually, on further examination, it looks like the behavior is to add the IP address/subnet/gateway to the list (string array), instead of replacing the old info, but the program isn't even getting an updated version of the list with the intended IP on it. This may not have started until after messing with the registry values using code from the above link, I can't be sure. I also can't seem to remove the extra IPs from my PC's configuration, they don't show up in the windows ipv4 configuration page (but I do get a warning when closing it about multiple gateways), and removing them from the registry seems to do nothing - so any help fixing my computer's NIC configuration would also be appreciated.
private bool set_staticIP(string Index, string[] IP, string[] Subnet, string[] Gateway, string[] DNS)
{
string WMIQuery = String.Format("Win32_NetworkAdapterConfiguration.Index='{0}'", Index);
ManagementObject NICConfig = new ManagementObject(#"root\CIMV2", WMIQuery, null);
ManagementBaseObject inParams = null;
ManagementBaseObject outParams = null;
string[] OldIP = (string[])NICConfig["IPAddress"];
try
{
/* Set IP/Subnet mask */
inParams = NICConfig.GetMethodParameters("EnableStatic");
inParams["IPAddress"] = IP;
inParams["SubnetMask"] = Subnet;
outParams = NICConfig.InvokeMethod("EnableStatic", inParams, null);
if (outParams["ReturnValue"].ToString() != "0")
{
MessageBox.Show("Error setting IP, returned " + outParams["ReturnValue"]);
}
/* Set Gateway(s) */
inParams = NICConfig.GetMethodParameters("SetGateways");
inParams["DefaultIPGateway"] = Gateway;
inParams["GatewayCostMetric"] = new int[] {1};
outParams = NICConfig.InvokeMethod("SetGateways", inParams, null);
if (outParams["ReturnValue"].ToString() != "0")
{
MessageBox.Show("Error setting Gateway, returned " + outParams["ReturnValue"]);
}
/* Set DNS Servers */
inParams = NICConfig.GetMethodParameters("SetDNSServerSearchOrder");
inParams["DNSServerSearchOrder"] = DNS;
outParams = NICConfig.InvokeMethod("SetDNSServerSearchOrder", inParams, null);
if (outParams["ReturnValue"].ToString() != "0")
{
MessageBox.Show("Error setting DNS, returned " + outParams["ReturnValue"]);
}
bool IPMatches = false;
string[] currentIPs = null;
int timeout = 2000;
int i;
for (i = 0; i < timeout && !IPMatches; i++)
{
currentIPs = (string[])NICConfig["IPAddress"];
if (currentIPs == IP || currentIPs != OldIP)
{
IPMatches = true;
break;
}
Task.Delay(100);
}
if (i >= timeout)
{
MessageBox.Show("Timeout while setting static IP address");
}
}
catch(ManagementException e)
{
MessageBox.Show("set_static() threw exception " + e.Message);
}
return IPMatches;
}
The machines I've tested this on are a laptop running Windows 7 x64, I get the same behavior with the internal NIC and a USB NIC, and a tablet running Windows 8.1 x64 with the same USB NIC.
You can use:
// Callback für Netzwerk-Änderungen erzeugen
NetworkChange.NetworkAddressChanged += new NetworkAddressChangedEventHandler(AddressChangedCallback);
// Callback für Netzwerk-Änderungen
void AddressChangedCallback(object sender, EventArgs e)
{
// IP is changed;
}
You will get the callback whenever a network adress is changed. Now you can check if it is the adress you are waiting for.
I have a following method that connects to an end point when my program starts
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
I also have a timer that is set to trigger every 60 seconds to call CheckConnectivity, that attempts to send an arbitrary byte array to the end point to make sure that the connection is still alive, and if the send fails, it will attempt to reconnect.
public bool CheckConnectivity(bool isReconnect)
{
if (ChannelSocket != null)
{
var blockingState = ChannelSocket.Blocking;
try
{
var tmp = new byte[] { 0 };
ChannelSocket.Blocking = false;
ChannelSocket.Send(tmp);
}
catch (SocketException e)
{
try
{
ReconnectChannel();
}
catch (Exception ex)
{
return false;
}
}
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} is null!", ChannelIp, ChannelPort));
return false;
}
return true;
}
private void ReconnectChannel()
{
try
{
ChannelSocket.Shutdown(SocketShutdown.Both);
ChannelSocket.Disconnect(true);
ChannelSocket.Close();
}
catch (Exception ex)
{
ConnectivityLog.Error(ex);
}
ChannelSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remoteIpAddress = IPAddress.Parse(ChannelIp);
ChannelEndPoint = new IPEndPoint(remoteIpAddress, ChannelPort);
ChannelSocket.Connect(ChannelEndPoint);
Thread.Sleep(1000);
if (ChannelSocket.Connected)
{
ConnectivityLog.Info(string.Format("{0}:{1} is reconnected!", ChannelIp, ChannelPort));
}
else
{
ConnectivityLog.Warn(string.Format("{0}:{1} failed to reconnect!", ChannelIp, ChannelPort));
}
}
So how I'd test the above, is to physically unplug the LAN cable from my ethernet device, allowing my code to attempt to reconnect (which fails obviously) and reconnect back the LAN cable.
However, even after reconnecting the LAN cable (able to ping), ChannelSocket.Connect(ChannelEndPoint) in my Reconnect method always throws this error
No connection could be made because the target machine actively refused it 192.168.168.160:4001
If I were to restart my whole application, it connects successfully. How can I tweak my reconnect method such that I don't have to restart my application to reconnect back to my Ethernet device?
If an application closes a TCP/IP port, the protocol dictates that the port stays in TIME_WAIT state for a certain duration (default of 240 seconds on a windows machine).
See following for references -
http://en.wikipedia.org/wiki/Transmission_Control_Protocol
http://support.microsoft.com/kb/137984
http://www.pctools.com/guides/registry/detail/878/
What this means for your scenario - is that you cannot expect to close (willingly or unwillingly) and re-open a port within a short period of time (even several seconds). Despite some registry tweaks which you'd find on internet.. the port will be un-available for any app on windows, for a minimum of 30 seconds. (Again, default is 240 seconds)
Your options - here are limited...
From the documentation at http://msdn.microsoft.com/en-us/library/4xzx2d41(v=vs.110).aspx -
"If the socket has been previously disconnected, then you cannot use this (Connect) method to restore the connection. Use one of the asynchronous BeginConnect methods to reconnect. This is a limitation of the underlying provider."
The reason why documentation suggests that BeginConnect must be used is what I mentioned above.. It simply doesn't expect to be able to establish the connection right away.. and hence the only option is to make the call asynchronously, and while you wait for the connection to get established in several minutes, do expect and plan for it to fail. Essentially, likely not an ideal option.
If the long wait and uncertainty is not acceptable, then your other option is to somehow negotiate a different port between the client and server. (For example, in theory you could use UDP, which is connectionless, to negotiate the new TCP port you'd re-establish the connection on). Communication using UDP, in theory of course, itself is not guaranteed by design. But should work most of the times (Today, networking in typical org is not that flaky / unreliable). Subjective to scenario / opinion, perhaps better than option 1, but more work and smaller but finite chance of not working.
As suggested in one of the comments, this is where application layer protocols like http and http services have an advantage. Use them, instead of low level sockets, if you can.
If acceptable, this is the best option to go with.
(PS - FYI - For HTTP, there is a lot of special handling built into OS, including windows - For example, there is a dedicated driver Http.sys, specially for dealing with multiple apps trying to listen on same port 80 etc.. The details here are a topic for another time.. point is, there is lots of goodness and hard work done for you, when it comes to HTTP)
Maybe you should switch to a higher abstraction class, which better deals with all these nifty little details?
I'm going to use for these network connections the TcpListener and TcpClient classes. The usage of these classes is quite easy:
The client side:
public void GetInformationAsync(IPAddress ipAddress)
{
_Log.Info("Start retrieving informations from address " + ipAddress + ".");
var tcpClient = new TcpClient();
tcpClient.BeginConnect(ipAddress, _PortNumber, OnTcpClientConnected, tcpClient);
}
private void OnTcpClientConnected(IAsyncResult asyncResult)
{
try
{
using (var tcpClient = (TcpClient)asyncResult.AsyncState)
{
tcpClient.EndConnect(asyncResult);
var ipAddress = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address;
var stream = tcpClient.GetStream();
stream.ReadTimeout = 5000;
_Log.Debug("Connection established to " + ipAddress + ".");
var formatter = new BinaryFormatter();
var information = (MyInformation)formatter.Deserialize(stream);
_Log.Info("Successfully retrieved information from address " + ipAddress + ".");
InformationAvailable.FireEvent(this, new InformationEventArgs(information));
}
}
catch (Exception ex)
{
_Log.Error("Error in retrieving informations.", ex);
return;
}
}
The server side:
public void Start()
{
ThrowIfDisposed();
if (_TcpServer != null;)
_TcpServer.Stop();
_TcpServer = new TcpListener(IPAddress.Any, _PortNumber);
_TcpServer.Start();
_TcpServer.BeginAcceptTcpClient(OnClientConnected, _TcpServer);
_Log.Info("Start listening for incoming connections on " + _TcpServer.LocalEndpoint + ".");
}
private void OnClientConnected(IAsyncResult asyncResult)
{
var tcpServer = (TcpListener)asyncResult.AsyncState;
IPAddress address = IPAddress.None;
try
{
if (tcpServer.Server != null
&& tcpServer.Server.IsBound)
tcpServer.BeginAcceptTcpClient(OnClientConnected, tcpServer);
using (var client = tcpServer.EndAcceptTcpClient(asyncResult))
{
address = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
_Log.Debug("Client connected from address " + address + ".");
var formatter = new BinaryFormatter();
var informations = new MyInformation()
{
// Initialize properties with desired values.
};
var stream = client.GetStream();
formatter.Serialize(stream, description);
_Log.Debug("Sucessfully serialized information into network stream.");
}
}
catch (ObjectDisposedException)
{
// This normally happens, when the server will be stopped
// and their exists no other reliable way to check this state
// before calling EndAcceptTcpClient().
}
catch (Exception ex)
{
_Log.Error(String.Format("Cannot send instance information to {0}.", address), ex);
}
}
This code works and doesn't make any problems with a lost connection on the client side. If you have a lost connection on the server side you have to re-establish the listener, but that's another story.
In ReconnectChannel just dispose the ChannelSocket object.
try
{
`//ChannelSocket.Shutdown(SocketShutdown.Both);
//ChannelSocket.Disconnect(true);
//ChannelSocket.Close();
ChannelSocket.Dispose();`
}
This is working for me. Let me know if it doesn't work for you.
I have a c# application that has a module for checks the server connection. The relevant code is like the following:
private void PingCheck(string hostName)
{
using (var p = new Ping())
{
try
{
var pr = p.Send(hostName, 2000);
if (pr.Status != IPStatus.Success)
{
log.ErrorFormat("Ping error! Host = {0}, Ping status = {1}", hostName, pr.Status.ToString());
}
}
catch (Exception exc)
{
log.Error("Ping error!", exc);
}
}
}
We have deployed this application to our server that is inside the same network as the target machine. That's why this method checks internal connectivity. Is there any way to check server external connectivity? Because sometimes server connection is available in our network although connection from external network is down. How can I achieve this?
No, there is not, since you are on the server itself.
Either ping some resource outside to check connectivity, or use the NetworkInterface.GetIsNetworkAvailable() method to check whether there is an active connection.