the squid in second platoon
f
This commit is contained in:
parent
b49acd08d4
commit
331c050540
10 changed files with 145 additions and 51 deletions
23
protocol.md
23
protocol.md
|
@ -271,16 +271,31 @@ Communication between the master server and clients will be done over a WebSocke
|
|||
<th>#</th>
|
||||
<th>Region</th>
|
||||
<th>Type</th>
|
||||
<th>if</th>
|
||||
</thead>
|
||||
<tr>
|
||||
<td class="center">1</td>
|
||||
<td>Succeeded</td>
|
||||
<td>Boolean</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<tr style="border-bottom: 2px solid;">
|
||||
<td class="center">2</td>
|
||||
<td>Message</td>
|
||||
<td>String</td>
|
||||
<td>R<sub>1</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">2</td>
|
||||
<td>Session Id</td>
|
||||
<td>Packed Unsigned Long</td>
|
||||
<td>¬R<sub>1</sub></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="center">3</td>
|
||||
<td>Secret</td>
|
||||
<td>Bytes (16)</td>
|
||||
<td>¬R<sub>1</sub></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -430,8 +445,12 @@ Communication between the master server and clients will be done over a WebSocke
|
|||
<th colspan="100" class="center">
|
||||
ID 4: Server List Request<br />
|
||||
[Encrypted] Requester<br />
|
||||
<i>Bodyless Packet</i>
|
||||
</th>
|
||||
<thead>
|
||||
<th colspan="100" class="center">
|
||||
<i>Bodyless Packet</i>
|
||||
</th>
|
||||
</thead>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace SockScape.Encryption {
|
|||
try {
|
||||
var ms = new MemoryStream(data);
|
||||
var cs = new CryptoStream(ms,
|
||||
new TripleDESCryptoServiceProvider().CreateEncryptor(Key, IV),
|
||||
new TripleDESCryptoServiceProvider().CreateDecryptor(Key, IV),
|
||||
CryptoStreamMode.Read);
|
||||
|
||||
byte[] ret = new byte[data.Length];
|
||||
|
|
|
@ -48,8 +48,10 @@ namespace SockScape {
|
|||
serverHandle.Start();
|
||||
}
|
||||
|
||||
//var server = new Server<PlayerConnection>(6770, PoolManager.Pending);
|
||||
//server.Start();
|
||||
if(Configuration.General["Run Master"])
|
||||
MasterIntraServer.Initialize();
|
||||
|
||||
MasterIntraClient.Initialize();
|
||||
|
||||
/*while(true) {
|
||||
var send = Console.ReadLine();
|
||||
|
@ -60,7 +62,9 @@ namespace SockScape {
|
|||
|
||||
Console.ReadLine();
|
||||
|
||||
//server.Stop();
|
||||
MasterIntraClient.Close();
|
||||
if(Configuration.General["Run Master"])
|
||||
MasterIntraServer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ namespace Glove.INI {
|
|||
public double Dbl
|
||||
=> this;
|
||||
|
||||
public bool Bool
|
||||
=> this;
|
||||
|
||||
public static implicit operator string(Value value)
|
||||
=> value.Raw;
|
||||
|
||||
|
|
|
@ -2,29 +2,39 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Glove;
|
||||
|
||||
namespace SockScape {
|
||||
static class MasterServerList {
|
||||
public static Dictionary<UInt16, Server> Servers { get; }
|
||||
private static Dictionary<UInt16, Server> _Servers
|
||||
= new Dictionary<UInt16, Server>();
|
||||
|
||||
public static Dictionary<UInt16, Server> Servers {
|
||||
get {
|
||||
lock(_Servers) {
|
||||
return _Servers.ToDictionary(x => x.Key,
|
||||
x => x.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(Server server) {
|
||||
lock(Servers) {
|
||||
if(HasId(server.Id) && !Servers[server.Id].Address.Equals(server.Address))
|
||||
lock(_Servers) {
|
||||
if(HasId(server.Id) && !_Servers[server.Id].Address.Equals(server.Address))
|
||||
Console.WriteLine($"{DateTime.Now.ToShortTimeString()} - Server {server.Id} has changed IP addresses.");
|
||||
|
||||
Servers[server.Id] = server;
|
||||
_Servers[server.Id] = server;
|
||||
}
|
||||
}
|
||||
|
||||
public static Packet ReportPacket {
|
||||
get {
|
||||
lock(Servers) {
|
||||
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)Servers.Count).Pack());
|
||||
foreach(var server in Servers)
|
||||
lock(_Servers) {
|
||||
var packet = new Packet(kInterMasterId.ServerListing, ((ushort)_Servers.Count).Pack());
|
||||
foreach(var server in _Servers)
|
||||
// TODO change this to support IPv6
|
||||
packet.AddRegions(server.Key.Pack(), server.Value.UserCount.Pack(),
|
||||
server.Value.Address.MapToIPv4().ToString(), server.Value.Port.Pack());
|
||||
|
@ -34,11 +44,24 @@ namespace SockScape {
|
|||
}
|
||||
}
|
||||
|
||||
public static bool HasId(UInt16 id)
|
||||
=> Servers.ContainsKey(id);
|
||||
public static void RemoveServersByOwners(IEnumerable<MasterIntraServer.Client> owners) {
|
||||
lock(_Servers) {
|
||||
_Servers = _Servers.Where(x => !owners.Contains(x.Value.Owner))
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clear()
|
||||
=> Servers.Clear();
|
||||
public static bool HasId(UInt16 id) {
|
||||
lock(_Servers) {
|
||||
return _Servers.ContainsKey(id);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Clear() {
|
||||
lock(_Servers) {
|
||||
_Servers.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Server {
|
||||
|
@ -46,5 +69,6 @@ namespace SockScape {
|
|||
public ushort UserCount { get; set; }
|
||||
public IPAddress Address { get; set; }
|
||||
public ushort Port { get; set; }
|
||||
public MasterIntraServer.Client Owner { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RunPostBuildEvent>OnBuildSuccess</RunPostBuildEvent>
|
||||
<RunPostBuildEvent>Always</RunPostBuildEvent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Kneesocks;
|
||||
using Glove;
|
||||
using SockScape.DAL;
|
||||
using SockScape.Encryption;
|
||||
|
||||
namespace SockScape {
|
||||
|
@ -18,7 +20,7 @@ namespace SockScape {
|
|||
}
|
||||
|
||||
protected override void OnParse() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
protected override void OnReceive(byte[] data) {
|
||||
|
@ -31,6 +33,11 @@ namespace SockScape {
|
|||
return;
|
||||
}
|
||||
|
||||
if(packet.Id != (int)kInterMasterId.KeyExchange && Encryptor == null) {
|
||||
Disconnect(Frame.kClosingReason.ProtocolError, "You must exchange keys before performing any other operations.");
|
||||
return;
|
||||
}
|
||||
|
||||
switch((kInterMasterId)packet.Id) {
|
||||
case kInterMasterId.KeyExchange:
|
||||
Key.ParseResponsePacket(packet);
|
||||
|
@ -42,10 +49,17 @@ namespace SockScape {
|
|||
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||
break;
|
||||
case kInterMasterId.LoginAttempt:
|
||||
if(packet.RegionCount != 2)
|
||||
break;
|
||||
|
||||
using(var db = new ScapeDb()) {
|
||||
if(db.Users.)
|
||||
}
|
||||
break;
|
||||
case kInterMasterId.RegistrationAttempt:
|
||||
|
||||
using(var db = new ScapeDb()) {
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Disconnect(Frame.kClosingReason.ProtocolError, "Packet ID could not be understood at this time.");
|
||||
|
|
|
@ -12,6 +12,7 @@ using SockScape.Encryption;
|
|||
namespace SockScape {
|
||||
static class MasterIntraClient {
|
||||
private static Key Key;
|
||||
private static BlockCipher Encryptor;
|
||||
|
||||
private static UdpClient Sock;
|
||||
private static Thread ListeningThread;
|
||||
|
@ -32,6 +33,12 @@ namespace SockScape {
|
|||
ushort port = (ushort)Configuration.General["Master Port"];
|
||||
Sock = new UdpClient(Configuration.General["Master Addr"], port);
|
||||
|
||||
// TODO figure out what this has to do with ICMP (in server too)
|
||||
uint IOC_IN = 0x80000000,
|
||||
IOC_VENDOR = 0x18000000,
|
||||
SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||
Sock.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] {0}, null);
|
||||
|
||||
Key = new Key();
|
||||
Encryptor = null;
|
||||
|
||||
|
@ -42,19 +49,22 @@ namespace SockScape {
|
|||
|
||||
public static void Listener() {
|
||||
while(IsOpen) {
|
||||
var endPoint = new IPEndPoint(0, 0);
|
||||
var endPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
while(Sock.Available > 0) {
|
||||
var data = Sock.Receive(ref endPoint);
|
||||
LastMessageIn = DateTime.Now;
|
||||
|
||||
bool readRaw = Encryptor == null
|
||||
|| data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber);
|
||||
|
||||
Packet packet =
|
||||
Encryptor == null ? Packet.FromBytes(data)
|
||||
: Packet.FromBytes(Encryptor.Parse(data));
|
||||
readRaw ? Packet.FromBytes(data)
|
||||
: Packet.FromBytes(Encryptor.Decrypt(data));
|
||||
|
||||
switch((kIntraMasterId)packet.Id) {
|
||||
case kIntraMasterId.KeyExchange:
|
||||
var responsePacket = Key.ParseRequestPacket(packet);
|
||||
Encryptor = new StreamCipher(Key.PrivateKey);
|
||||
Encryptor = new BlockCipher(Key.PrivateKey);
|
||||
if(responsePacket != null)
|
||||
Send(responsePacket);
|
||||
else
|
||||
|
@ -62,16 +72,14 @@ namespace SockScape {
|
|||
break;
|
||||
|
||||
case kIntraMasterId.PositiveAck:
|
||||
Console.WriteLine($"Packet type {packet[0]} accepted by master");
|
||||
Console.WriteLine($"Packet type {packet[0].Raw[0]} accepted by master");
|
||||
break;
|
||||
|
||||
case kIntraMasterId.NegativeAck:
|
||||
Console.WriteLine($"Packet type {packet[0]} declined by master for reason {packet[1]}");
|
||||
Console.WriteLine($"Packet type {packet[0].Raw[0]} declined by master for reason {packet[1].Str}");
|
||||
break;
|
||||
|
||||
case kIntraMasterId.EncryptionError:
|
||||
NextSendId = NextRecvId = 0;
|
||||
Buffer.Clear();
|
||||
Key = new Key();
|
||||
Encryptor = null;
|
||||
LastMessageIn = new DateTime(0);
|
||||
|
@ -79,12 +87,12 @@ namespace SockScape {
|
|||
}
|
||||
}
|
||||
|
||||
if(LastMessageIn.Ticks != 0) {
|
||||
if(Encryptor != null) {
|
||||
if(DeltaLastOut.TotalSeconds > 2)
|
||||
Send(Encryptor.Parse(ServerContext.StatusUpdatePacket.GetBytes()));
|
||||
SendEncrypted(ServerContext.StatusUpdatePacket);
|
||||
} else
|
||||
if(DeltaLastOut.TotalSeconds > 10)
|
||||
Send(new Packet(kIntraSlaveId.InitiationAttempt, Configuration.General["Master Secret"]));
|
||||
Send(new Packet(kIntraSlaveId.InitiationAttempt, Configuration.General["Master Secret"].Str));
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
@ -94,11 +102,13 @@ namespace SockScape {
|
|||
Send(packet.GetBytes());
|
||||
}
|
||||
|
||||
public static void SendEncrypted(Packet packet) {
|
||||
Send(Encryptor.Encrypt(packet.GetBytes()));
|
||||
}
|
||||
|
||||
public static void Send(byte[] bytes) {
|
||||
Sock.Send(bytes, bytes.Length);
|
||||
LastMessageOut = DateTime.Now;
|
||||
Buffer.Add(NextSendId, bytes);
|
||||
++NextSendId;
|
||||
}
|
||||
|
||||
public static void Close() {
|
||||
|
|
|
@ -12,7 +12,7 @@ using SockScape.DAL;
|
|||
using SockScape.Encryption;
|
||||
|
||||
namespace SockScape {
|
||||
static class MasterUdpServer {
|
||||
static class MasterIntraServer {
|
||||
private static Dictionary<string, Client> Prospects;
|
||||
private static Dictionary<string, Client> Clients;
|
||||
|
||||
|
@ -30,7 +30,13 @@ namespace SockScape {
|
|||
|
||||
ushort port = (ushort)Configuration.General["Master Port"];
|
||||
Sock = new UdpClient(new IPEndPoint(IPAddress.Any, port));
|
||||
|
||||
|
||||
// TODO figure out what this has to do with ICMP (in client too)
|
||||
/*uint IOC_IN = 0x80000000,
|
||||
IOC_VENDOR = 0x18000000,
|
||||
SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
|
||||
Sock.Client.IOControl((int)SIO_UDP_CONNRESET, new byte[] {0}, null);*/
|
||||
|
||||
IsOpen = true;
|
||||
ListeningThread = new Thread(Listener);
|
||||
ListeningThread.Start();
|
||||
|
@ -38,7 +44,7 @@ namespace SockScape {
|
|||
|
||||
public static void Listener() {
|
||||
while(IsOpen) {
|
||||
IPEndPoint endPoint = new IPEndPoint(0, 0);
|
||||
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
while(Sock.Available > 0) {
|
||||
var data = Sock.Receive(ref endPoint);
|
||||
var client = endPoint.ToString();
|
||||
|
@ -48,7 +54,7 @@ namespace SockScape {
|
|||
|
||||
Packet packet =
|
||||
encryptor == null ? Packet.FromBytes(data)
|
||||
: Packet.FromBytes(encryptor.Parse(data));
|
||||
: Packet.FromBytes(encryptor.Decrypt(data));
|
||||
|
||||
if(packet == null) {
|
||||
if(encryptor != null)
|
||||
|
@ -56,7 +62,11 @@ namespace SockScape {
|
|||
continue;
|
||||
}
|
||||
|
||||
Clients[client].LastReceive = DateTime.Now;
|
||||
if(IsProspectConnected(client) && encryptor == null)
|
||||
Prospects[client].LastReceive = DateTime.Now;
|
||||
else if(IsClientConnected(client) && encryptor != null)
|
||||
Clients[client].LastReceive = DateTime.Now;
|
||||
|
||||
switch((kIntraSlaveId)packet.Id) {
|
||||
case kIntraSlaveId.InitiationAttempt:
|
||||
if(packet.RegionCount != 1 || IsProspectConnected(client))
|
||||
|
@ -81,7 +91,7 @@ namespace SockScape {
|
|||
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
||||
if(privateKey != -1) {
|
||||
Prospects[client].LastReceive = DateTime.Now;
|
||||
Prospects[client].Encryptor = new StreamCipher(privateKey);
|
||||
Prospects[client].Encryptor = new BlockCipher(privateKey);
|
||||
Clients[client] = Prospects[client];
|
||||
Prospects.Remove(client);
|
||||
} else
|
||||
|
@ -92,7 +102,7 @@ namespace SockScape {
|
|||
if(!IsClientConnected(client) || packet.RegionCount < 1)
|
||||
break;
|
||||
|
||||
if(packet.CheckRegions(0, 1)) {
|
||||
if(!packet.CheckRegions(0, 1)) {
|
||||
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
||||
break;
|
||||
}
|
||||
|
@ -104,14 +114,15 @@ namespace SockScape {
|
|||
}
|
||||
|
||||
for(byte i = 0; i < serverCount; ++i) {
|
||||
if(!packet.CheckRegions(2 + 3 * i, 2, 2, 2))
|
||||
if(!packet.CheckRegions(1 + 3 * i, 2, 2, 2))
|
||||
continue;
|
||||
|
||||
MasterServerList.Write(new Server {
|
||||
Id = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
||||
UserCount = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
||||
Id = packet[1 + 3 * i].Raw.UnpackUInt16(),
|
||||
UserCount = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
||||
Address = endPoint.Address,
|
||||
Port = packet[4 + 3 * i].Raw.UnpackUInt16()
|
||||
Port = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
||||
Owner = Clients[client]
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -120,7 +131,12 @@ namespace SockScape {
|
|||
}
|
||||
}
|
||||
|
||||
Prospects = Prospects.Where(x => x.Value.ReceiveDelta.Seconds < 10)
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
|
||||
var expiredClients = Clients.Where(x => x.Value.ReceiveDelta.Seconds > 60).Select(x => x.Value).ToList();
|
||||
if(expiredClients.Count > 0)
|
||||
MasterServerList.RemoveServersByOwners(expiredClients);
|
||||
|
||||
Thread.Sleep(1);
|
||||
}
|
||||
|
@ -149,23 +165,23 @@ namespace SockScape {
|
|||
return Clients.ContainsKey(client);
|
||||
}
|
||||
|
||||
private static void PositiveAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id) {
|
||||
Send(cipher.Parse(new Packet(kIntraMasterId.PositiveAck, id).GetBytes()), endPoint);
|
||||
private static void PositiveAck(IPEndPoint endPoint, BlockCipher cipher, kIntraSlaveId id) {
|
||||
Send(cipher.Encrypt(new Packet(kIntraMasterId.PositiveAck, (byte)id).GetBytes()), endPoint);
|
||||
}
|
||||
|
||||
private static void NegativeAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
||||
Send(cipher.Parse(new Packet(kIntraMasterId.NegativeAck, id, message).GetBytes()), endPoint);
|
||||
private static void NegativeAck(IPEndPoint endPoint, BlockCipher cipher, kIntraSlaveId id, string message = "An error occurred while parsing a packet.") {
|
||||
Send(cipher.Encrypt(new Packet(kIntraMasterId.NegativeAck, (byte)id, message).GetBytes()), endPoint);
|
||||
}
|
||||
|
||||
private static void EncryptionError(IPEndPoint endPoint, string message = "A general encryption error has occurred. Renegotiation required.") {
|
||||
Send(new Packet(kIntraMasterId.EncryptionError, message), endPoint);
|
||||
}
|
||||
|
||||
class Client {
|
||||
public class Client {
|
||||
public IPEndPoint Address { get; set; }
|
||||
public DateTime LastReceive { get; set; }
|
||||
public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
|
||||
public StreamCipher Encryptor { get; set; }
|
||||
public BlockCipher Encryptor { get; set; }
|
||||
public Key Key { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ namespace SockScape {
|
|||
Regions.Add((byte[])region);
|
||||
else if(region.GetType() == typeof(string))
|
||||
Regions.Add(((string)region).GetBytes());
|
||||
else if(region.GetType() == typeof(byte))
|
||||
Regions.Add(new[] { (byte)region });
|
||||
else
|
||||
Console.WriteLine($"Could not add region {region} of type {region.GetType()}.");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -104,7 +108,7 @@ namespace SockScape {
|
|||
return false;
|
||||
|
||||
for(int i = 0; i < lengths.Length; ++i) {
|
||||
if(this[startIndex + i].Raw.Length == lengths[i])
|
||||
if(this[startIndex + i].Raw.Length != lengths[i])
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue