I've made a programm, which sends HTTP-webrequests.
To secure these requests being sent, I want to have the ability to define an IP, over which the request should be sent.
So in case of the default exit not working the request should be sent via another exit.
I've tried doing that by using IPEndPoint and Sockets but somehow it's not working.
Here is my Code so far
public Response ExecuteRequest(RequestData requestData, NetworkAddress exit) {
Tracer.Info("Versuche Request über HTTP abzusetzen.");
if (!PrepareIpEndPoint(Address, exit)) {
return null;
}
Address = new Uri(PlaceholderReplacer.ReplacePlaceholders(Address.ToString(), requestData));
return RequestExecutor.ExecuteRequest(Address);
}
private bool PrepareIpEndPoint(Uri url, NetworkAddress exit) {
Tracer.Debug(string.Format("Setze den IP-Endpoint auf{0}", exit));
var ipEndPoint = new IPEndPoint(IPAddress.Parse(exit.Address), 0);
var tempSocket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
tempSocket.Bind(ipEndPoint);
tempSocket.Connect(ipEndPoint);
return tempSocket.Connected;
}
the above code is throwing SocketExceptions.
Any ideas are greatly appreciated.
Thanks, Josh
Remove this line: (it's for opening up a port for accepting clients)
tempSocket.Bind(ipEndPoint);
You want to act as a client by connecting to the server with:
tempSocket.Connect(ipEndPoint);
Are you really sure that you want to connet to port zero, i'm pretty sure this is not a valid choice. (standard HTTP = 80, HTTPS = 443)
var ipEndPoint = new IPEndPoint(IPAddress.Parse(exit.Address), 80);
Related
I am trying to make some UDP communication between 2 different address, so my sending code looks like:
var localEndpoint = new IPEndPoint(IpAddress.Parse("192.168.2.10"), 51111)
var remoteEndpoint = new IPEndPoint(IpAddress.Parse("192.168.1.10"), 51111)
var sender = new UdpClient (localEndpoint)
sender.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
sender.Send (request.RawRequest, request.RawRequest.Length, remoteEndpoint) |> ignore
sender.Close ()
As you see those are 2 different address, so I am binding interface address to my client and turning off routing. But when I try this I am getting unreachable network message, but when I try same address families well it works.
I also do broadcast to this destination (that is 192.168.1.2) where endpoint is:
new IPEndPoint(IpAddress.Parse("255.255.255.255"), 51111)
sender.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
And it works.
What am I doing wrong?
I am working on a service discovery implementation in C#. In an attempt to get around some issues, I have implemented both broadcast and multicast, simplified to the snippets shown.
Client side broadcast:
var requestData = new byte[]{ /* Whatever */}
// Configure broadcast
var ipBroadcastEndPoint = new IPEndPoint(IPAddress.Broadcast, 12301);
var broadcastServerEp = new IPEndPoint(IPAddress.Any, 0);
var broadcastClient = new UdpClient {EnableBroadcast = true};
broadcastClient.Client.Bind(_broadcastServerEp);
// Send a request:
broadcastClient.Send(requestData, requestData.Length, ipBroadcastEndPoint);
// Listen for a reply:
var broadcastserverEp = new IPEndPoint(IPAddress.Any, 0);
var broadcastserverResponseData = broadcastClient.Receive(ref broadcastserverEp);
Client side multicast:
var requestData = new byte[]{ /* Whatever */}
// Configure multicast
var ipMulticastEndPoint = new IPEndPoint(IPAddress.Parse("239.255.255.253"), 12302);
var multicastServerEp = new IPEndPoint(IPAddress.Any, 0);
var multicastClient = new UdpClient(AddressFamily.InterNetwork);
multicastClient.JoinMulticastGroup(IPAddress.Parse("239.255.255.253"), 32);
multicastClient.Client.Bind(_multicastServerEp);
// Send a request:
multicastClient.Send(requestData, requestData.Length, ipMulticastEndPoint);
// Listen for a reply:
var multicastserverEp = new IPEndPoint(IPAddress.Any, 0);
var multicastserverResponseData = multicastClient.Receive(ref multicastserverEp);
Server side broadcast:
// Listen for broadcast
Task.Run(() =>
{
var broadcastServer = new UdpClient(12301);
while(/**/)
{
var broadcastclientEp = new IPEndPoint(IPAddress.Any, 0);
var broadcastclientRequestData = broadcastServer.Receive(ref broadcastclientEp);
// Reply to broadcast:
var responseData = new byte[]{ /* Whatever */}
broadcastServer.Send(responseData, responseData.Length, broadcastclientEp);
}
}
Server side multicast:
// Listen for multicast
Task.Run(() =>
{
var multicastServer = new UdpClient(12302);
multicastServer.JoinMulticastGroup(IPAddress.Parse("239.255.255.253"));
while(/**/)
{
var multicastclientEp = new IPEndPoint(IPAddress.Any, 0);
var multicastclientRequestData = multicastServer.Receive(ref multicastclientEp);
// Reply to multicast:
var responseData = new byte[]{ /* Whatever */}
multicastServer.Send(responseData, responseData.Length, multicastclientEp);
}
}
If both client and server components are running on the same computer, both broadcast and multicast work as expected.
If both client and server components are on different computers in the same subnet, broadcast works, multicast works in one direction only (two computers in a given WLAN topology, multicast works when one of them is in the server role, but not the other way around).
If both client and server components are on different subnets in the same corporate network, neither broadcast or multicast works.
I'd like to get this to work reliably across subnets. From what I've learned so far, I know broadcast won't work, but multicast should.
Is there some magic to the selection of multicast addresses and/or port numbers? In other words, are there specific addresses and ports I should or should not be using for it to work reliably regardless of network topology? Are there address/port combinations which are customarily filtered or customarily kept open? Are there any configuration options I have overlooked?
Allowing multicast traffic to pass between subnets is controlled entirely by the routers between those subnets.
The routers need to be configured to either with static multicast routes, or to accept IGMP messages from hosts to set up multicast groups as they are joined.
I have this code, but I don't know if I am well connected or joined to the multicast group. I can send and receive messages through the normal IP "ip". But I don't know if I should do anything more to receive messages through multicast. I have this code:
public void UDPConnect()
{
socket = new UdpClient(25504);
try
{
endPoint = new IPEndPoint(IPAddress.Parse(ip), 2600);
socket.JoinMulticastGroup(IPAddress.Parse(multicastIP));
socket.Connect(endPoint);
byte[] sendBytes = Encoding.ASCII.GetBytes("Hello, from the client");
socket.Send(sendBytes, sendBytes.Length);
ConnectToServer();
}
catch (Exception e)
{
print("Exception thrown " + e.Message);
}
}
public void ConnectToServer()
{
InitializeClientData();
isConnected = true;
StartCoroutine(ClientSend.VisualStartupCor());
socket.BeginReceive(ReceiveCallback, null);
}
public void ReceiveCallback(IAsyncResult _result)
{
try
{
byte[] _data = socket.EndReceive(_result, ref endPoint);
socket.BeginReceive(ReceiveCallback, null);
if (_data.Length < 4)
{
Instance.Disconnect();
return;
}
HandleData(_data);
}
catch
{
Disconnect();
}
}
And this is my server code, just too simple. I just wanna to test if I can send and receive for the Client. As you can see, I have put the multicast IP that I use (231.1.1.10) in the Send method. When I send a message from the client, this server answers by sending the same message to the client. My client, in Unity, detects this message. It means that the multicast connection is successful?
var udp = require('dgram');
// --------------------creating a udp server --------------------
// creating a udp server
var server = udp.createSocket('udp4');
// emits when any error occurs
server.on('error',function(error){
console.log('Error: ' + error);
server.close();
});
// emits on new datagram msg
server.on('message',function(msg,info){
console.log('Data received from client : ' + msg.toString());
console.log('Received %d bytes from %s:%d\n',msg.length, info.address, info.port);
//sending msg
server.send(msg,info.port,'231.1.1.10',function(error){
if(error){
client.close();
}else{
console.log('Data sent !!!');
}
});
});
//emits when socket is ready and listening for datagram msgs
server.on('listening',function(){
var address = server.address();
var port = address.port;
var family = address.family;
var ipaddr = '192.XXX.X.XX';
console.log('Server is listening at port' + port);
console.log('Server ip :' + ipaddr);
console.log('Server is IP4/IP6 : ' + family);
console.log(address);
});
//emits after the socket is closed using socket.close();
server.on('close',function(){
console.log('Socket is closed !');
});
server.bind(2600);
UDP doesn't have a connected status, when you call a JoinMulticastGroup the socket sends a IGMP (Internet Group Management Protocol) packet to the service requesting membership to the multicast group.
If the client is accepted to the group, you can start receiving data on the socket
socket.BeginReceive(ReceiveCallback, null);
Basically there is no way to know if the server is going to send you a message, the point of UDP is to not maintain a connection. You could create a method to ping (send a message) the server and force it to multicast, which sort of looks like what you are trying to do with the "Hello, from the client" message
For more info on multicast groups check out this link
We have a web application running on server and it posts http requests via XDomainRequest (because of IE9).
There are lots of client computers which have a console application listening on a port via socket listener. Clients open web application with their
IE9 browsers and when they click on a link, the web page sends requests like that:
"https://localhost:portNumber/applicationName/doSomething"
"https://computerName:portNumber/applicationName/doSomething"
"https://ipAddress:portNumber/applicationName/doSomething"
The second and third requests are made to console applications of other users' computers.
The problem is that if requests come with localhost, console application does not have a problem about reading incoming data and sending response back. But
if the request comes with computer name or ip address then browser shows certification warning and wants user to click on
"Continue to this web site (not recommended)" link.
We thought creating three different certificates via code.
But even using sslstream with three of them is possible we cannot decide to select true certification because we make authenticatiton first and then receive data. So when we catch incoming request the authentication must already be done.
Another way is forcing socket listener or sslstream to behave all these three requests as if they are localhost. So for each one authentication will be made as localhost. But I could not find an actual way for that.
Here is the code. I give the code because maybe there is some wrong usage of SslStream.
using System;
using System.Net.Sockets;
using System.Net;
using System.Configuration;
using System.Security.Cryptography.X509Certificates;
using System.Windows.Forms;
using System.IO;
using System.Net.Security;
using System.Security.Authentication;
using System.Threading;
using System.Text;
namespace StackOverFlowProject
{
class StackOverFlowSample
{
private static ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
private static X509Certificate _cert = null;
static void Main(string[] args)
{
StackOverFlowSample stackOverFlowSample = new StackOverFlowSample();
stackOverFlowSample.StartListening();
}
private void StartListening()
{
GetCertificate();
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 1234);
if (localEndPoint != null)
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (listener != null)
{
listener.Bind(localEndPoint);
listener.Listen(10);
Console.WriteLine("Socket listener is running. Waiting for requests...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
}
}
private static void GetCertificate()
{
byte[] pfxData = File.ReadAllBytes(Application.StartupPath + #"\" + "localhost.pfx");
_cert = new X509Certificate2(pfxData, "password", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.Exportable);
}
private void AcceptCallback(IAsyncResult result)
{
Socket listener = null;
Socket handler = null;
StateObject state = null;
SslStream sslStream = null;
_manualResetEvent.Set();
listener = (Socket)result.AsyncState;
handler = listener.EndAccept(result);
state = new StateObject();
if (handler.RemoteEndPoint != null)
{
state.clientIP = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
}
sslStream = new SslStream(new NetworkStream(handler, true));
sslStream.AuthenticateAsServer(_cert, false, SslProtocols.Tls, true);
sslStream.ReadTimeout = 100000;
sslStream.WriteTimeout = 100000;
state.workStream = sslStream;
if (state.workStream.IsAuthenticated)
{
state.workStream.BeginRead(state.buffer, 0, StateObject.BufferSize, ReceiveCallback, state);
}
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
private void ReceiveCallback(IAsyncResult result)
{
StateObject stateObject = null;
SslStream sslStreamReader = null;
byte[] byteData = null;
stateObject = (StateObject)result.AsyncState;
sslStreamReader = stateObject.workStream;
int byteCount = sslStreamReader.EndRead(result);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(stateObject.buffer, 0, byteCount)];
decoder.GetChars(stateObject.buffer, 0, byteCount, chars, 0);
stateObject.sb.Append(chars);
if (byteCount > 0)
{
stateObject.totalReceivedBytes += byteCount;
string[] lines = stateObject.sb.ToString().Split('\n');
if (lines[lines.Length - 1] != "<EOF>")
{
// We didn't receive all data. Continue reading...
sslStreamReader.BeginRead(stateObject.buffer, 0, stateObject.buffer.Length, new AsyncCallback(ReceiveCallback), stateObject);
}
else
{
Console.WriteLine("We received all data. Sending response...");
byteData = Encoding.UTF8.GetBytes("Hello! I received your request!");
string httpHeaders = "HTTP/1.1" + "\r\n"
+ "Cache-Control: no-cache" + "\r\n"
+ "Access-Control-Allow-Origin: *" + "\r\n"
+ "\r\n";
byte[] byteHttpHeaders = Encoding.UTF8.GetBytes(httpHeaders);
byte[] concat = new byte[byteHttpHeaders.Length + byteData.Length];
Buffer.BlockCopy(byteHttpHeaders, 0, concat, 0, byteHttpHeaders.Length);
Buffer.BlockCopy(byteData, 0, concat, byteHttpHeaders.Length, byteData.Length);
stateObject.sslStreamReader = sslStreamReader;
sslStreamReader.BeginWrite(concat, 0, concat.Length, new AsyncCallback(SendCallback), stateObject);
}
}
}
private void SendCallback(IAsyncResult ar)
{
SslStream sslStreamSender = null;
StateObject stateObject = (StateObject)ar.AsyncState;
sslStreamSender = stateObject.sslStreamReader;
sslStreamSender.EndWrite(ar);
Console.WriteLine(stateObject.totalReceivedBytes.ToString() + " bytes sent to " + stateObject.clientIP + " address");
sslStreamSender.Close();
sslStreamSender.Dispose();
}
}
public class StateObject
{
public SslStream workStream = null;
public SslStream sslStreamReader = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
public string clientIP = "";
public int totalReceivedBytes = 0;
}
}
Your security guy is right. The way you are trying to make this happen wont work with SSL.
If you have a certificate, it is set to authenticate one CN. So, for an oversimplified example. Google has a certificate. It authenticates https://*.google.com. This means that any requests to google.com come up as having a valid certificate. And your browser is happy.
Now open a command prompt, ping google.com. Grab the ip address (in my case it came up as 216.58.210.14). Enter https://216.58.210.14. Your browser complains that the site is insecure etc. The reason being that the server may be the same one that served your earlier request, but the way you are getting to it is not valid according to the certificate,as the CN is not google.com, but an IP address.
So if you have a service which needs to connect to (for eg) 127.0.0.1, 10.92.1.4 AND myserver.com, you will need a cert which is valid for each case.
The certificate warning that you are encountering is really a name mismatch error, which indicates that the common name (domain name) in the SSL certificate does not match the URL/address used to access the web site/server.
https://www.sslshopper.com/ssl-certificate-name-mismatch-error.html
In your usage scenario, you may want to transition away from localhost and ip addresses in favor of a simple domain model that leverages the computer name. (e.g. computerName.someDomain.com)
Then, you could obtain a wildcard certificate (e.g. *.someDomain.com) which could be used to authenticate inter-process communication.
https://www.sslshopper.com/best-ssl-wildcard-certificate.html
I am not sure what your "https://computerName:portNumber/applicationName/doSomething" means. So not sure if you are using the certificate right or whether the paths/connection that you are accessing or using in code are correct. https://technet.microsoft.com/en-us/library/dd891009.aspx
It can access any protocol not restricted to TCP. https://technet.microsoft.com/en-us/library/cc784450(v=ws.10).aspx
Wildcard SSL Certificates allow admins to secure an unlimited number of subdomains on the same domain with a single SSL Certificate. A WildCard SSL Certificate is issued to *.yourdomain.com giving cost savings benefits from having to purchase numerous SSL Certificates for each subdomain, and also only require the use of one IP address.
Typical SSL Certificates only secure one Fully Qualified Domain Name. Unified Communications certificates allow you to assign multiple host names—known as Subject Alternative Names or SANs—in one certificate. For total flexibility, a Multi-Domain SSL Certificate allows the use of the Subject Alternative Name (SAN) field so you can secure up to 100 different domain names, sub-domains, or public IP addresses using a single SSL Certificate and requiring just one IP address.
** The value must match exactly with the hostname or domain name you access. Otherwise you will still receive browser certificate errors after the certificate has been imported and trusted. Eg: If you were previously using http://101.10.10.1:9000/ to access the site and the common name of your new certificate is "mydomain", then the shortcut should be updated to http://mydomain:9000/ ; if you created a certificate for mydomain:9000. Second, Use the hostname or CNAME by which you will address the server. This is very important. If your web server’s real hostname is mysubdomain.mydomain.com but people will be using www.mydomain.com to address the box, then use the latter name to answer the “Common Name” (CNAME) question.
** Check if you are able to connect using the openssl s_time -connect remote.host:443 (use specific ssl commands to troubleshoot, I am citing openssl) or the openssl s_time -connect remote.host:443 -www /test.html -new
** If you don’t have an SSL-enabled web server available for your use, you can emulate one using the s_server option.
# on one host, set up the server (using default port 4433)
openssl s_server -cert mycerti.pem -www
# on second host (or even the same one), run s_time
openssl s_time -connect mydomain:9001 -www / -new -ssl3
or
# on second host (or even the same one), run s_time
openssl s_time -connect mydomain:9001 -www / -new -ssl3
** Check if cert is in use?
$ openssl s_client -connect [ip_or_dns_name]:[port]
$ man s_client
Solution I am proposing is having assumption:
site is hosted on IIS
you can access application by machine name across network without any issue.
you need not to access webapp on internet(that will need cetificate from certified authority).
Try:
Create self signed certificate by IIS like :
i. Open IIS, select Server certificates like:
ii. Create self signed certificate like:
iii. configure website to use that certificate like:
select website, click bindings.
click edit bindings for https
iv. Edit site binding to use certificate you have created like :
Now you can access you application with machine name.
Same process you can repeat for domain certificates for internet but that requires certificate registered/provided by some certified authority.
Please note that now use can access application with Machine Name on both local & on network. Since certificate are issued for single host name/co-domain so use machine name instead of localhost on local machine too.
I tried creating a simple HTTP server using System.Net.HTTPListener, but it doesn't receive connections from other computers in the network. Example code:
class HTTPServer
{
private HttpListener listener;
public HTTPServer() { }
public bool Start()
{
listener = new HttpListener();
listener.Prefixes.Add("http://+:80/");
listener.Start();
listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
return true;
}
private static void ListenerCallback(IAsyncResult result)
{
HttpListener listener = (HttpListener)result.AsyncState;
listener.BeginGetContext(new AsyncCallback(ListenerCallback), listener);
Console.WriteLine("New request.");
HttpListenerContext context = listener.EndGetContext(result);
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
byte[] page = Encoding.UTF8.GetBytes("Test");
response.ContentLength64 = page.Length;
Stream output = response.OutputStream;
output.Write(page, 0, page.Length);
output.Close();
}
}
class Program
{
static void Main(string[] args)
{
HTTPServer test = new HTTPServer();
test.Start();
while (true) ;
}
}
Is there something wrong with this code, or is there another problem?
I've tried running the application with administrator privileges, but when I browse to the computer's IP address (i.e. 192.168.1.100) on another computer, I never receive the request. The server works fine if the request is sent from the same computer as where the application is running (using "localhost", "127.0.0.1" and "192.168.1.100"). Pinging works fine. I've also tried nginx, and that works perfectly over the network.
I'm using HTTPListener as a lightweight server to deliver a webpage with a Silverlight XAP file with some dynamic init params, clientaccesspolicy.xml and a simple mobile HTML page.
Firewall
I also thought first of the Firewall. However the problem where my endpoints:
From a tutorial I had a code like the following
String[] endpoints = new String[] {
"http://localhost:8080/do_something/",
// ...
};
This code only works locally and only if you use localhost. To be able to use the IP, I changed it to
String[] endpoints = new String[] {
"http://127.0.0.1:8080/do_something/",
// ...
};
This time the request by ip adress worked, but the server did not respond to remote requests from another ip. What got me working for me was to use a star (*) instead of localhost and 127.0.0.1, so the following code:
String[] endpoints = new String[] {
"http://*:8080/do_something/",
// ...
};
Just leaving this here if somebody stumbles upon this post as I did.