Proxy Socket Managing - c#

I'm trying to create a transparent proxy with c#. i was able to transfer my network traffic into my proxy client and redirect it to my proxy server. it's working, but i have 2 problems,
1- It's slow, max speed is 60kbps, here is how i transfer traffic between my server and proxy client
while (SocketConnected(tcp_link.Client) &&
SocketConnected(_tcp.Client) &&
!ioError)
{
try
{
Thread.Sleep(1);
if (streamLink.DataAvailable)
{
byte[] l_buffer = new byte[4096];
int l_read = streamLink.Read(l_buffer, 0, l_buffer.Length);
byte[] l_data = new byte[l_read];
Array.Copy(l_buffer, l_data, l_data.Length);
byte[] l_send = MBR.reverse(l_data);
_stream.Write(l_send, 0, l_send.Length);
}
if (_stream.DataAvailable)
{
byte[] c_buffer = new byte[4596];
int c_read = _stream.Read(c_buffer, 0, c_buffer.Length);
byte[] c_data = new byte[c_read];
Array.Copy(c_buffer, c_data, c_data.Length);
byte[] c_send = MBR.reverse(c_data);
streamLink.Write(c_send, 0, c_send.Length);
}
}
catch (Exception ex)
{
onErrorLog(this, new ErrorLogEventArgs(ex));
ioError = true;
}
}
my other question is: when should i close my socket? and which one should get closed first? is http server going to close connection with my proxy server or i should disconnect?
sorry for my back english

I think it's not a problem with mere logic but rather about handling the parallelism. I have used SocketAsyncEventArgs for implementing a high performance, async TCP server and it shines.
A good article can be found here.

Related

wss WebSocket server in Mono C# : SslStream gives me no data but Stream do

Since days I'm trying to get (JS)wss/(c#)SslStream connection to work in order to create a wss server in mono c#.
My Problem : When an incomming secure WebSocket connection is accepted by the server, I can't get data from it in order to begin the handshake process.
What I did so far :
I setup a TCPListener that accept the client giving me a TCPClient instance.
I get the stream from the TCPClient and create a SslStream from it.
I synchronously authenticate it with AuthenticateAsServer(X509Certificate2)
I unsuccessfully try to read data
Other details :
I note that if I use a Stream object instead of an SslStream one, I succed in getting data from it (but crypted as expected)
I tested to connect my WebSoket to same adress/port to Fleck (built on my box with Monodevelop too) using the same pfx certificate and got it working properly
I note also that Fleck throw messages saying it recieve 0 byte, then it close the connection and (in some way) reconnect it and get data properly from Socket/SslStream.
I don't get any error, SslStream seem to be correctly authenticated
I correctly connect clients in https and deal with requests on an another port in the same program
My Configuration :
OS : ArchLinux
C# : Mono .Net Framework 4.7
Browsers (Chromium & Firefox)
Despite of all my research so far I've not found the solution , maybe someone can help me to wonder what I miss here ...
Thanks in advance for any help !
The listen code :
public void AudioListen ()
{
audioComListener.Start ();
while (isAudioActive) {
TcpClient s = audioComListener.AcceptTcpClient ();
Stream clientStream;
string hellostr;
clientStream = getClientStream(s);
if(debugCommuncation)
{
logToFileLine("(KEY) HandShaking begins with "+s.Client.RemoteEndPoint.ToString ().Split (':') [0]);
}
if(!WebSocketHandshake(clientStream))
{
if(debugCommuncation)
{
logToFileLine("(KEY) (X) HandShake read 0 byte from "+s.Client.RemoteEndPoint.ToString ().Split (':') [0]);
}
s.Close();
return;
}
else
{
logToFileLine("(KEY) HandShaking OK with "+s.Client.RemoteEndPoint.ToString ().Split (':') [0]);
}
hellostr=streamReadLine(clientStream);
if(hellostr.IndexOf("hello:")==0)
{
string usrstr=hellostr.Split(':')[1];
User usr= Users.GetUser(usrstr);
if(usr!=null)
{
usr.TcpC=s;
User usrdest=usr.corresp;
if( usrdest!=null &&
usrdest.ByPass==null &&
usrdest.TcpC!=null)
{
Stream clientStream2 = getClientStream(usrdest.TcpC);
usr.ByPass=new TCPByPass(clientStream,clientStream2);
usrdest.ByPass=usr.ByPass;
}
}
}
Thread.Sleep (1);
};
}
Function to get the SslStream :
private Stream getClientStream(TcpClient s,bool forceHTTP=false)
{
Stream clientStream;
if(isSSL && !forceHTTP)
{
clientStream = new SslStream (s.GetStream ());
((SslStream)clientStream).AuthenticateAsServer(SrvCert);
// Set timeouts for the read and write to 5 seconds.
/**/clientStream.ReadTimeout = 5000;
clientStream.WriteTimeout = 5000;
//SecuDiag.MakeAllDiag(((SslStream)clientStream));
}
else
{
clientStream=s.GetStream ();
}
return clientStream;
}
Function that try to get data for hanshake purpose :
public bool WebSocketHandshake(Stream clientStream)
{
string hellostr;
// Here I test trying to get data (Also tried to use Stream.ReadByte())
Byte[] toto=new Byte[2048];
((SslStream)clientStream).Read(toto,0,2048);
if(toto[0]==0)return false;
Console.WriteLine("#############################################");
Console.WriteLine("toto array is {0} bytes long",toto.Length);
for(int t =0;t<10;t++)
{
for(int u =0;u<10;u++)
{
Console.Write(toto[t*10+u].ToString());
}
Console.WriteLine(";");
}
Console.WriteLine("#############################################");
// Trying to get data
//hellostr=streamReadLine(clientStream);
//Console.WriteLine(hellostr);
return true;
}
I think I solved the problem. I don't understand why, but I think its necessary to close the accepted connection just after accepting it iaoi the connection is wss. The the websocket wil automagically reconnect :)

