diff --git a/protocol.md b/protocol.md
index 49244b9..8cd9cd6 100644
--- a/protocol.md
+++ b/protocol.md
@@ -87,6 +87,49 @@ Communication between the master server and clients will be done over a WebSocke
+
+
+
+ ID 2: Positive ACK
+ Responder
+ |
+
+
+ # |
+ Region |
+ Type |
+
+
+ 1 |
+ Request Packet ID |
+ Byte |
+
+
+
+
+
+
+ ID 3: Negative ACK
+ Responder
+ |
+
+
+ # |
+ Region |
+ Type |
+
+
+ 1 |
+ Request Packet ID |
+ Byte |
+
+
+ 2 |
+ Error Message |
+ String |
+
+
+
#### Slave to Master
@@ -127,6 +170,49 @@ Communication between the master server and clients will be done over a WebSocke
+
+
+
+ ID 2: Status Update
+ Blind Requester
+ |
+
+
+ # (r) |
+ Region |
+ Type |
+
+
+ 1 |
+ Server Count (n) |
+ Unsigned Byte |
+
+
+ r > 1 |
+ Iterated over n (0 ≤ i ≤ n - 1) |
+
+
+ 2 + 4i |
+ Server Id |
+ Packed Unsigned Short |
+
+
+ 3 + 4i |
+ User Count |
+ Packed Unsigned Short |
+
+
+ 4 + 4i |
+ IPv4 Address |
+ Bytes (4) |
+
+
+ 5 + 4i |
+ Port |
+ Packed Unsigned Short |
+
+
+
### Master/Client Packet IDs
#### Master to Client
diff --git a/server/Entrypoint.cs b/server/Entrypoint.cs
index 35c8cf3..b0ea486 100644
--- a/server/Entrypoint.cs
+++ b/server/Entrypoint.cs
@@ -13,15 +13,17 @@ using Kneesocks;
using MySql.Data.Entity;
namespace SockScape {
+ static class ServerContext {
+ public static Dictionary> Servers { get; }
+ = new Dictionary>();
+ public static Dictionary> Pools { get; }
+ = new Dictionary>();
+ }
+
class Entrypoint {
static void Main(string[] args) {
var db = new DAL.ScapeDb();
- Dictionary servers
- = new Dictionary();
- Dictionary> pools
- = new Dictionary>();
-
foreach(var server in Configuration.Servers) {
var pool = new Pool {
InitialCount = 3,
@@ -33,8 +35,8 @@ namespace SockScape {
var serverHandle = new Server((ushort)server["Port"], pool, server);
- pools.Add(server["Id"], pool);
- servers.Add(server["Id"], serverHandle);
+ ServerContext.Pools.Add(server["Id"], pool);
+ ServerContext.Servers.Add(server["Id"], serverHandle);
serverHandle.Start();
}
diff --git a/server/ServerList.cs b/server/ServerList.cs
index f4e2836..13e7b5b 100644
--- a/server/ServerList.cs
+++ b/server/ServerList.cs
@@ -6,10 +6,26 @@ using System.Text;
using System.Threading.Tasks;
namespace SockScape {
- static class ServerList {
- public static Dictionary Servers { get; private set; }
- = new Dictionary();
+ class ServerList {
+ public static Dictionary Servers { get; }
+ = new Dictionary();
-
+ public Server this[int i] {
+ get => Servers.ContainsKey(i) ? Servers[i] : null;
+ set => Servers[i] = value;
+ }
+
+ public bool HasId(int id)
+ => Servers.ContainsKey(id);
+
+ public void Clear()
+ => Servers.Clear();
+ }
+
+ class Server {
+ public ushort Id { get; set; }
+ public ushort UserCount { get; set; }
+ public IPEndPoint Address { get; set; }
+ public IPEndPoint Owner { get; set; }
}
}
diff --git a/server/Socks/MasterUdpClient.cs b/server/Socks/MasterUdpClient.cs
index 1b7d1e1..9facb0f 100644
--- a/server/Socks/MasterUdpClient.cs
+++ b/server/Socks/MasterUdpClient.cs
@@ -16,12 +16,13 @@ namespace SockScape {
private static UdpClient Sock;
private static Thread ListeningThread;
private static bool IsOpen;
+ private static DateTime LastMessage;
public static void Initialize() {
if(IsOpen || ListeningThread != null)
return;
- short port = (short)Configuration.General["Master Port"];
+ ushort port = (ushort)Configuration.General["Master Port"];
Sock = new UdpClient(Configuration.General["Master Addr"], port);
Key = new Key();
@@ -41,6 +42,11 @@ namespace SockScape {
}
}
+ public static void Send(byte[] message) {
+ Sock.Send(message, message.Length);
+ LastMessage = DateTime.Now;
+ }
+
public static void Close() {
IsOpen = false;
ListeningThread.Join();
diff --git a/server/Socks/MasterUdpServer.cs b/server/Socks/MasterUdpServer.cs
index cd81e2b..756f6d0 100644
--- a/server/Socks/MasterUdpServer.cs
+++ b/server/Socks/MasterUdpServer.cs
@@ -13,6 +13,7 @@ namespace SockScape {
static class MasterUdpServer {
private static Dictionary Prospects;
private static Dictionary Clients;
+ private static ServerList Servers;
private static UdpClient Sock;
private static Thread ListeningThread;
@@ -22,8 +23,11 @@ namespace SockScape {
if(IsOpen || ListeningThread != null)
return;
+ Servers = new ServerList();
+ Prospects = new Dictionary();
Clients = new Dictionary();
- short port = (short)Configuration.General["Master Port"];
+
+ ushort port = (ushort)Configuration.General["Master Port"];
Sock = new UdpClient(new IPEndPoint(IPAddress.Any, port));
IsOpen = true;
@@ -31,10 +35,6 @@ namespace SockScape {
ListeningThread.Start();
}
- private static bool IsClientConnected(string client) {
- return Clients.ContainsKey(client);
- }
-
public static void Listener() {
while(IsOpen) {
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 0);
@@ -42,29 +42,59 @@ namespace SockScape {
var data = Sock.Receive(ref endPoint);
var client = endPoint.ToString();
var encryptor = IsClientConnected(client) ? Clients[client].Encryptor : null;
+ if(data.Take(Packet.MagicNumber.Length).SequenceEqual(Packet.MagicNumber))
+ encryptor = null;
Packet packet =
encryptor == null ? Packet.FromBytes(data)
: Packet.FromBytes(encryptor.Parse(data));
+ if(packet == null)
+ break;
+
+ byte[] sendBuffer;
switch((kIntraMasterId)packet.Id) {
case kIntraMasterId.InitiationAttempt:
if(packet.RegionCount != 1)
break;
if(packet[0] == Configuration.General["Master Secret"]) {
- var request =
-
- var request = Key.GenerateRequestPacket().GetBytes();
- Sock.Send(request, request.Length, endPoint);
+ var key = new Key();
+ Prospects[client] = new Client {
+ LastReceive = DateTime.Now,
+ Address = endPoint,
+ Key = key
+ };
+
+ sendBuffer = key.GenerateRequestPacket().GetBytes();
+ Sock.Send(sendBuffer, sendBuffer.Length, endPoint);
}
break;
+
case kIntraMasterId.KeyExchange:
+ if(!IsProspectConnected(client))
+ break;
+
+ var privateKey = Prospects[client].Key.ParseResponsePacket(packet);
+ if(privateKey != -1) {
+ Prospects[client].Encryptor = new Cipher(privateKey);
+ Clients[client] = Prospects[client];
+ Prospects.Remove(client);
+ } else
+ Prospects.Remove(client);
+ break;
+
+ case kIntraMasterId.StatusUpdate:
+ if(!IsClientConnected(client) || packet.RegionCount < 1)
+ break;
+
break;
}
}
+
+
Thread.Sleep(1);
}
}
@@ -75,8 +105,25 @@ namespace SockScape {
ListeningThread = null;
Sock.Dispose();
}
+
+ private static bool IsProspectConnected(string client) {
+ return Prospects.ContainsKey(client);
+ }
+
+ private static bool IsClientConnected(string client) {
+ return Clients.ContainsKey(client);
+ }
+
+ private static Packet PositiveAck(byte id) {
+ return new Packet((int)kIntraMasterAckId.PositiveAck, new { id });
+ }
+
+ private static Packet NegativeAck(byte id, string message) {
+ return new Packet((int)kIntraMasterAckId.NegativeAck, new { id, message });
+ }
class Client {
+ public IPEndPoint Address { get; set; }
public DateTime LastReceive { get; set; }
public Cipher Encryptor { get; set; }
public Key Key { get; set; }
diff --git a/server/Socks/Protocols/IntraMasterIds.cs b/server/Socks/Protocols/IntraMasterIds.cs
index 2d24c58..3e952a1 100644
--- a/server/Socks/Protocols/IntraMasterIds.cs
+++ b/server/Socks/Protocols/IntraMasterIds.cs
@@ -7,6 +7,12 @@ using System.Threading.Tasks;
namespace SockScape {
public enum kIntraMasterId {
InitiationAttempt = 0,
- KeyExchange
+ KeyExchange,
+ StatusUpdate
+ }
+
+ public enum kIntraMasterAckId {
+ PositiveAck = 1,
+ NegativeAck
}
}
diff --git a/server/Socks/Protocols/Packet.cs b/server/Socks/Protocols/Packet.cs
index 1c54f6c..55e7da3 100644
--- a/server/Socks/Protocols/Packet.cs
+++ b/server/Socks/Protocols/Packet.cs
@@ -7,7 +7,8 @@ using Glove;
namespace SockScape {
class Packet {
- private static readonly byte[] MagicNumber = { 0xF0, 0x9F, 0xA6, 0x91 };
+ // (squid)
+ public static readonly byte[] MagicNumber = { 0xF0, 0x9F, 0xA6, 0x91 };
public static Packet FromBytes(byte[] raw) {
if(raw.Length < 7)