I am working with an application that receives a file by a TCP protocol, the application processes the file and then sends it by the same protocol, i am receiving the file without problems, my problem is when i try to send the file, because i need to send the file to another application that is listening a Dynamic port, the code that i am using to send these files is:
internal void Send(byte[] buffer)
{
TcpClient _client = null;
try
{
_client = new TcpClient(RemoteIPaddress, Dynamic_port);
if (_client != null)
{
NetworkStream _clienttStream = _client.GetStream();
_clienttStream.Write(buffer, 0, buffer.Length);
_clienttStream.Flush();
_clienttStream.Close();
_clienttStream = null;
}
}
catch
{
if (_client != null)
{
_client.Close();
_client = null;
}
}
}
The question is, how can i send a file by TCP protocol to a remote machine that uses a dynamic port
Typically, the server should listen on a well known port for a connection request. The response should include the port number that the server will communicate further on. Then your app connects to that port for transferring the data.
The communication should do the following:
Client connects to server on well known port.
Server responds with the dynamic port number to use for further communication.
Client connects to server on the received port number.
Server responds stating connection established.
Client transmits data and disconnects.
This is a simplified version of how passive FTP works.
Point is, there are only two ways to connect to a server on a dynamic port. The first way is outlined above. If you can't do it that way then your client app will have to do a port scan, sending a connection attempt to every port within a range, and see which one the server responds on. However, firewalls are generally programmed to notice this type of thing and shut you down (it's hacker behavior).
Are you asking how you can determine the dynamic port that the remote machine has selected to use? There is no automated way to do this. The server should either work on a port that both machines are aware of or you should work out a way for them to select a port through some other mode of communication. Either by connecting to a 3rd party server or hosting a web service that the client can access.
Related
I've created two apps (A client and a server) which can communicate with each other as long as I input the local IP address of the machine the server app is running on into the client app (in code).
I would like the client app to automatically discover the local IP address of the machine running the server app and connect to it, so they can be run on any network without the need to enter the IP in code.
Both of these apps with be running on the same network (ie. Over WiFi, not the Internet)
Here is what I have so far in my client app:
// COMMUNICATE WITH SERVER
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.35"), 8888);
public Console()
{
InitializeComponent();
client.Connect(serverEndPoint);
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
In this example I can only connect to a server running on "192.168.2.35", I would like it to be able to find the server running on port 8888 on any machine on the network.
Alternatively, if this isn't possible I would like the server to broadcast its IP as a message (of some sort) and have the client receive this message and verify it is the server and connect to it.
I think my second example is the proper way to do this, but I can't seem to wrap my head around how to get it working (I'm fairly new to C#), and any other examples I've found I can't seem to get to work with my applications.
Here is my server code if it helps answer my question:
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
TcpClient client = this.tcpListener.AcceptTcpClient();
connectedClients++;
lblNumberOfConnections.Text = connectedClients.ToString();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
Thanks
EDIT: I've tried adding THIS to my project, but being so new I'm unsure how to implement it properly, and it didn't get me anywhere.
2nd EDIT: I've tried implementing a UDP broadcast a few times now, with no luck on any attempt yet. My latest attempt was at implementing THIS (minus the chat parts). I just can't seem to get a UDP broadcast working at all with my project, as it seems to be way over my head at my current skill level. Unfortunately, having my client automatically connect to the server is 100% necessary for my project to function...
My other problem, which is maybe best to start a separate question for, but somewhat correlates to this issue is: My client GUI consists of a panel that switches between multiple custom classes, each containing different buttons, etc. (works similar to tab pages) that communicate to the server I'm trying to connect to. Once I get the UDP broadcast figured out, will I need to code that into every class separately? or is there a way of having all classes running in my panel connect to the same server?
A simple, but possibly costly(in terms of network traffic) solution would be for your server application to broadcast over UDP it's application and connection info. Your client could listen for all broadcast packets that have your servers custom header. Assuming a connection is made you could stop the broadcast. The downside is you would have to be broadcasting constantly if a client is not connected and this can clog your network if there aren't limits placed on the broadcast speed.
EDIT: Here is a boiled down explanation generated from the MSDN article https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
EDIT #2: I've expanded on this answer on my blog, as well as provided downloadable example projects. the article can be found at http://martialdeveloper.com/wordpress/?p=21
1. Find your network's broadcast IP
A special “Broadcast Address” must be used when using UDP for the purpose of sending a datagram to all machines connected to a given network. For example, the typical home network host/gateway of 192.168.0.1 has a broadcast address of 192.168.0.255. If your network differs from this you can use an IPv4 broadcast address calculator like the one found here http://jodies.de/ipcalc
Or read the introductory section on MSDN describing the broadcast address. https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
2. Select a listening/broadcast port
Any port that is free on your client & server is fine. The MSDN example uses 11000. This port number is used in your broadcaster, and listener.
3. Code for the Listener
Note to the reader. All error handling has been omitted for clarity of the example.
int listenPort = 11000;
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any,listenPort);
while (!done) // This loop listens for your broadcast packets
{
Console.WriteLine("Waiting for broadcast");
byte[] bytes = listener.Receive( ref groupEP);
Console.WriteLine("Received broadcast from {0} :\n {1}\n",
groupEP.ToString(),
Encoding.ASCII.GetString(bytes,0,bytes.Length));
}
listener.Close();
Note: The third parameter to Console.WriteLine, "Encoding.ASCII..." represents the string value sent over UDP in the datagram packet. This contains the desired negotiation information for a discovery situation, such as the IP address of the client or server you wish to connect to.
4. Code for the Broadcaster
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse("This string should be the broadcast IP address"); //NOTE: Broadcast IP goes here!!
byte[] sendbuf = Encoding.ASCII.GetBytes("This is the message string to be broadcast"); //Your message to the client/server goes here, I.E. an
// app/client name or ID and an IP to connect with over TCP
IPEndPoint ep = new IPEndPoint(broadcast, 11000);
s.SendTo(sendbuf, ep);
Console.WriteLine("Message sent to the broadcast address");
NOTE: This is a very simple example. The broadcaster may need to rebroadcast for a period of time to make sure the Listener receives it. Even after the UDP datagram is sent/received there will need to be some negotiation to ensure the TCP connection is made properly.
I'm trying to develop a transparent proxy which forwards unsecured http traffic from the clients as secured https traffic to the server, and back again. To better illustrate my point, take a look at the following image.
Let's suppose that for various reasons the clients will be using HTTP only, they can't use port 443 for HTTPS. Since some servers don't accept traffic from port 80, my proxy needs to reroute them to port 443. This is a possible scenario:
Receive data from client which are headed to port 80 towards www.google.com
Initialize connection with https://www.google.com to port 443 (Do the handshake and so on)
Encrypt data from client and send them to https://www.google.com to port 443.
Receive response from https://www.google.com, decrypt them and send them back to the client to port 80.
Since this is a transparent proxy, the clients (in my case lots of them) shouldn't need any extra configuration. The network is already configured so that their traffic go through my node. Currently my node simply reroutes the data and blocks some if they contain viruses. This is done using WinPcap to get access to low networking layers but I'm willing to change my approach if it's too hard to be done using raw packets (mainly concerned about the handshake).
What I've tried:
Note: www.google.com could be any site on the web. It's merely used as an example.
Iridium's suggestion. This doesn't work for the reason that TcpListener only accepts a new connection if another application uses a TcpClient to connect to it. Since this is a transparent proxy, it doesn't work.
Using HttpListener instead. However, it seems that this doesn't work since it only accepts connections to my own IP (not www.google.com).
Using HttpListener as before but this time I'm forwarding packets to my own IP so that HttpListener accepts the connection. For some reason, this doesn't seem to work (Inspected through wireshark and TCP SYN packets keep re-sending, not sure why or how to fix it).
Using SslStream to connect to https://www.google.com, then getting the contents from the raw packets received from the clients and writing them to the stream. This doesn't work since SslStream handles TCP packets (Such as ACK or SYN) on its own. The stream expects only Http requests. Another reason why it doesn't work is because I can't read the contents of TCP packets from the stream, only the contents of HTTP responses (So the client is sat there waiting for an ACK).
Forwarding TCP packets from the client as they are to port 443 and from the server to port 80 (Since only HTTP requests and responses are encrypted with SSL, it wouldn't make a difference) and using the HttpRequest class to make all the http requests and responses (Since the class handles the handshake on its own). This doesn't work because the ACKs are wrong on both sides.
What would be the best way to go into developing such a proxy?
Edit: Is there ANY way that TcpListener or HttpListener can act as a transparent proxy? (Without configuration on the clients' computers). When exactly does HttpListener recognize that a client is trying to connect?
I don't really understand why you need to read the encrypted data from the SslStream. If I'm reading your description correctly, you should simply need to:
Wait for a client connection
When a client connects, connect to the server
Wrap the server connection's NetworkStream in an SslStream and AuthenticateAsClient
Once authenticated, in parallel:
Read data from the client and write it to the SslStream
Read data from the SslStream and write it to the client
I don't see anywhere in this process that you'd need to see the encrypted data from the SslStream.
The following is a very basic sample (though completely untested):
static void Main(string[] args)
{
var listener = new TcpListener(IPAddress.Any, 11180);
var clientConnection = listener.AcceptTcpClient();
// When we get here, the client has connected, initiate the server connection
var serverConnection = new TcpClient("your.server.name", 443);
var serverStream = serverConnection.GetStream();
var secureStream = new SslStream(serverStream);
secureStream.AuthenticateAsClient("your.server.name");
ConnectStreams(clientConnection.GetStream(), secureStream);
}
private static void ConnectStreams(Stream streamA, Stream streamB)
{
ForwardStream(streamA, streamB, new byte[1024]);
ForwardStream(streamB, streamA, new byte[1024]);
}
private static void ForwardStream(Stream source, Stream destination, byte[] buffer)
{
source.BeginRead(buffer, 0, buffer.Length, r => Forward(source, destination, r, buffer), null);
}
private static void Forward(Stream source, Stream destination, IAsyncResult asyncResult, byte[] buffer)
{
var bytesRead = source.EndRead(asyncResult);
if (bytesRead == 0)
{
destination.Close();
return;
}
destination.Write(buffer, 0, bytesRead);
ForwardStream(source, destination, buffer);
}
I have the following setup:
Dedicated server --> Internet --> Modem (telenet) --> Router --> client
The client initiates a tcp connection with the server to register itself on the server, and gives through following info:
mac address of the client
external ip; this is retrieved by using webclient string download from whatsmyip.org
Some updates occur on the server and of course the client needs to be notified, so the client can start a sync session on its own:
To notify the client, the server sends a udp packet from the server to the modem (to the external ip, earlier received from the client), in the meanwhile the client is listening for udp packets behind the router.
The problem is that I'm not receiving any packets.. Is my scenario possible, what should I do?
Requirements:
Solving this by enabling port-forwarding on the router isn't an option
The server has a fixed ip
The client can be disconnected from the internet, at times
The solution has to work on different kinds of routers
Both ports at which packets are send & received are the same
All programming is done in C#
The server notifies the client when there is an update, the client may never poll the server for updates to prevent overload (in case several clients are doing this the same time)
Greets Daan & thanks in advance
EDIT:
Code example from server:
UdpClient udpSender = new UdpClient();
IPEndPoint localServerGateway = new IPEndPoint(IPAddress.Parse(externalIp), 8003);
string message = "testmessage";
byte[] messageBytes = Encoding.ASCII.GetBytes(message);
try
{
udpSender.Send(messageBytes, messageBytes.Length, localServerGateway);
}
catch (Exception error)
{
Console.WriteLine("Error while sending message: " + error.ToString());
}
udpSender.Close();
Code example from client:
private void listenForMasterSyncRequest()
{
bool done = false;
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 8003);
try
{
while (!done)
{
byte[] bytes = masterSyncUdpListener.Receive(ref groupEP);
handleMessage(bytes, bytes.Length, true); // handles incoming messages, this is never reached because no packets are received :-(
}
}
catch (Exception e)
{
Console.WriteLine("An error occured while listening to server broadcast updates: " + e.ToString());
}
finally
{
masterSyncUdpListener.Close();
}
}
NAT works by setting up sessions between external and internal hosts. But the session must be initiated on the internal side, and in your case that's the client side. So the way it has to work is that the client has to poll the server, sending a UDP packet to a particular port on the server asking if a sync is needed. The server must send a UDP response from that same port back to the same port the client sent the original request. If you do it this way packets from the server will get through, otherwise they will not. I know this works because this is exactly how DNS lookups work from behind NAT.
Since you don't have control of the NAT devices in the path, the only sane way here is to use TCP as your main transport.
I have a web service on a server in my company that we have restricted access to from all but one other server on our network.
I do however need to make calls to this from another machine. Is there a way I can spoof the other servers IP address in order to send an http request to the web service? I only need to send it info I don't need any returned data. It's for logging hits from another server on our main server.
I am using this
IPEndPoint endpointAddress = new IPEndPoint(IPAddress.Parse(ipAddress), 80);
using (Socket socket = new Socket(endpointAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp))
{
socket.SendTimeout = 500;
socket.Connect(endpointAddress);
socket.Send(byteGetString, byteGetString.Length, 0);
}
but get an exception
A connection attempt failed because
the connected party did not properly
respond after a period of time, or
established connection failed because
connected host has failed to respond
23.202.147.163:80
In general, it is not possible to establish a TCP connection with a server without being able to receive and process some reply packets from that server. HTTP is built upon TCP, and TCP starts communications with a "3-way handshake" that lets the client and server communicate.
The start of an HTTP request is not a single packet.
You could use a proxy to bounce your requests from an IP address that has access.
I've got a strange problem. I have a client sending packets to my server, but my servers UDP socket never receives them. Same thing happens the other way around, if I send and he tries to receive.
Check this image, captured from wireshark:
http://img263.imageshack.us/img263/2636/bokus.png
I hav bound my UDP socket to EndPoint 192.168.2.3, which is the internal IP of the server, and port 9998.
The client sends data to my IP, which should then be forwarded to the local server machine..
As you can see wireshark clearly detects incomming packets for 192.168.2.3 with destination port 9998 but nothing gets delivered!
(...why does it say distinct32 btw in destination port?)
Something else to watch for is make sure any firewall you might running has a rule setup to allow communications on your port 9998.
If I had to guess (would need to see your recieving C# code to know), It looks like you might be trying to receive UDP packets but using TCP protocol on the client side. (Or i might just be misunderstanding some of the text of your screenshot.)
Theres no need to 'listen' for a connection when using UDP. UDP packets don't have a connect/disconnect protocol. Nor do they guarantee that packets are received in the same order they're sent.
try using something along these lines in your C# client and see if you get data.
var udpClient = new System.Net.Sockets.UdpClient(9998);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);