-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathEncryptEverything.cs
More file actions
298 lines (246 loc) · 9.09 KB
/
Copy pathEncryptEverything.cs
File metadata and controls
298 lines (246 loc) · 9.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#if LOL
using Reese.Common.Replayer;
using Reese.Core.Localization;
using System;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Reflection;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Terraria;
using Terraria.ID;
using Terraria.Localization;
using Terraria.ModLoader;
using Terraria.Net;
using Terraria.Net.Sockets;
namespace Reese;
// FIXME: cache/optimize reflection
// TODO :
// This class has been disabled because it prevents the server from starting, making us unable to use the recorder at all.
[Autoload(false)]
public class EncryptEverything : ModSystem
{
private class SslSocket : ISocket
{
private SslStream ssl;
// Cached remote address for serverbound connection or from clientbound connection.
private RemoteAddress remoteAddress;
private bool done;
private TcpListener listener;
private SocketConnectionAccepted acceptCallback;
public X509Certificate Certificate { get; set; }
private static X509Certificate GenerateSelfSignedServerCertificate()
{
var request = new CertificateRequest("cn=tModLoader Server", ECDsa.Create(), HashAlgorithmName.SHA256);
var now = DateTimeOffset.Now;
return request.CreateSelfSigned(now, now.AddYears(1));
}
public bool StartListening(SocketConnectionAccepted callback)
{
var address = IPAddress.Any;
if (Program.LaunchParameters.TryGetValue("-ip", out var value) && !IPAddress.TryParse(value, out address))
address = IPAddress.Any;
Certificate ??= GenerateSelfSignedServerCertificate();
listener ??= new TcpListener(address, 7777);
listener.Start();
listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);
acceptCallback = callback;
return true;
}
public bool IsConnected()
{
// FIXME: i have no clue!
return !done && ssl != null && ssl.IsAuthenticated;
}
private void OnAcceptTcpClient(IAsyncResult ar)
{
var tcpClient = listener.EndAcceptTcpClient(ar);
var ipEndPoint = (IPEndPoint)tcpClient.Client.RemoteEndPoint;
var remoteAddress = new TcpAddress(ipEndPoint.Address, ipEndPoint.Port);
var sslSocket = new SslSocket
{
ssl = new SslStream(tcpClient.GetStream()),
remoteAddress = remoteAddress
};
// FIXME: weirdly here maybe it okay tho, reaching into sslSocket to do this thing and give it a callback
sslSocket.ssl.BeginAuthenticateAsServer(Certificate, sslSocket.OnAuthenticateAsServer, acceptCallback);
listener.BeginAcceptTcpClient(OnAcceptTcpClient, null);
}
public void Close()
{
done = true;
ModLoader.GetMod("Reese").Logger.Info("ok gotta close socket");
if (ssl != null)
{
// FIXME: dispose async?
ssl.Dispose();
// ssl = null;
}
listener?.Dispose();
}
public void Connect(RemoteAddress address)
{
if (address is not TcpAddress tcpAddress)
throw new ArgumentException("address must be TcpAddress", nameof(address));
var tcpClient = new TcpClient();
tcpClient.BeginConnect(tcpAddress.Address, tcpAddress.Port, OnConnect, tcpClient);
remoteAddress = address;
}
private void OnConnect(IAsyncResult ar)
{
var tcpClient = (TcpClient)ar.AsyncState!;
tcpClient.EndConnect(ar);
// FIXME: dispose async?
ssl = new SslStream(tcpClient.GetStream(), false, ValidateRemoteCertificate);
ssl.BeginAuthenticateAsClient("tModLoader Server", OnAuthenticateAsClient, null);
}
private void OnAuthenticateAsClient(IAsyncResult ar)
{
ssl.EndAuthenticateAsClient(ar);
}
private void OnRead(IAsyncResult ar)
{
int length;
try
{
length = ssl.EndRead(ar);
}
catch (ObjectDisposedException)
{
done = true;
ModLoader.GetMod("Reese").Logger.Info($"EndRead whilst disposed prob ignore");
return;
}
catch (Exception e)
{
ModLoader.GetMod("Reese").Logger.Warn($"Fuck while EndRead {e}");
Close();
return;
}
if (length == 0)
{
ModLoader.GetMod("Reese").Logger.Warn("ZERO READ LEN so we close now");
Close();
return;
}
((Action<int>)ar.AsyncState!)(length);
}
private bool ValidateRemoteCertificate(object sender, X509Certificate x509Certificate, X509Chain chain,
SslPolicyErrors sslPolicyErrors)
{
ModLoader.GetMod("Reese").Logger.Info($"client saying YES to server cert {x509Certificate}");
return true;
}
public void AsyncSend(byte[] data, int offset, int size, SocketSendCallback callback, object state = null)
{
ssl.BeginWrite(data, offset, size, OnWrite, () => callback(state));
}
private void OnWrite(IAsyncResult ar)
{
try
{
ssl.EndWrite(ar);
}
catch (ObjectDisposedException)
{
done = true;
ModLoader.GetMod("Reese").Logger.Info("EndWrite whilst disposed prob ignore");
return;
}
catch (Exception e)
{
ModLoader.GetMod("Reese").Logger.Warn($"Fuck while EndWrite {e}");
Close();
return;
}
((Action)ar.AsyncState!)();
}
public void AsyncReceive(byte[] data, int offset, int size, SocketReceiveCallback callback, object state = null)
{
ssl.BeginRead(data, offset, size, OnRead, (int size) => callback(state, size));
}
public bool IsDataAvailable()
{
// FIXME: LOL NO?
return !done && ssl != null && ssl.IsAuthenticated;
}
public void SendQueuedPackets()
{
return;
}
private void OnAuthenticateAsServer(IAsyncResult ar)
{
ssl.EndAuthenticateAsServer(ar);
((SocketConnectionAccepted)ar.AsyncState!)(this);
}
public void StopListening()
{
listener.Stop();
}
public RemoteAddress GetRemoteAddress()
{
return remoteAddress;
}
}
public override void Load()
{
On_Netplay.InitializeServer += OnNetplayInitializeServer;
On_Netplay.ClientLoopSetup += OnNetplayClientLoopSetup;
On_Netplay.ServerLoop += OnNetplayServerLoop;
}
private void OnNetplayServerLoop(On_Netplay.orig_ServerLoop orig)
{
orig();
Log.Info("okay gonna kick disconnect and close all remote clients");
foreach (var remoteClient in Netplay.Clients)
{
if (!remoteClient.IsActive)
continue;
typeof(Netplay).GetMethod("KickClient", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null,
[remoteClient.Socket, NetworkText.FromLiteral("Server shutting down")]);
Player.Hooks.PlayerDisconnect(remoteClient.Id);
remoteClient.Reset();
}
}
private void OnNetplayClientLoopSetup(On_Netplay.orig_ClientLoopSetup orig, RemoteAddress address)
{
orig(address);
if (Playback.IsPlaying)
{
Log.Debug("Replay playback connection: skipping SSL socket replacement.");
return;
}
Netplay.Connection.Socket = new SslSocket();
}
public override void Unload()
{
if (Netplay.Connection.Socket is SslSocket)
{
Log.Error(
"We are unloading while the Netplay.Connection socket is an SslSocket! surely THIS IS WRONG!");
}
}
// FIXME: not big enough??
private const int RemoteClientReadBufferLength = 1024;
private void OnNetplayInitializeServer(On_Netplay.orig_InitializeServer orig)
{
Main.myPlayer = 255;
Netplay.ServerIP = IPAddress.Any;
Main.menuMode = MenuID.MultiplayerJoining;
Main.statusText = Loc.Get("ServerStartedSsl");
Main.netMode = NetmodeID.Server;
Netplay.Disconnect = false;
for (var i = 0; i < Netplay.MaxConnections; i++)
{
var client = new RemoteClient();
client.Reset();
client.Id = i;
client.ReadBuffer = new byte[RemoteClientReadBufferLength];
Netplay.Clients[i] = client;
}
Netplay.TcpListener = new SslSocket();
typeof(Netplay).GetMethod("StartListening", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, []);
}
}
#endif