2017-06-16 21:00:01 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Sockets;
|
2017-09-07 21:00:03 +00:00
|
|
|
|
using System.Security.Cryptography;
|
2017-06-16 21:00:01 +00:00
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
2017-08-30 21:02:51 +00:00
|
|
|
|
using Glove;
|
2017-09-06 20:59:38 +00:00
|
|
|
|
using SockScape.DAL;
|
2017-08-30 21:02:51 +00:00
|
|
|
|
using SockScape.Encryption;
|
2017-06-16 21:00:01 +00:00
|
|
|
|
|
2017-08-29 20:14:44 +00:00
|
|
|
|
namespace SockScape {
|
2017-06-16 21:00:01 +00:00
|
|
|
|
static class MasterUdpServer {
|
2017-08-30 21:02:51 +00:00
|
|
|
|
private static Dictionary<string, Client> Prospects;
|
|
|
|
|
private static Dictionary<string, Client> Clients;
|
|
|
|
|
|
2017-06-16 21:00:01 +00:00
|
|
|
|
private static UdpClient Sock;
|
2017-08-21 21:03:32 +00:00
|
|
|
|
private static Thread ListeningThread;
|
|
|
|
|
private static bool IsOpen;
|
2017-06-16 21:00:01 +00:00
|
|
|
|
|
|
|
|
|
public static void Initialize() {
|
2017-08-28 21:15:10 +00:00
|
|
|
|
if(IsOpen || ListeningThread != null)
|
2017-06-16 21:00:01 +00:00
|
|
|
|
return;
|
2017-09-06 20:59:38 +00:00
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
MasterServerList.Clear();
|
2017-08-31 20:59:57 +00:00
|
|
|
|
Prospects = new Dictionary<string, Client>();
|
2017-08-30 21:02:51 +00:00
|
|
|
|
Clients = new Dictionary<string, Client>();
|
2017-08-31 20:59:57 +00:00
|
|
|
|
|
|
|
|
|
ushort port = (ushort)Configuration.General["Master Port"];
|
2017-08-29 20:14:44 +00:00
|
|
|
|
Sock = new UdpClient(new IPEndPoint(IPAddress.Any, port));
|
2017-06-16 21:00:01 +00:00
|
|
|
|
|
|
|
|
|
IsOpen = true;
|
2017-08-21 21:03:32 +00:00
|
|
|
|
ListeningThread = new Thread(Listener);
|
2017-06-16 21:00:01 +00:00
|
|
|
|
ListeningThread.Start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void Listener() {
|
|
|
|
|
while(IsOpen) {
|
2017-09-01 17:10:19 +00:00
|
|
|
|
IPEndPoint endPoint = new IPEndPoint(0, 0);
|
2017-06-16 21:00:01 +00:00
|
|
|
|
while(Sock.Available > 0) {
|
2017-08-30 21:02:51 +00:00
|
|
|
|
var data = Sock.Receive(ref endPoint);
|
|
|
|
|
var client = endPoint.ToString();
|
|
|
|
|
var encryptor = IsClientConnected(client) ? Clients[client].Encryptor : null;
|
2017-08-31 20:59:57 +00:00
|
|
|
|
if(data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber))
|
|
|
|
|
encryptor = null;
|
2017-08-30 21:02:51 +00:00
|
|
|
|
|
|
|
|
|
Packet packet =
|
|
|
|
|
encryptor == null ? Packet.FromBytes(data)
|
|
|
|
|
: Packet.FromBytes(encryptor.Parse(data));
|
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
if(packet == null) {
|
|
|
|
|
if(encryptor != null)
|
|
|
|
|
EncryptionError(endPoint);
|
2017-09-06 20:59:38 +00:00
|
|
|
|
continue;
|
2017-09-07 21:00:03 +00:00
|
|
|
|
}
|
2017-09-07 04:26:58 +00:00
|
|
|
|
|
|
|
|
|
Clients[client].LastReceive = DateTime.Now;
|
2017-09-01 17:10:19 +00:00
|
|
|
|
switch((kIntraSlaveId)packet.Id) {
|
|
|
|
|
case kIntraSlaveId.InitiationAttempt:
|
|
|
|
|
if(packet.RegionCount != 1 || IsProspectConnected(client))
|
2017-08-30 21:02:51 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if(packet[0] == Configuration.General["Master Secret"]) {
|
2017-08-31 20:59:57 +00:00
|
|
|
|
var key = new Key();
|
|
|
|
|
Prospects[client] = new Client {
|
|
|
|
|
LastReceive = DateTime.Now,
|
|
|
|
|
Address = endPoint,
|
|
|
|
|
Key = key
|
|
|
|
|
};
|
|
|
|
|
|
2017-09-01 17:10:19 +00:00
|
|
|
|
Send(key.GenerateRequestPacket(), endPoint);
|
2017-08-30 21:02:51 +00:00
|
|
|
|
}
|
|
|
|
|
break;
|
2017-08-31 20:59:57 +00:00
|
|
|
|
|
2017-09-01 17:10:19 +00:00
|
|
|
|
case kIntraSlaveId.KeyExchange:
|
2017-08-31 20:59:57 +00:00
|
|
|
|
if(!IsProspectConnected(client))
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
|
|
|
|
|
if(privateKey != -1) {
|
2017-09-07 21:00:03 +00:00
|
|
|
|
Prospects[client].LastReceive = DateTime.Now;
|
|
|
|
|
Prospects[client].Encryptor = new StreamCipher(privateKey);
|
2017-08-31 20:59:57 +00:00
|
|
|
|
Clients[client] = Prospects[client];
|
|
|
|
|
Prospects.Remove(client);
|
|
|
|
|
} else
|
|
|
|
|
Prospects.Remove(client);
|
|
|
|
|
break;
|
|
|
|
|
|
2017-09-01 17:10:19 +00:00
|
|
|
|
case kIntraSlaveId.StatusUpdate:
|
2017-08-31 20:59:57 +00:00
|
|
|
|
if(!IsClientConnected(client) || packet.RegionCount < 1)
|
|
|
|
|
break;
|
|
|
|
|
|
2017-09-06 20:59:38 +00:00
|
|
|
|
if(packet.CheckRegions(0, 1)) {
|
2017-09-07 21:00:03 +00:00
|
|
|
|
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Server count is malformed.");
|
2017-09-06 20:59:38 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
byte serverCount = packet[0].Raw[0];
|
|
|
|
|
if(packet.RegionCount != 1 + 3 * serverCount) {
|
2017-09-07 21:00:03 +00:00
|
|
|
|
NegativeAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate, "Region count does not match server count");
|
2017-09-06 20:59:38 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(byte i = 0; i < serverCount; ++i) {
|
|
|
|
|
if(!packet.CheckRegions(2 + 3 * i, 2, 2, 2))
|
|
|
|
|
continue;
|
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
MasterServerList.Write(new Server {
|
2017-09-06 20:59:38 +00:00
|
|
|
|
Id = packet[2 + 3 * i].Raw.UnpackUInt16(),
|
|
|
|
|
UserCount = packet[3 + 3 * i].Raw.UnpackUInt16(),
|
|
|
|
|
Address = endPoint.Address,
|
|
|
|
|
Port = packet[4 + 3 * i].Raw.UnpackUInt16()
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
PositiveAck(endPoint, encryptor, kIntraSlaveId.StatusUpdate);
|
2017-08-30 21:02:51 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
2017-06-16 21:00:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-08-31 20:59:57 +00:00
|
|
|
|
|
|
|
|
|
|
2017-06-16 21:00:01 +00:00
|
|
|
|
Thread.Sleep(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-01 17:10:19 +00:00
|
|
|
|
private static void Send(Packet packet, IPEndPoint client) {
|
2017-09-07 21:00:03 +00:00
|
|
|
|
Send(packet.GetBytes(), client);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void Send(byte[] bytes, IPEndPoint client) {
|
|
|
|
|
Sock.Send(bytes, bytes.Length, client);
|
2017-09-01 17:10:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 21:00:01 +00:00
|
|
|
|
public static void Close() {
|
|
|
|
|
IsOpen = false;
|
|
|
|
|
ListeningThread.Join();
|
|
|
|
|
ListeningThread = null;
|
2017-08-29 20:14:44 +00:00
|
|
|
|
Sock.Dispose();
|
2017-06-16 21:00:01 +00:00
|
|
|
|
}
|
2017-08-31 20:59:57 +00:00
|
|
|
|
|
|
|
|
|
private static bool IsProspectConnected(string client) {
|
|
|
|
|
return Prospects.ContainsKey(client);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsClientConnected(string client) {
|
|
|
|
|
return Clients.ContainsKey(client);
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
private static void PositiveAck(IPEndPoint endPoint, StreamCipher cipher, kIntraSlaveId id) {
|
|
|
|
|
Send(cipher.Parse(new Packet(kIntraMasterId.PositiveAck, id).GetBytes()), endPoint);
|
2017-09-01 17:10:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-07 21:00:03 +00:00
|
|
|
|
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);
|
2017-08-31 20:59:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-09-06 20:59:38 +00:00
|
|
|
|
private static void EncryptionError(IPEndPoint endPoint, string message = "A general encryption error has occurred. Renegotiation required.") {
|
|
|
|
|
Send(new Packet(kIntraMasterId.EncryptionError, message), endPoint);
|
2017-08-31 20:59:57 +00:00
|
|
|
|
}
|
2017-08-30 21:02:51 +00:00
|
|
|
|
|
|
|
|
|
class Client {
|
2017-08-31 20:59:57 +00:00
|
|
|
|
public IPEndPoint Address { get; set; }
|
2017-08-30 21:02:51 +00:00
|
|
|
|
public DateTime LastReceive { get; set; }
|
2017-09-07 04:26:58 +00:00
|
|
|
|
public TimeSpan ReceiveDelta => DateTime.Now - LastReceive;
|
2017-09-07 21:00:03 +00:00
|
|
|
|
public StreamCipher Encryptor { get; set; }
|
2017-08-30 21:02:51 +00:00
|
|
|
|
public Key Key { get; set; }
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-06-16 21:00:01 +00:00
|
|
|
|
}
|