I'm new to C# and I was wondering if it's possible to have a mechanism to check authorization similar to how a TCP client sends a decrypted password in its handshake packet. If not, how can I prevent unauthorized clients from connecting to my TCP server?
The code below shows where I accept each client and keep them in a TCPClientObject Array for further use later:
private void startTcpClientAccept()
{
while (true)
{
TCPClientObject temp = new TCPClientObject();
temp.setIndex(availableIndexes.Dequeue());
temp.setClient(server.AcceptTcpClient());
//I need the check mecanism here. before receiving any messages
clientList[temp.getIndex()] = temp;
Console.WriteLine("GSM Client is accepted");
}
}
Basically, the problem is anyone can connect to server and this may create some security problems further.
Related
I tried to use single server to serve both pure C# socket client (without ssl) and secure websocket client (with required ssl - wss). How does my server detect which type of client to serving? My server is written in C# too.
I tried use the Available property of Socket class. Websocket clients often has larger value than pure socket clients, but it doesn't seem to work. The value of Available is not stable.
Socket ClientSocket = Server.Accept();
if (/* condition to decide type of socket client */) // I tried but not work: ClientSocket.Available > 100
{
NetworkStream _stream = new NetworkStream(ClientSocket);
var ssl = new SslStream(_stream, false);
this.Authenticate(ClientSocket, ssl, ServerCertificate);
// call StartClient() after authenticating successfully
}
else
{
StartClient(ClientSocket);
}
I've got a little problem with the .Net Sockets in C#.
I programmed a client and a server working with TCP.
As the client is opened it sends a handshake to the server. The server answers with it's state (clientexists, clientaccepted,...). After that the application sends a getdata-request, abandons the connection and listens for the server's 'response'. Now, the server builds a connection to the client and sends all the data the client needs.
The code and everything else works, but the problem:
On our company testserver it works fine, on the live server only the handshake works. After it the client doesn't receive any more data. Serverapplication is the same on both servers.
I thought the problem was caused by some firewall (server wants to build a tcp connection to the client -> not good), but the system administrator said there is no firewall that could block that.
Now I'm searching for a ('cheap') solution that doesn't take too much time and changes in code. If anyone knows how to theoretically solve that, that would be great.
BTW: I am not allowed to do anything on the live server other than run the serverapplication. I don't have the possibility to debug on this server.
I can't publish all of my code, but if you need to see specific parts of it, ask for it please.
---EDIT---
Client-Server communication
1) Client startup
Client send handshake (new tcp connection)
2) Server validates handshake and saves IP
Server responds with it's client state (same tcp connection)
3) Client acknowledges this response and abandons this connection
Client sends getdata-request (new tcp connection)
Client abandons this tcp connection, too
4) Server receives getdata-request and collects the needed data in the main database
Server sends all the collected data to the client (multiple tcp connections)
5) Client receives all data and displays it in it's GUI (multiple tcp connections and the order of the data is kept by working with AutoResetEvents and Counts of sockets to send)
This is the main part my code does. It's by far not the best but it was for me as I wrote it I guess. Step one, two and three work as intended. The processing of the data works fine, too.
Another thing i forgot to mention is that the solution uses two Ports '16777' and '16778'. One to receive/listen and one to send.
My code is based on the MSDN example of the asynchronous server and client.
Sending a handshake (and getdata-request)
public void BeginSend(String data)
{
try
{
StateObject state = new StateObject();
state.workSocket = sender;
byte[] byteData = Encoding.UTF8.GetBytes(data);
sender.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback((IAsyncResult e) =>
{
Socket socket = (Socket)e.AsyncState;
SocketBase.StateObject stateObject = new SocketBase.StateObject();
stateObject.workSocket = socket;
socket.BeginReceive(stateObject.buffer, 0, 256, SocketFlags.None, new AsyncCallback(this.ReadCallback), (object)stateObject);
}), sender);
sender = RetrieveSocket(); //Socketreset
Thread.Sleep(100);
}
catch /*(Exception e)*/
{
//--
}
}
Server listener
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(System.Int32.MaxValue);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
//--
}
}
public void AcceptCallback(...);
public void ReadCallback(...);
Socket send
private void Send(Socket handler, String data)
{
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.UTF8.GetBytes(data);
// Begin sending the data to the remote device.
t.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), t);
}
Socket send all data part (answer to getdata-request | socToHandle should be the socket of the previous connection of the getdata-request)
private void SendAllData(Socket socToHandle, string PakContent)
{
#region IsThereADatetime? //Resolve a given datetime
#region GiveClientNumberOfPackets //Send the client info about how much he has to receive (See line below)
Send(socToHandle, "ALERT#TASKCOUNT;OPT-" + GetBestDate(dateStart) + EndSocket);
#region #SendResouces
#region #SendGroups
#region #SendTasks
}
Looking through my old code I have one idea =>
Could I send everything over the same connection by changing:
Socket t = RetrieveSocket(((IPEndPoint)handler.RemoteEndPoint).Address);
(which creates a new connection) to something that uses the same connection?
If that would work, how can I do that?
And would the listener part of the client still receive single packets?
Servers and their environment are configured to handle incoming requests properly. Clients are usually behind a router, which by default make them unable to receive incoming connections from outside their network (a good thing).
To enable incoming connections, you could configure your router to forward all requests for a certain port number to your machine. No one else on your network would be able to run the client then, though.
This is why in a typical multiple clients-single server environment, the client makes all the connections, and only the server requires any changes to the network landscape.
I don't know why you chose to connect to the clients from the server side, but I would strongly advise against this - any cheap solution that uses this mechanism may turn out to be very expensive in the end.
I am new to c# and I am building server / client application.
I have created both the server and the client successfully , but when any client connects to the server... I need to save that client because the server is supposed to send them a message after 10 minutes .
private void Form1_Load(object sender, EventArgs e) {
TcpListener myList;
myList = new TcpListener(IPAddress.Any, 8001);
while (true)
{
TcpClient client = myList.AcceptTcpClient();
MessageBox.Show("Connection accepted from " + client.Client.LocalEndPoint.ToString());
}
}
Now , my problem is how to save "client" id or anything about this client which is connected, to send message after 10 minutes from server to this client.
Can anyone help please?
Form onLoad is rather bad place to accept clients. Instead use ,for example, Background Worker. Also you might want to avoid using while(true) without any way to break the loop.
Object storage must be outside of method (event handler) to preserve connections from evil Garbage Collector. There are many ways to store object, it might be array (bothersome) or some collection, which although heavier to compute are pleasant to use. You can even use Concurent collections which will take care of thread synchronization on their own.
Dictionary<string,TcpClient> clientDict;
List<TcpClient> clientList;
...
void acceptClients()
{
TcpListener myList;
myList = new TcpListener(IPAddress.Any, 8001);
while (true)
{
TcpClient client = myList.AcceptTcpClient();
clientDict.Add("client nickname, id etc.",client);
clientList.Add(client);
MessageBox.Show("Connection accepted from " + client.Client.LocalEndPoint.ToString());
if (clientList.count>=8 || clientDict.count>=8)
{
break; // I want to break freeeeee!!!!
}
}
}
...
void sendToClient(string nick)
{
if (clientDict.ContainsKey(nick))
{
TcpClient client = clientDict[nick];
//and use selected client.
}
}
void broadcast()
{
foreach(TcpClient client in clientList) //clientList can be replaced with clientDict.Values
{
//and use selected client.
}
}
you would have to store the TCPClient in some list/dictionary. Regarding identifying connections you can use IP/Port in the TCPClient to differentiate between different connections.
Below is one such article i have posted to create a multi-threaded TCP chat application. it might be helpful.
http://shoaibsheikh.blogspot.com/2012/05/multi-threaded-tcp-socket-chat-server.html
The only possible way is to keep the connection open. Because many clients connect from behind NAT devices (corporate access points, home routers etc) is not possible to ask the client for a 'call back' address (IP:port).
What that mean in C# code, you need a reference to the client object you created in AcceptTcpClient. When you want to send something, you must retrieve this object and Write something into the client's stream (obtained via client.GetStream()). How exactly this is accomplished, it depends entirely on your code. A Dictionary perhaps? Do expect the connection to had closed by then for various reasons, even if KeepAlive is set.
Note that having a large number of accepted connections is not feasible (for many reasons).
I have a server that accepts async socket connections from multiple clients. Right now I am assigning them a server-side unique ID dependent on their incoming IP address & port. My concern is - what if 2 clients connect from the same IP & behind an NAT. Is there a better way to determine this?
private static int DetermineSocketToConnectionID(Socket handler)
{
int connectionIDForHandler = 0;
string uniqueIPString = handler.RemoteEndPoint.ToString();
if (Client1Buffers.UserIPAddress == uniqueIPString)
{
connectionIDForHandler = 1;
}
if (Client2Buffers.UserIPAddress == uniqueIPString)
{
connectionIDForHandler = 2;
}
return connectionIDForHandler;
}
You may be better off having those clients authenticate themselves with the server on their first connection and pass you something you can use to identify them other than trusting network information. This is exactly why sessions and cookies were created for logging in clients to web servers. You can do something similar by handshaking with the client and passing them back a uid, which they would then need to pass back to the server on each subsequent connect.
I am getting Access Denied exception while trying to open a socket.
My connect function is as shown.
internal void Connect()
{
try
{
//AccessPolicy = new SocketClientAccessPolicyProtocol();
args = new SocketAsyncEventArgs();
args.UserToken = socket;
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnConnect);
**isConnected = socket.ConnectAsync(args);**
//autoEvent.WaitOne();
if (args.SocketError != SocketError.Success)
throw new SocketException((int)args.SocketError);
if(isConnected)
global::System.Windows.MessageBox.Show("Connected");
}
catch (Exception ex)
{
global::System.Windows.MessageBox.Show(ex.Message);
}
}
The function ConnectAsync however is executing fine as isConnected is coming true but socket is not getting connected.
http://drdobbs.com/windows/208403238
Looking through the code you'll see that it uses the TcpListener class to listen for incoming client connections. Once a client connects the code checks the request for the following value: <policy-file-request/>
Silverlight automatically sends this text to the policy file socket once it connects. If the request contains the proper value the code writes the contents of the client access policy back to the client stream (see the OnReceiveComplete() method). Once the policy file is received, Silverlight parses it, checks that it allows access to the desired port, and then accepts or rejects the socket call that the application is trying to make.
If this is Silverlight in the browser, you need a socket policy server in the mix. See http://msdn.microsoft.com/en-us/library/cc645032%28v=vs.95%29.aspx for details.