sockscape/server/Socks/Protocols/Packet.cs

133 lines
4.1 KiB
C#
Raw Normal View History

2017-05-19 21:02:39 +00:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
2017-07-22 19:27:41 +00:00
using Glove;
2017-05-19 21:02:39 +00:00
2017-07-22 19:27:41 +00:00
namespace SockScape {
2017-05-19 21:02:39 +00:00
class Packet {
2017-08-16 21:01:08 +00:00
private static readonly byte[] MagicNumber = { 0xF0, 0x9F, 0xA6, 0x91 };
2017-05-25 21:08:21 +00:00
public static Packet FromBytes(byte[] raw) {
2017-08-16 21:01:08 +00:00
if(raw.Length < 7)
return null;
2017-05-19 21:02:39 +00:00
Packet packet = new Packet();
2017-08-16 21:01:08 +00:00
if(!raw.Subset(0, 4).SequenceEqual(MagicNumber))
return null;
packet.Id = raw[4];
2017-08-16 21:01:08 +00:00
var regionCount = raw[5];
2017-05-19 21:02:39 +00:00
var regionLengths = new List<uint>();
2017-08-16 21:01:08 +00:00
var headerPtr = 6;
2017-05-19 21:02:39 +00:00
for(var i = 0; i < regionCount; ++i) {
2017-05-26 20:28:02 +00:00
regionLengths.Add(0);
2017-05-19 21:02:39 +00:00
var first = raw[headerPtr];
if(first < 254) {
regionLengths[i] = first;
++headerPtr;
} else if(first == 254) {
if(headerPtr + 3 < raw.Length)
2017-08-16 21:01:08 +00:00
return null;
2017-05-19 21:02:39 +00:00
regionLengths[i] = raw.Subset(headerPtr + 1, 2).UnpackUInt16();
headerPtr += 3;
} else {
if(headerPtr + 5 < raw.Length)
2017-08-16 21:01:08 +00:00
return null;
2017-05-19 21:02:39 +00:00
regionLengths[i] = raw.Subset(headerPtr + 1, 4).UnpackUInt32();
headerPtr += 5;
}
if(headerPtr > raw.Length)
2017-08-16 21:01:08 +00:00
return null;
2017-05-19 21:02:39 +00:00
}
2017-05-26 20:28:02 +00:00
if(headerPtr + regionLengths.Sum(x => x) > raw.Length)
2017-08-16 21:01:08 +00:00
return null;
2017-05-20 23:33:39 +00:00
2017-05-19 21:02:39 +00:00
long bodyPtr = headerPtr;
foreach(var regionLength in regionLengths) {
// FLAG this could fail if one region exceeds 2^31-1 in size, check later
packet.Regions.Add(raw.Subset((int)bodyPtr, (int)regionLength));
bodyPtr += regionLength;
}
return packet;
}
2017-08-21 21:03:32 +00:00
private readonly List<byte[]> Regions = new List<byte[]>();
public int Id { get; private set; }
2017-08-21 21:03:32 +00:00
public int RegionCount
=> Regions.Count;
2017-05-19 21:02:39 +00:00
protected Packet() { }
2017-05-20 23:33:39 +00:00
public Packet(int id, params object[] regions) {
2017-05-19 21:02:39 +00:00
Id = id;
2017-05-24 21:03:57 +00:00
foreach(var region in regions)
AddRegion(region);
2017-05-19 21:02:39 +00:00
}
2017-08-21 21:03:32 +00:00
public Region this[int i]
=> new Region(Regions[i]);
2017-05-19 21:02:39 +00:00
2017-05-25 21:08:21 +00:00
public Packet AddRegion(object region) {
2017-05-24 21:03:57 +00:00
if(region.GetType() == typeof(byte[]))
Regions.Add((byte[])region);
else if(region.GetType() == typeof(string))
Regions.Add(((string)region).GetBytes());
2017-05-25 21:08:21 +00:00
return this;
2017-05-24 21:03:57 +00:00
}
2017-05-19 21:02:39 +00:00
public byte[] GetBytes() {
2017-08-16 21:01:08 +00:00
var header = new List<byte>();
header.AddRange(MagicNumber);
header.Add((byte)Id);
header.Add((byte)RegionCount);
2017-05-19 21:02:39 +00:00
IEnumerable<byte> body = new byte[0];
foreach(var region in Regions) {
if(region.Length < 0xFE)
2017-05-19 21:02:39 +00:00
header.Add((byte)region.Length);
else if(region.Length <= 0xFFFF) {
header.Add(0xFE);
2017-05-19 21:02:39 +00:00
header.AddRange(((UInt16)region.Length).Pack());
} else {
header.Add(0xFF);
2017-05-19 21:02:39 +00:00
header.AddRange(region.Length.Pack());
}
body = body.Concat(region);
}
return header.Concat(body).ToArray();
}
2017-05-20 23:33:39 +00:00
public class Region {
2017-08-21 21:03:32 +00:00
public byte[] Data { get; }
2017-05-19 21:02:39 +00:00
2017-05-20 23:33:39 +00:00
public Region(byte[] data) {
Data = data;
}
2017-05-19 21:02:39 +00:00
2017-05-20 23:33:39 +00:00
public static implicit operator byte[] (Region region) => region.Data;
2017-08-21 21:03:32 +00:00
public string Bytes
=> this;
2017-05-19 21:02:39 +00:00
2017-05-20 23:33:39 +00:00
public static implicit operator string(Region region) {
try {
return Encoding.UTF8.GetString(region.Data);
} catch {
return Encoding.ASCII.GetString(region.Data);
}
2017-05-19 21:02:39 +00:00
}
2017-08-21 21:03:32 +00:00
public string Str
=> this;
2017-05-19 21:02:39 +00:00
}
}
}