Can't send large data from Android through TCP socket

I'm trying to send an array of bytes from android (client) to Linux (server), I can send around 17kB but then the socket send an client socket timeout exception. At the server side I'm using netcat with the next command:
nc -l -p 55000 > out.txt
This works ok because I'm capable of sending files from other computer, for this reason I think the problem is at the client side (Android).
I'm using Visual Studio 2015 with Xamarin to compile the project and I tried many methods to send thought socket with the same result, between 15~20kB sended. Of course the permissions on Android to send through internet and other rights are ok.
This is the first mode I tried:
byte[] data = new byte[200000];
TcpClient client = new TcpClient("192.168.0.245", 55000);
client.SendBufferSize = 8192;
NetworkStream ns = client.GetStream();
ns.ReadTimeout = 1000;
ns.WriteTimeout = 1000;
ns.Write(data, 0, data.Length);
ns.Flush();
ns.Close();
client.Close();
With this method only around 17kB are received and the socket is not closed, but the close methods are executed (I tested it with the debugger placing MessageBox to test in release).
Other method I've tested is this:
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.245"), 55000);
System.Net.Sockets.Socket sender = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.ExclusiveAddressUse = true;
sender.LingerState = new LingerOption(true, 1);
sender.NoDelay = true;
sender.SendBufferSize = 8192;
sender.ReceiveBufferSize = 8192;
sender.SendTimeout = 1000;
sender.ReceiveTimeout = 1000;
sender.Ttl = 42;
try{
byte[] data = new byte[200000];
sender.Connect(remoteEP);
for (int a = 0; a < data.Length;)
{
int len = (data.Length - a) > 8192 ? 8192 : data.Length - a;
a += sender.Send(data, a, len, SocketFlags.None);
}
}
catch (Exception e)
{
string a = e.ToString();
}
The program send the first 8192 bytes and in the second round an socket timeout exception is trowed. If I try to send all the bytes is one time the program executes the send method the returned bytes are the total length of the array, this mean all bytes are sent to the socket but only received 17kB.
I've tested other methods to do the same thing with the same results in two phones. The android version for compiler I'm using is 4.2. For VS and Xamarin the latest.
Also I tried to download an app from the market to send files throught TCP to see if the problem is in Netcat, firewalls, SO or other and the files was sended ok.... I'm very frustated, I think I'm doing well all the things.
Thanks in advance

