the socks are almost done
fucking finally
This commit is contained in:
parent
c204d1ded5
commit
a9bf7201c9
5 changed files with 118 additions and 56 deletions
|
@ -14,5 +14,4 @@ class FileCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
}
|
}
|
|
@ -37,18 +37,19 @@ namespace Kneesocks {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Disconnect(string reason = null) {
|
public void Disconnect(string reason = null) {
|
||||||
|
Disconnect(Frame.kClosingReason.Normal, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Disconnect(Frame.kClosingReason status, string reason = null) {
|
||||||
Disconnected = true;
|
Disconnected = true;
|
||||||
DisconnectReason = reason;
|
DisconnectReason = reason;
|
||||||
|
|
||||||
if(Socket.Connected) {
|
if(Socket.Connected) {
|
||||||
Socket.SendTimeout = 1000;
|
Socket.SendTimeout = 1000;
|
||||||
if(!Handshaked) {
|
var raw = Handshaked ? Frame.Closing(status, reason).GetBytes()
|
||||||
var raw = Encoding.ASCII.GetBytes(Handshake.DenyRequest().GetRaw());
|
: Handshake.DenyRequest().ToString().GetBytes();
|
||||||
Stream.Write(raw, 0, raw.Length);
|
Stream.Write(raw, 0, raw.Length);
|
||||||
Socket.Close();
|
Socket.Close();
|
||||||
} else {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
OnClose();
|
OnClose();
|
||||||
|
|
|
@ -6,6 +6,17 @@ using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Kneesocks {
|
namespace Kneesocks {
|
||||||
public class Frame {
|
public class Frame {
|
||||||
|
public enum kClosingReason {
|
||||||
|
Normal = 1000,
|
||||||
|
GoingAway = 1001,
|
||||||
|
ProtocolError = 1002,
|
||||||
|
FrameTypeError = 1003,
|
||||||
|
DataError = 1007,
|
||||||
|
PolicyError = 1008,
|
||||||
|
FrameTooBig = 1009,
|
||||||
|
RequestError = 1011
|
||||||
|
}
|
||||||
|
|
||||||
public enum kOpcode {
|
public enum kOpcode {
|
||||||
Continuation = 0x0,
|
Continuation = 0x0,
|
||||||
TextFrame = 0x1,
|
TextFrame = 0x1,
|
||||||
|
@ -15,44 +26,63 @@ namespace Kneesocks {
|
||||||
Pong = 0xA
|
Pong = 0xA
|
||||||
};
|
};
|
||||||
|
|
||||||
public kOpcode Opcode { get; set; }
|
public kOpcode Opcode { get; set; } = kOpcode.BinaryFrame;
|
||||||
public bool IsFinal { get; set; }
|
public bool IsFinal { get; set; } = true;
|
||||||
public bool IsMasked { get; set; }
|
public bool IsMasked { get; set; } = false;
|
||||||
public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 };
|
public byte[] Mask { get; set; } = new byte[] { 0, 0, 0, 0 };
|
||||||
public byte Reserved { get; set; }
|
public byte Reserved { get; set; } = 0;
|
||||||
|
|
||||||
public byte[] Content { get; set; }
|
public byte[] Content { get; set; }
|
||||||
public byte[] MaskedContent {
|
public byte[] MaskedContent {
|
||||||
get {
|
get {
|
||||||
byte[] returnValue = new byte[Content.Length];
|
long counter = 0;
|
||||||
for(long i = 0; i < Content.LongLength; ++i)
|
return Content.Select(x => (byte)(x ^ Mask[counter++ % 4])).ToArray();
|
||||||
returnValue[i] = (byte)(Content[i] ^ Mask[i % 4]);
|
|
||||||
return returnValue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetRaw() {
|
public byte[] GetBytes() {
|
||||||
var headerSize = 2L;
|
var headerSize = 2L;
|
||||||
var bodySize = Content.LongLength;
|
var bodySize = Content.LongLength;
|
||||||
if(bodySize >= 0x7E && bodySize <= 0xFFFF)
|
var headerLengthFirstByte = (byte)Content.Length;
|
||||||
|
if(bodySize >= 0x7E && bodySize <= 0xFFFF) {
|
||||||
headerSize += 2;
|
headerSize += 2;
|
||||||
else if(bodySize > 0xFFFF)
|
headerLengthFirstByte = 126;
|
||||||
|
} else if(bodySize > 0xFFFF) {
|
||||||
headerSize += 8;
|
headerSize += 8;
|
||||||
|
headerLengthFirstByte = 127;
|
||||||
|
}
|
||||||
|
var headerLengthSize = (int)headerSize - 1;
|
||||||
if(IsMasked)
|
if(IsMasked)
|
||||||
headerSize += 4;
|
headerSize += 4;
|
||||||
|
|
||||||
var returnValue = new byte[headerSize + bodySize];
|
var returnValue = new byte[headerSize + bodySize];
|
||||||
|
returnValue[0] = (byte)(((byte)Opcode % 0x10)
|
||||||
|
| ((Reserved % 8) << 4)
|
||||||
|
| (IsFinal ? 0x80 : 0x0));
|
||||||
|
|
||||||
|
returnValue[1] = (byte)(headerLengthFirstByte
|
||||||
|
| (IsMasked ? 0x80 : 0x0));
|
||||||
|
|
||||||
|
if(headerLengthFirstByte >= 0x7E) {
|
||||||
|
var upperBound = headerLengthFirstByte == 0x7E ? 2 : 8;
|
||||||
|
for(var i = 0; i < upperBound; ++i)
|
||||||
|
returnValue[2 + i] |= (byte)((bodySize >> (8*(upperBound - i))) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(IsMasked)
|
||||||
|
Array.Copy(Mask, 0, returnValue, headerSize - 4, 4);
|
||||||
|
|
||||||
|
Array.Copy(IsMasked ? MaskedContent : Content, 0L, returnValue, headerSize, Content.LongLength);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Frame FromRaw(byte[] raw) {
|
public static Frame FromBytes(byte[] raw) {
|
||||||
if(raw.Length < 2)
|
if(raw.Length < 2)
|
||||||
throw new FormatException("Websocket frame cannot be less than two bytes long");
|
throw new FormatException("Websocket frame cannot be less than two bytes long");
|
||||||
|
|
||||||
var rawOpcode = raw[0] & 0x0F;
|
var rawOpcode = raw[0] & 0x0F;
|
||||||
if(!Enum.IsDefined(typeof(kOpcode), rawOpcode))
|
if(!Enum.IsDefined(typeof(kOpcode), rawOpcode))
|
||||||
throw new FormatException("Opcode '"+ rawOpcode.ToString("0x{0:X}") +"' not understood");
|
throw new FormatException("Opcode '0x"+ rawOpcode.ToString("X") +"' not understood");
|
||||||
|
|
||||||
var returnFrame = new Frame {
|
var returnFrame = new Frame {
|
||||||
IsFinal = (raw[0] & 0x80) != 0,
|
IsFinal = (raw[0] & 0x80) != 0,
|
||||||
|
@ -62,41 +92,63 @@ namespace Kneesocks {
|
||||||
};
|
};
|
||||||
|
|
||||||
ulong bodyLength = raw[1] & 0x7Ful;
|
ulong bodyLength = raw[1] & 0x7Ful;
|
||||||
int lengthOffset =
|
int headerOffset =
|
||||||
bodyLength < 126
|
bodyLength < 0x7E
|
||||||
? 1
|
? 1
|
||||||
: (bodyLength == 126 ? 3 : 9);
|
: (bodyLength == 0x7E ? 3 : 9);
|
||||||
|
|
||||||
|
if(raw.Length < headerOffset + 1)
|
||||||
|
throw new FormatException("Websocket frame is smaller than expected header size");
|
||||||
|
|
||||||
for(var i = lengthOffset - 1; i > 0; --i) {
|
bodyLength = bodyLength < 0x7E ? 0 : bodyLength;
|
||||||
var bytePos = lengthOffset - 1 - i;
|
for(var i = headerOffset - 1; i > 0; --i)
|
||||||
bodyLength &= 0xFFul << bytePos;
|
bodyLength |= (ulong)raw[2 + i] << (8*(headerOffset - 1 - i));
|
||||||
bodyLength |= (ulong)raw[2 + i] << bytePos;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(returnFrame.IsMasked) {
|
if(returnFrame.IsMasked) {
|
||||||
for(var i = 0; i < 4; ++i)
|
Array.Copy(raw, headerOffset + 1, returnFrame.Mask, 0, 4);
|
||||||
returnFrame.Mask[i] = raw[i + 1 + lengthOffset];
|
headerOffset += 4;
|
||||||
lengthOffset += 4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ulong expectedFrameLength = bodyLength + (uint)lengthOffset + 1;
|
ulong expectedFrameLength = bodyLength + (uint)headerOffset + 1;
|
||||||
if(expectedFrameLength < (ulong)raw.LongLength)
|
if(expectedFrameLength < (ulong)raw.LongLength)
|
||||||
throw new FormatException("Raw frame length ("+ expectedFrameLength +") is less than described size ("+ (ulong)raw.LongLength +")");
|
throw new FormatException("Raw frame length ("+ (ulong)raw.LongLength + ") is less than described size ("+ expectedFrameLength + ")");
|
||||||
|
|
||||||
ulong counter = 0;
|
Array.Copy(raw, headerOffset + 1, returnFrame.Content, 0L, (long)bodyLength);
|
||||||
returnFrame.Content = raw.Skip(lengthOffset + 1)
|
if(returnFrame.IsMasked)
|
||||||
.TakeWhile(x => counter++ < bodyLength)
|
returnFrame.Content = returnFrame.MaskedContent;
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
if(returnFrame.IsMasked) {
|
|
||||||
counter = 0;
|
|
||||||
returnFrame.Content =
|
|
||||||
returnFrame.Content.Select(
|
|
||||||
x => (byte)(x ^ returnFrame.Mask[counter++ % 4])
|
|
||||||
).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return returnFrame;
|
return returnFrame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Frame Closing(kClosingReason status = kClosingReason.Normal, string reason = "") {
|
||||||
|
var data = new byte[2 + reason.ByteLength()];
|
||||||
|
data[0] = (byte)(((short)status >> 8) & 0xFF);
|
||||||
|
data[1] = (byte)((short)status & 0xFF);
|
||||||
|
Array.Copy(reason.GetBytes(), 0, data, 2, reason.ByteLength());
|
||||||
|
|
||||||
|
return new Frame {
|
||||||
|
Opcode = kOpcode.Close,
|
||||||
|
Content = data
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Frame Ping(string data = "") {
|
||||||
|
return new Frame {
|
||||||
|
Opcode = kOpcode.Ping,
|
||||||
|
Content = data.GetBytes()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Frame Pong(string data = "") {
|
||||||
|
return new Frame {
|
||||||
|
Opcode = kOpcode.Pong,
|
||||||
|
Content = data.GetBytes()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Frame Pong(Frame pingFrame) {
|
||||||
|
pingFrame.Opcode = kOpcode.Pong;
|
||||||
|
return pingFrame;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,9 +99,9 @@ namespace Kneesocks {
|
||||||
return new Handshake(statusCode, message);
|
return new Handshake(statusCode, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetRaw() {
|
public override string ToString() {
|
||||||
if(Content != null) {
|
if(Content != null) {
|
||||||
SetHeader("Content-Length", Encoding.ASCII.GetByteCount(Content).ToString());
|
SetHeader("Content-Length", Content.ByteLength().ToString());
|
||||||
if(GetHeader("Content-Type") == null)
|
if(GetHeader("Content-Type") == null)
|
||||||
SetHeader("Content-Type", "text/plain");
|
SetHeader("Content-Type", "text/plain");
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,23 +10,33 @@ namespace Kneesocks {
|
||||||
RAW, HEX, BASE64
|
RAW, HEX, BASE64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] GetBytes(this string str, bool isUtf8 = true) {
|
||||||
|
return isUtf8 ? Encoding.UTF8.GetBytes(str)
|
||||||
|
: Encoding.ASCII.GetBytes(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int ByteLength(this string str, bool isUtf8 = true) {
|
||||||
|
return isUtf8 ? Encoding.UTF8.GetByteCount(str)
|
||||||
|
: Encoding.ASCII.GetByteCount(str);
|
||||||
|
}
|
||||||
|
|
||||||
public static string Base64Encode(this string str, bool isUtf8 = true) {
|
public static string Base64Encode(this string str, bool isUtf8 = true) {
|
||||||
var raw =
|
var raw =
|
||||||
isUtf8 ? Encoding.UTF8.GetBytes(str)
|
isUtf8 ? Encoding.UTF8.GetBytes(str)
|
||||||
: Encoding.ASCII.GetBytes(str);
|
: Encoding.ASCII.GetBytes(str);
|
||||||
return Convert.ToBase64String(raw);
|
return Convert.ToBase64String(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string Base64Decode(this string str, bool isUtf8 = true) {
|
public static string Base64Decode(this string str, bool isUtf8 = true) {
|
||||||
var raw = Convert.FromBase64String(str);
|
var raw = Convert.FromBase64String(str);
|
||||||
return isUtf8 ? Encoding.UTF8.GetString(raw)
|
return isUtf8 ? Encoding.UTF8.GetString(raw)
|
||||||
: Encoding.ASCII.GetString(raw);
|
: Encoding.ASCII.GetString(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string SHA1(this string str, kHashReturnType type = kHashReturnType.RAW) {
|
public static string SHA1(this string str, kHashReturnType type = kHashReturnType.RAW) {
|
||||||
using(var hasher = System.Security.Cryptography.SHA1.Create()) {
|
using(var hasher = System.Security.Cryptography.SHA1.Create()) {
|
||||||
return ParseRawHash(
|
return ParseRawHash(
|
||||||
hasher.ComputeHash(Encoding.ASCII.GetBytes(str)),
|
hasher.ComputeHash(str.GetBytes(false)),
|
||||||
type
|
type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -35,7 +45,7 @@ namespace Kneesocks {
|
||||||
public static string MD5(this string str, kHashReturnType type = kHashReturnType.RAW) {
|
public static string MD5(this string str, kHashReturnType type = kHashReturnType.RAW) {
|
||||||
using(var hasher = System.Security.Cryptography.MD5.Create()) {
|
using(var hasher = System.Security.Cryptography.MD5.Create()) {
|
||||||
return ParseRawHash(
|
return ParseRawHash(
|
||||||
hasher.ComputeHash(Encoding.ASCII.GetBytes(str)),
|
hasher.ComputeHash(str.GetBytes(false)),
|
||||||
type
|
type
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue