diff --git a/NETCODE REWRITE DESIGN PLAN.html b/NETCODE REWRITE DESIGN PLAN.html
index e13b7e4ef..358f87832 100644
--- a/NETCODE REWRITE DESIGN PLAN.html
+++ b/NETCODE REWRITE DESIGN PLAN.html
@@ -17,6 +17,7 @@ body {
Hacking is really easy
Lag is really hard to hide
It'll eventually be unusable because of new stuff being added
+Client and server shares code, requiring security checks on the server's side which are too easy to miss
Goals of rewrite
@@ -24,10 +25,11 @@ body {
- Authoritative server; less hacking
- More secure code
- Maybe better interpolation; make lag less noticeable
+- Make client and server code as isolated from each other as possible
How new netcode will work
Authentication
-Login encryption will be essentially the same as it is now. Hash of hashed password + nonce.
+Login encryption consists of sending a hash of hashed password with the nonce appended.
Authentication will be split into two steps:
diff --git a/Subsurface/Source/Networking/GameClient.cs b/Subsurface/Source/Networking/GameClient.cs
index d4d1aef3a..26f3e75cd 100644
--- a/Subsurface/Source/Networking/GameClient.cs
+++ b/Subsurface/Source/Networking/GameClient.cs
@@ -34,7 +34,6 @@ namespace Barotrauma.Networking
private bool requiresPw;
private int nonce;
private string saltedPw;
- NetEncryption algo;
public byte ID
{
@@ -151,14 +150,6 @@ namespace Barotrauma.Networking
updateInterval = new TimeSpan(0, 0, 0, 0, 150);
- if (reconnectBox==null)
- {
- reconnectBox = new GUIMessageBox("CONNECTING", "Connecting to " + serverIP, new string[] { "Cancel" });
-
- reconnectBox.Buttons[0].OnClicked += CancelConnect;
- reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
- }
-
CoroutineManager.StartCoroutine(WaitForStartingInfo());
// Start the timer
@@ -204,11 +195,19 @@ namespace Barotrauma.Networking
bool CanStart = false;
DateTime timeOut = DateTime.Now + new TimeSpan(0,0,20);
- DateTime reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 3);
+ DateTime reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 1);
// Loop until we are approved
while (!CanStart && !connectCancelled)
{
+ if (reconnectBox == null)
+ {
+ reconnectBox = new GUIMessageBox("CONNECTING", "Connecting to " + serverIP, new string[] { "Cancel" });
+
+ reconnectBox.Buttons[0].OnClicked += CancelConnect;
+ reconnectBox.Buttons[0].OnClicked += reconnectBox.Close;
+ }
+
int seconds = DateTime.Now.Second;
string connectingText = "Connecting to " + serverIP;
@@ -249,11 +248,10 @@ namespace Barotrauma.Networking
outmsg.Write(GameMain.SelectedPackage.Name);
outmsg.Write(GameMain.SelectedPackage.MD5hash.Hash);
outmsg.Write(name);
- outmsg.Encrypt(algo);
client.SendMessage(outmsg, NetDeliveryMethod.Unreliable);
}
}
- reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 3);
+ reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 1);
}
yield return CoroutineStatus.Running;
@@ -275,15 +273,19 @@ namespace Barotrauma.Networking
switch (header)
{
case ServerPacketHeader.AUTH_RESPONSE:
- if (inc.ReadBoolean())
+ if (needAuth)
{
- //requires password
- nonce = inc.ReadInt32();
- requiresPw = true;
- }
- else
- {
- requiresPw = false;
+ if (inc.ReadBoolean())
+ {
+ //requires password
+ nonce = inc.ReadInt32();
+ requiresPw = true;
+ }
+ else
+ {
+ requiresPw = false;
+ }
+ needAuth = false; //got auth!
}
break;
case ServerPacketHeader.AUTH_FAILURE:
@@ -291,10 +293,15 @@ namespace Barotrauma.Networking
pwMsg = inc.ReadString();
requiresPw = true;
break;
+ case ServerPacketHeader.UPDATE_LOBBY:
+ //server accepted client
+ CanStart = true;
+ break;
}
break;
case NetIncomingMessageType.StatusChanged:
- if (client.ConnectionStatus == NetConnectionStatus.Disconnected)
+ NetConnectionStatus connectionStatus = (NetConnectionStatus)inc.ReadByte();
+ if (connectionStatus == NetConnectionStatus.Disconnected)
{
string denyMessage = inc.ReadString();
@@ -312,8 +319,14 @@ namespace Barotrauma.Networking
break;
}
- if (requiresPw && needAuth)
+ if (requiresPw && !CanStart && !connectCancelled)
{
+ if (reconnectBox != null)
+ {
+ reconnectBox.Close(null, null);
+ reconnectBox = null;
+ }
+
var msgBox = new GUIMessageBox(pwMsg, "", new string[] { "OK", "Cancel" });
var passwordBox = new GUITextBox(new Rectangle(0, 40, 150, 25), Alignment.TopLeft, GUI.Style, msgBox.children[0]);
passwordBox.UserData = "password";
@@ -323,7 +336,19 @@ namespace Barotrauma.Networking
while (GUIMessageBox.MessageBoxes.Contains(msgBox))
{
- while (client.ReadMessage() != null) {} //clear incoming message queue until client sends password request
+ while (client.ReadMessage() != null) {
+
+ }
+
+ if (DateTime.Now > reqAuthTime)
+ {
+ //request auth again to prevent timeout
+ NetOutgoingMessage reqAuthMsg = client.CreateMessage();
+ reqAuthMsg.Write((byte)ClientPacketHeader.REQUEST_AUTH);
+ client.SendMessage(reqAuthMsg, NetDeliveryMethod.Unreliable);
+ reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 3);
+ }
+
okButton.Enabled = !string.IsNullOrWhiteSpace(passwordBox.Text);
if (okButton.Selected)
@@ -331,11 +356,9 @@ namespace Barotrauma.Networking
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(passwordBox.Text)));
saltedPw = saltedPw + Convert.ToString(nonce);
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
- algo = new NetXtea(client, saltedPw);
timeOut = DateTime.Now + new TimeSpan(0, 0, 20);
- reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 0);
- needAuth = false;
+ reqAuthTime = DateTime.Now + new TimeSpan(0, 0, 1);
msgBox.Close(null, null);
break;
@@ -352,11 +375,11 @@ namespace Barotrauma.Networking
}
}
}
-
- if (reconnectBox != null)
- {
- reconnectBox.Close(null, null);
- reconnectBox = null;
+
+ if (reconnectBox != null)
+ {
+ reconnectBox.Close(null, null);
+ reconnectBox = null;
}
if (connectCancelled) yield return CoroutineStatus.Success;
diff --git a/Subsurface/Source/Networking/GameServer.cs b/Subsurface/Source/Networking/GameServer.cs
index 8eea8577a..f9d1d094b 100644
--- a/Subsurface/Source/Networking/GameServer.cs
+++ b/Subsurface/Source/Networking/GameServer.cs
@@ -423,15 +423,11 @@ namespace Barotrauma.Networking
}
else
{
- if ((ClientPacketHeader)inc.ReadByte() == ClientPacketHeader.REQUEST_AUTH)
+ if ((ClientPacketHeader)inc.SenderConnection.RemoteHailMessage.ReadByte() == ClientPacketHeader.REQUEST_AUTH)
{
inc.SenderConnection.Approve();
ClientAuthRequest(inc.SenderConnection);
}
- else
- {
- inc.SenderConnection.Deny("GAY");
- }
}
break;
}
diff --git a/Subsurface/Source/Networking/GameServerLogin.cs b/Subsurface/Source/Networking/GameServerLogin.cs
index cc554f5fe..4db954c06 100644
--- a/Subsurface/Source/Networking/GameServerLogin.cs
+++ b/Subsurface/Source/Networking/GameServerLogin.cs
@@ -22,7 +22,7 @@ namespace Barotrauma.Networking
Connection = connection;
Nonce = nonce;
- AuthTimer = 5.0f;
+ AuthTimer = 10.0f;
failedAttempts = 0;
}
@@ -56,6 +56,7 @@ namespace Barotrauma.Networking
unauthClient = new UnauthenticatedClient(conn, nonce);
unauthenticatedClients.Add(unauthClient);
}
+ unauthClient.AuthTimer = 10.0f;
//if the client is already in the queue, getting another unauth request means that our response was lost; resend
NetOutgoingMessage nonceMsg = server.CreateMessage();
nonceMsg.Write((byte)ServerPacketHeader.AUTH_RESPONSE);
@@ -94,8 +95,6 @@ namespace Barotrauma.Networking
string saltedPw = password;
saltedPw = saltedPw + Convert.ToString(unauthClient.Nonce);
saltedPw = Encoding.UTF8.GetString(NetUtility.ComputeSHAHash(Encoding.UTF8.GetBytes(saltedPw)));
- NetEncryption algo = new NetXtea(server, saltedPw);
- inc.Decrypt(algo);
string clPw = inc.ReadString();
if (clPw != saltedPw)
{
@@ -115,6 +114,7 @@ namespace Barotrauma.Networking
reject.Write((byte)ServerPacketHeader.AUTH_FAILURE);
reject.Write("Wrong password!");
server.SendMessage(reject, unauthClient.Connection, NetDeliveryMethod.Unreliable);
+ unauthClient.AuthTimer = 10.0f;
return;
}
}
@@ -190,6 +190,13 @@ namespace Barotrauma.Networking
newClient.Connection = unauthClient.Connection;
unauthenticatedClients.Remove(unauthClient);
unauthClient = null;
+
+ //TEMPORARY TEST CODE; MUST REMOVE
+ NetOutgoingMessage testMsg = server.CreateMessage();
+ testMsg.Write((byte)ServerPacketHeader.UPDATE_LOBBY);
+ server.SendMessage(testMsg, newClient.Connection, NetDeliveryMethod.Unreliable);
+ //END TEMPORARY TEST CODE
+
return;
}
}