C# Tcp is losing packets?

I wrote a C# chat software that uses a new (at least for me) system that I called request system. I don't know if that has been created before, but for now I think of it as my creation :P
Anyhow, this system works like this:
soc receives a signal
checks the signal
if the data it just received is the number 2, the client software knows that the server is about to send a chat message. if the number is 3, so the client knows that the server is about to send the member list, and so on.
The problem is this: when I do step-by-step in VS2012 it works fine, the chat is working properly. When I use it on debug mode or just run it on my desktop, there seems to be missing data, and it shouldn't be because the code is working just fine...
Example of code for the sending&receiving message on client:
public void RecieveSystem()
{
while (true)
{
byte[] req = new byte[1];
soc.Receive(req);
int requestID = int.Parse(Encoding.UTF8.GetString(req));
if (requestID == 3)
{
byte[] textSize = new byte[5];
soc.Receive(textSize);
byte[] text = new byte[int.Parse(Encoding.UTF8.GetString(textSize))];
soc.Receive(text);
Dispatcher.Invoke(() => { ChatBox.Text += Encoding.UTF8.GetString(text) + "\r\n"; });
}
}
}
public void OutSystem(string inputText)
{
byte[] req = Encoding.UTF8.GetBytes("3");
soc.Send(req);
byte[] textSize = Encoding.UTF8.GetBytes(Encoding.UTF8.GetByteCount(inputText).ToString());
soc.Send(textSize);
byte[] text = Encoding.UTF8.GetBytes(inputText);
soc.Send(text);
Thread.CurrentThread.Abort();
}
and on the server:
public void UpdateChat(string text)
{
byte[] req = Encoding.UTF8.GetBytes("3");
foreach (User user in onlineUsers)
user.UserSocket.Send(req);
byte[] textSize = Encoding.UTF8.GetBytes(Encoding.UTF8.GetByteCount(text).ToString());
foreach (User user in onlineUsers)
user.UserSocket.Send(textSize);
byte[] data = Encoding.UTF8.GetBytes(text);
foreach (User user in onlineUsers)
user.UserSocket.Send(data);
}
public void RequestSystem(Socket soc)
{
~~~
}
else if (request == 3)
{
byte[] dataSize = new byte[5];
soc.Receive(dataSize);
byte[] data = new byte[int.Parse(Encoding.UTF8.GetString(dataSize))];
soc.Receive(data);
UpdateChat(Encoding.UTF8.GetString(data));
}
}
catch
{
if (!soc.Connected)
{
Dispatcher.Invoke(() => { OnlineMembers.Items.Remove(decodedName + " - " + soc.RemoteEndPoint); Status.Text += soc.RemoteEndPoint + " Has disconnected"; });
onlineUsers.Remove(user);
Thread.CurrentThread.Abort();
}
}
}
}
What could be the problem?
You're assuming that you'll have one packet for each Send call. That's not stream-oriented - that's packet-oriented. You're sending multiple pieces of data which I suspect are coalesced into a single packet, and then you'll get them all in a single Receive call. (Even if there are multiple packets involved, a single Receive call could still receive all the data.)
If you're using TCP/IP, you should be thinking in a more stream-oriented fashion. I'd also encourage you to change the design of your protocol, which is odd to say the least. It's fine to use a length prefix before each message, but why would you want to encode it as text when you've got a perfectly good binary connection between the two computers?
I suggest you look at BinaryReader and BinaryWriter: use TcpClient and TcpListener rather than Socket (or at least use NetworkStream), and use the reader/writer pair to make it easier to read and write pieces of data (either payloads or primitives such as the length of messages). (BinaryWriter.Write(string) even performs the length-prefixing for you, which makes things a lot easier.)

