I'm trying to get two applications to communicate through a local network using HTTP / WCF. The Master makes web requests and looks for Slave applications that each has a web service running. The slaves are configured to answer to localhost:\\[MACHINENAME]:8000
It works when I run the slave on the same computer as the Master but not when I run it on another computer on the same network. I confirm that the computers are on the same network by the cmd prompt Ping [MachineName]. What is required to send requests to another computer on the same network?
Slave sets up webservice:
public void Run()
{
Config config = Config.validateAndCreate();
string machineName = System.Environment.MachineName;
string baseAddress = "http://" + machineName + ":" + config.port;
Service.setConfig(config);
if (new Service().UpdateScripts().status != ExecStatus.OK)
{
throw new Exception("Failed to update scripts");
}
using (WebServiceHost host = new WebServiceHost(typeof(Service), new Uri(baseAddress)))
{
host.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpGetEnabled = true });
host.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;
host.Description.Behaviors.Find<ServiceDebugBehavior>().HttpHelpPageEnabled = false;
ServiceEndpoint ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), "");
host.Open();
log.Info("Service is running at: " + baseAddress);
log.Info("Press the 'q' key to quit...");
while (Console.ReadKey(true).Key != ConsoleKey.Q) { }
host.Close();
}
}
The most likely thing to be blocking it is a Firewall. If you haven't added a 3rd party firewall, then the Windows Firewall (which is on by default) will be blocking it.
You will need to add an exception to the firewall, to permit traffic on that port to be routed to your application.
Click "Start" and type "Windows Firewall with Advanced Security".
Click "Inbound Rules" -> New Rule, and add either a Program rule or a Port rule as appropriate.
Related
I am trying to get the MAC address of the client pc but it shows the mac address of the IIS server where my project is hosted.
protected void Page_Load(object sender, EventArgs e)
{
NetworkInterface[] anics = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface adapter in anics)
{
if (amacaddress == String.Empty)
{
IPInterfaceProperties properties = adapter.GetIPProperties();
amacaddress = adapter.GetPhysicalAddress().ToString();
lblname.Visible = true;
string ip = Request.UserHostAddress;
lblname.Text = "MAC Address is :- " + amacaddress + " "+ ip;
}
}
}
Yeah. That is similar to asking for getting the IMSI of a phone from a phone call - not possible, you call a phone number, the rest is implementation detail. MAC Addresses pretty much never travel more than one ethernet domain (next switch/router). They are not pat of the IP protocol layer. As such, you can not get them from the http request, which ultimatly is a TCP thus an IP connection. YOu will have to execute (C#, not javascript) code on the client to possibly get the local MAC AddressES - that is plural, there may be more than one (as in: 2 local network cards, a wireless adapter = 3 mac addresses).
I would like to ask if you know how to implement Secure Web Socket with .Net.
I've implemented ws:// and everything ok but I've no idea how to switch to wss://.
Thanks in advance.
You could try Fleck
Fleck is a WebSocket server implementation in C#
From their examples:
var server = new WebSocketServer("wss://0.0.0.0:8431");
server.Certificate = new X509Certificate2("MyCert.pfx");
server.Start(socket =>
{
//...use as normal
});
This question is very old but here's how i got my C# server accept an SSL connection from the client (js code running on Chrome / Firefox).
Assuming you already have a working and valid certificate (in my case the same certificate working to serve SSL on my Apache webserver), signed by a trusted CA (in my case, letsencrypt.org, which let you request a certificate for free), this is an excerpt from working code:
public static X509Certificate2 serverCertificate = null;
public Server(string ip_addr, int port)
{
serverCertificate = GetCertificateFromStore("CN=mydomain.com");
string resultsTrue = serverCertificate.ToString(true); // Debugging purposes
bool hasPrivateKey = serverCertificate.HasPrivateKey; // Debugging purposes (MUST return true)
Console.WriteLine("Certificate validation results: " + resultsTrue);
Console.WriteLine("Has private key? " + hasPrivateKey);
server = new TcpListener(IPAddress.Parse(ip_addr), port);
server.Start();
Console.WriteLine("Server has started on ip: " + ip_addr + ":"+port + " - Waiting for a connection...", Environment.NewLine);
}
public class ClientHandler
{
TcpClient client { get; set; }
//NetworkStream stream { get; set; } // Old plain non-secure tcp stream
SslStream stream { get; set; } // New secure tcp stream
....
public ClientHandler(TcpClient client, string room_id)
{
....
stream = new SslStream(client.GetStream(), false);
try
{
stream.AuthenticateAsServer(Server.serverCertificate, clientCertificateRequired: false, checkCertificateRevocation: false);
// Set timeouts for the read and write to 5 seconds.
stream.ReadTimeout = 5000;
stream.WriteTimeout = 5000;
}
catch (Exception ex)
{
Console.WriteLine("Error during SSL authentication with the client:" + ex);
return;
}
}
}
The tricky part is that class X509Certificate2 needs to retrieve the certificate not from file but from your local keystore.
Also you need both the certificate file AND your private key for SSL to work.
I'm developing on Linux and Mono.Net but it should not change much on other platforms. The tools i needed were: openssl and certmgr (mono certificate manager).
To create the .pfx file containing the cert & the private key:
openssl pkcs12 -export -in yourcertfile.cer -inkey yourprivatekeyfile.pem -out finalfile.pfx
To add the file obtained to my local store:
certmgr -add -c -m Trust finalfile.pfx
Finally, you can edit your client side connection code to point to the same domain you're hosting your server (which should be the same domain reported in your certificate).
This:
var mySocket = new WebSocket("ws://127.0.0.1:5050");
Becomes:
var mySocket = new WebSocket("wss://yourdomain.com:5050");
Keep in mind that, once you've implemented SSL, you'll have to revise the whole networking code, since you're adding overhead to your TCP stream and you must take it into account when parsing the bytes and the bits to find and decode the headers.
This is where i'm stuck myself but beside that, SSL connection works great :)
If you use WebSocketSharp-NonPreRelease Package to develop the websocket you can simply add your certificate using below code
var wssv = new WebSocketServer (5963, true);
wssv.SslConfiguration.ServerCertificate =
new X509Certificate2 ("/path/to/cert.pfx", "password for cert.pfx");
I'm trying to set up a custom server on an Azure VM. I've assigned it a public IP address, which I'm able to reach and get into the server via Remote Desktop, so that part's working just fine.
But when I try to bind to the public IP address using the websocket-sharp library, it fails, saying "the host part isn't a local host name."
I've tracked this down to this file, where the following code block executes, and ends up returning false:
var host = System.Net.Dns.GetHostName ();
var addrs = System.Net.Dns.GetHostAddresses (host);
foreach (var addr in addrs) {
if (address.Equals (addr))
return true;
}
return false;
With a bit of debugging, I've determined that Dns.GetHostAddresses is showing internal IPs only, but not the external IP address. I've configured the IP address in Azure and attached it to the server, and I've turned on IP forwarding in the networking configuration and rebooted the VM, but the server still doesn't recognize its own external IP.
What am I missing?
What am I missing?
You could test Dns.GetHostAddresses with the local machine hostname, it also just could get the internal ip, it is not related to Azure VM.
If we want to get the public Ip of Azure VM with host name, we could use the Azure SDK to do that.
I also do a sample demo to get the public IP. Before that we need to registry Azure AD and assign corrosponding role to registried App. About how to registry Azure AD and create creditial file, you could refer to another SO thread and this link.
var subscriptiondId = "subscription Id";
var credentials = SdkContext.AzureCredentialsFactory.FromFile(#"path of creditial file");
var resouceGroup = "resouce group";
var hostName = "host name";
NetworkManagementClient networkManagement = new NetworkManagementClient(credentials) { SubscriptionId = subscriptiondId };
ComputeManagementClient computeManagement =
new ComputeManagementClient(credentials) {SubscriptionId = subscriptiondId};
var nic = computeManagement.VirtualMachines.GetAsync(resouceGroup, hostName).Result.NetworkProfile.NetworkInterfaces
.FirstOrDefault();
var networkIntefaceName = nic?.Id.Split('/').Last();
var ipConfiguration = networkManagement.NetworkInterfaces.GetAsync(resouceGroup, networkIntefaceName).Result.IpConfigurations.FirstOrDefault();
var publicIpAddressId = ipConfiguration?.PublicIPAddress.Id;
var ip = networkManagement.PublicIPAddresses.GetAsync(resouceGroup, publicIpAddressId?.Split('/').Last()
How do you determine or examine the connection profile of the current network connection (if any)?
Specifically, I need to determine if the current connection is to a private or public network, and from there determine whether network discovery is turned on or off.
It seems like this information is readily available in a Windows Store app via the Windows.Networking.Connectivity.NetworkInformation.GetConnectionProfiles() or NetworkInformation.GetInternetConnectionProfile() functions, but this is a standard desktop app that must run on Win 7 and Server 2008 as well as Win 8 and Server 2012.
Enumerating the NICs on a machine is not a problem, but this doesn't solve my issue - I need to get the properties of the connection, not the physical device.
Is there an inbuilt way to do this with the .Net framework? Alternatively can it be done with WMI? Or as a crude alternative, can it be done by invoking the netsh command (although this seems to depend on the dot3svc and/or wlansvc services to be running)?
You can use Network List Manager API for that purpose, to use it from C# import Network List Manager Type Library.
Then you must enumerate all connected networks, because there can be more than one, for example right now I am connected to internet and VPN. Then for all connected networks call GetCategory() API, it returns NLM_NETWORK_CATEGORY (private, public or domain).
Here is the sample code (add using NETWORKLIST in use clauses) :
var manager = new NetworkListManager();
var connectedNetworks = manager.GetNetworks(NLM_ENUM_NETWORK.NLM_ENUM_NETWORK_CONNECTED).Cast<INetwork>();
foreach (var network in connectedNetworks)
{
Console.Write(network.GetName() + " ");
var cat = network.GetCategory();
if (cat == NLM_NETWORK_CATEGORY.NLM_NETWORK_CATEGORY_PRIVATE)
Console.WriteLine("[PRIVATE]");
else if (cat == NLM_NETWORK_CATEGORY.NLM_NETWORK_CATEGORY_PUBLIC)
Console.WriteLine("[PUBLIC]");
else if (cat == NLM_NETWORK_CATEGORY.NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED)
Console.WriteLine("[DOMAIN]");
}
Console.ReadKey();
For this to work one must add reference to COM Network List 1.0 Type Library, like this:
For Network Discovery you have to use Firewall API and reference COM library NetFwTypeLib and get INetFwProfile for active profile, then in services there are File sharing, Network Discovery and Remote Desktop services, and there is a bool flag if these are Enabled. Here is the example code : (just to warn you I didn't use below code in production I was just exploring this API)
Type objectType = Type.GetTypeFromCLSID(new Guid("{304CE942-6E39-40D8-943A-B913C40C9CD4}"));
var man = Activator.CreateInstance(objectType) as INetFwMgr;
/// get current profile
INetFwProfile prof = man.LocalPolicy.CurrentProfile;
Console.WriteLine("Current profile ");
ShowProfileServices(prof);
And the method that shows profile services.
private static void ShowProfileServices(INetFwProfile prof)
{
var services = prof.Services.Cast<INetFwService>();
var sharing = services.FirstOrDefault(sc => sc.Name == "File and Printer Sharing");
if (sharing != null)
Console.WriteLine(sharing.Name + " Enabled : " + sharing.Enabled.ToString());
else
Console.WriteLine("No sharing service !");
var discovery = services.FirstOrDefault(sc => sc.Name == "Network Discovery");
if (discovery != null)
Console.WriteLine(discovery.Name + " Enabled : " + discovery.Enabled.ToString());
else
Console.WriteLine("No network discovery service !");
var remoteDesktop = services.FirstOrDefault(sc => sc.Name == "Remote Desktop");
if (remoteDesktop != null)
Console.WriteLine(remoteDesktop.Name + " Enabled : " + remoteDesktop.Enabled.ToString());
else
Console.WriteLine("No remote desktop service !");
}
I know this question is super old, but I faced this problem recently - how to get Network Category (private or public) in C# using Windows.Network.Connectivity from Windows Runtime API.
There is almost everything related to networking but I could not find the Network Category.
The solution is NetworkTypes enum.
https://learn.microsoft.com/en-us/uwp/api/windows.networking.connectivity.networktypes?view=winrt-22000
Simply check if returned types has flag PrivateNetwork. If yes - then is't private, if not - it's public.
Example code below:
var adapters = NetworkInterface.GetAllNetworkInterfaces();
var upNetworkInterfaces = adapters.Where(x =>
x.Supports(NetworkInterfaceComponent.IPv4) &&
x.NetworkInterfaceType is NetworkInterfaceType.Ethernet or NetworkInterfaceType.Wireless80211);
foreach (var adapter in upNetworkInterfaces)
{
var hostname = NetworkInformation.GetHostNames()
.FirstOrDefault(x =>
x.IPInformation != null &&
string.Equals(x.IPInformation.NetworkAdapter.NetworkAdapterId.ToString(),
adapter.Id.Replace("{", string.Empty).Replace("}", string.Empty),
StringComparison.InvariantCultureIgnoreCase));
if (hostname is not null)
{
var networkTypes = hostname.IPInformation.NetworkAdapter.NetworkItem.GetNetworkTypes();
var privateNetwork = networkTypes.HasFlag(NetworkTypes.PrivateNetwork)
? NetworkAccessibilityLevel.Private
: NetworkAccessibilityLevel.Public;
}
}
Is there a way to search for the existence of a given WCF service in any of the computer of a local Network?
For example, I am looking for the Math/Add2Numbers service and I want to know which machines on the LAN provide it, is there any way to do that?
Here is a super simple discovery example. It does not use a config file, it is all c# code, but you can probably port the concepts to a config file.
share this interface between host and client program (copy to each program for now)
[ServiceContract]
public interface IWcfPingTest
{
[OperationContract]
string Ping();
}
put this code in the host program
public class WcfPingTest : IWcfPingTest
{
public const string magicString = "djeut73bch58sb4"; // this is random, just to see if you get the right result
public string Ping() {return magicString;}
}
public void WcfTestHost_Open()
{
string hostname = System.Environment.MachineName;
var baseAddress = new UriBuilder("http", hostname, 7400, "WcfPing");
var h = new ServiceHost(typeof(WcfPingTest), baseAddress.Uri);
// enable processing of discovery messages. use UdpDiscoveryEndpoint to enable listening. use EndpointDiscoveryBehavior for fine control.
h.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
h.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// enable wsdl, so you can use the service from WcfStorm, or other tools.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
h.Description.Behaviors.Add(smb);
// create endpoint
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
h.AddServiceEndpoint(typeof(IWcfPingTest) , binding, "");
h.Open();
Console.WriteLine("host open");
}
put this code in the client program
private IWcfPingTest channel;
public Uri WcfTestClient_DiscoverChannel()
{
var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindCriteria fc = new FindCriteria(typeof(IWcfPingTest));
fc.Duration = TimeSpan.FromSeconds(5);
FindResponse fr = dc.Find(fc);
foreach(EndpointDiscoveryMetadata edm in fr.Endpoints)
{
Console.WriteLine("uri found = " + edm.Address.Uri.ToString());
}
// here is the really nasty part
// i am just returning the first channel, but it may not work.
// you have to do some logic to decide which uri to use from the discovered uris
// for example, you may discover "127.0.0.1", but that one is obviously useless.
// also, catch exceptions when no endpoints are found and try again.
return fr.Endpoints[0].Address.Uri;
}
public void WcfTestClient_SetupChannel()
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var factory = new ChannelFactory<IWcfPingTest>(binding);
var uri = WcfTestClient_DiscoverChannel();
Console.WriteLine("creating channel to " + uri.ToString());
EndpointAddress ea = new EndpointAddress(uri);
channel = factory.CreateChannel(ea);
Console.WriteLine("channel created");
//Console.WriteLine("pinging host");
//string result = channel.Ping();
//Console.WriteLine("ping result = " + result);
}
public void WcfTestClient_Ping()
{
Console.WriteLine("pinging host");
string result = channel.Ping();
Console.WriteLine("ping result = " + result);
}
on the host, simply call the WcfTestHost_Open() function, then sleep forever or something.
on the client, run these functions. It takes a little while for a host to open, so there are several delays here.
System.Threading.Thread.Sleep(8000);
this.server.WcfTestClient_SetupChannel();
System.Threading.Thread.Sleep(2000);
this.server.WcfTestClient_Ping();
host output should look like
host open
client output should look like
uri found = http://wilkesvmdev:7400/WcfPing
creating channel to http://wilkesvmdev:7400/WcfPing
channel created
pinging host
ping result = djeut73bch58sb4
this is seriously the minimum I could come up with for a discovery example. This stuff gets pretty complex fast.
What you need is WS-Discovery, but unfortunately, this is not included as part of the ws-* extensions in WCF. There are some homegrown implementations of it. Here's a google search for that.
Otherwise, you can implement an enterprise UDDI or registry solution by a third party vendor (like IBM or Microsoft).
You could use UDDI to find it, but if there were multiple instances of the service, how would you decide which instance to use?