Incomplete data received across network from C# to Arduino

I am trying to send a word over to an Arduino running as a server, from a WPF C# application. Every now and again the complete work is not sent.
C# Code
public void send(String message)
{
TcpClient tcpclnt = new TcpClient();
ConState.Content = "Connecting.....";
try
{
tcpclnt.Connect("192.168.0.177", 23);
ConState.Content = "Connected";
String str = message;
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
stm.Write(ba, 0, ba.Length);
tcpclnt.Close();
}
catch (Exception)
{
ConState.Content = "Not Connected";
return;
}
}
How it is sent to the method:
String mes = "back;";
send(mes);
Arduino code:
if (client.available() > 0) {
// Read the bytes incoming from the client:
char thisChar = client.read();
if (thisChar == ';')
{
//Add a space
Serial.println("");
}
else {
//Print because it's not a space
Serial.write(thisChar);
}
}
The Arduino is using the chat server example. I am sending "back;" and "forward;" across. The results on the serial monitor:
back
forwaback
forward
back
forwaforwar
The problem seems to be with this code:
if (client.available() > 0) {
// read the bytes incoming from the client:
char thisChar = client.read();
...
}
What it does is:
Check if we have received data from the client
Read a single byte from the client buffer
Exit, and go on to do other things
As the OP pointed out, this comes direct from Arduino chat server example. In that example, this working correctly in loop() depends on the alreadyConnected flag being set right after a new connection is made: if it isn't, then the buffer is flushed before any data is read. That's one possible landmine.
Nonetheless, there is no reason to change the if block to be a while loop in the OP's case so, in other words instead of
if (client.available() > 0) {
have
while (client.available() > 0) {
The only reason to have an if statement there is to make sure that you frequently do other processing in loop() if you have clients that send a lot of data: If the reading of client data is done from inside a while this loop will not exit until the there is no more data from the client. Since this doesn't seem to be an issue in the asked-about case, the if to while change makes sense.

c# Socket Closing

I'm working on a http proxy application, everything is working fine (client can connect to server and get contents), the problem is neither of HTTP Server or browser close the TCP connection.. I'm not sure if I'm doing it right, here is the code:
while (tcp_link.Connected && _tcp.Connected && !ioError)
{
try
{
Thread.Sleep(100);
if (streamLink.DataAvailable)
{
byte[] l_buffer = new byte[10000];
int l_read = streamLink.Read(l_buffer, 0, l_buffer.Length);
byte[] l_data = new byte[l_read];
Array.Copy(l_buffer, l_data, l_data.Length);
_stream.Write(l_data, 0, l_data.Length);
}
if (_stream.DataAvailable)
{
byte[] c_buffer = new byte[10500];
int c_read = _stream.Read(c_buffer, 0, c_buffer.Length);
byte[] c_data = new byte[c_read];
Array.Copy(c_buffer, c_data, c_data.Length);
streamLink.Write(c_data, 0, c_data.Length);
}
}
catch
{
ioError = true;
}
}
I have same code both sides (proxy client, and proxy server)
NOTE: browser will connect to proxy client (which is on the same computer), and proxy client will connect to proxy server, and obviously proxy server will connect to http server, the reason is i wan't to encode data before sending it out
How long have you observed the connection open for?
It's very likely that the client uses HTTP 1.1 where Persistent Connections are on by default.
If you're writing a proxy then you should consider: http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html
Okay i found the problem, who ever is out there having problem with closing socket connection..
Actually, Socket.Available isn't working as i expected, to see if a socket is really connected you should check both Available and Poll properties, below function should resolve your problem: thanks to: zendar
bool SocketConnected(Socket s)
{
bool part1 = s.Poll(1000, SelectMode.SelectRead);
bool part2 = (s.Available == 0);
if (part1 & part2)
return false;
else
return true;
}
i hope this solve your problem too ;)

Categories

Resources