using linker.libs.extends;
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Net;
using System.Text;
namespace linker.libs.socks5
{
///
/// socks5 数据包解析和组装
///
public sealed class Socks5Parser
{
///
/// 获取客户端过来的支持的认证方式列表
///
///
///
public static Socks5EnumAuthType[] GetAuthMethods(ReadOnlySpan span)
{
//VER NMETHODS METHODS
// 1 1 1-255
//版本 支持哪些认证 一个认证方式一个字节
byte length = span[1];
Socks5EnumAuthType[] res = new Socks5EnumAuthType[length];
for (byte i = 0; i < length; i++)
{
res[i] = (Socks5EnumAuthType)span[2 + i];
}
return res;
}
///
/// 获取账号密码
///
///
///
public static (string username, string password) GetPasswordAuthInfo(Span span)
{
/*
子版本 username长度 username password长度 password
0x01
*/
string username = span.Slice(2, span[1]).GetString();
string password = span.Slice(2 + span[1] + 1, span[2 + span[1]]).GetString();
return (username, password);
}
///
/// 获取地址
///
///
///
public static ReadOnlyMemory GetRemoteEndPoint(ReadOnlyMemory data, out Socks5EnumAddressType addressType, out ushort port, out int index)
{
//VERSION COMMAND RSV ATYPE DST.ADDR DST.PORT
//去掉 VERSION COMMAND RSV
ReadOnlyMemory memory = data.Slice(3);
ReadOnlySpan span = memory.Span;
addressType = (Socks5EnumAddressType)span[0];
index = 0;
ReadOnlyMemory result = Helper.EmptyArray;
switch (addressType)
{
case Socks5EnumAddressType.IPV4:
{
result = memory.Slice(1, 4);
index = 1 + 4;
}
break;
case Socks5EnumAddressType.Domain:
{
result = memory.Slice(2, span[1]);
index = 2 + span[1];
}
break;
case Socks5EnumAddressType.IPV6:
{
result = memory.Slice(1, 16);
index = 1 + 16;
}
break;
default:
break;
}
port = BinaryPrimitives.ReadUInt16BigEndian(span.Slice(index, 2));
index += 2;
index += 3;
return result;
}
///
/// 获取udp中继中的数据
///
///
///
///
public static ReadOnlyMemory GetUdpData(ReadOnlyMemory span)
{
//RSV FRAG ATYPE DST.ADDR DST.PORT DATA
//去掉 RSV FRAG RSV占俩字节
span = span.Slice(3);
return (Socks5EnumAddressType)span.Span[0] switch
{
Socks5EnumAddressType.IPV4 => span[(1 + 4 + 2)..],
Socks5EnumAddressType.IPV6 => span[(1 + 16 + 2)..],
Socks5EnumAddressType.Domain => span[(2 + span.Span[1] + 2)..],
_ => Helper.EmptyArray,
};
}
///
/// 生成connect返回包
///
///
///
///
public static unsafe byte[] MakeConnectResponse(IPEndPoint remoteEndPoint, byte responseCommand)
{
//VER REP RSV ATYPE BND.ADDR BND.PORT
byte[] res = new byte[6 + (remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16)];
var span = res.AsSpan();
res[0] = 5;
res[1] = responseCommand;
res[2] = 0;
res[3] = (byte)(remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? Socks5EnumAddressType.IPV4 : Socks5EnumAddressType.IPV6);
remoteEndPoint.Address.TryWriteBytes(span.Slice(4), out _);
int port = remoteEndPoint.Port;
ref int _port = ref port;
fixed (void* p = &_port)
{
byte* pp = (byte*)p;
res[^2] = *(pp + 1);
res[^1] = *pp;
}
return res;
}
///
/// 生成udp中中继数据包
///
///
///
///
public static unsafe byte[] MakeUdpResponse(IPEndPoint remoteEndPoint, ReadOnlyMemory data, out int length)
{
//RSV FRAG ATYPE DST.ADDR DST.PORT DATA
//RSV占俩字节
int ipLength = (remoteEndPoint.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork ? 4 : 16);
length = 4 + ipLength + 2 + data.Length;
byte[] res = ArrayPool.Shared.Rent(length);
var span = res.AsSpan();
res[0] = 0;
res[1] = 0;
res[2] = 0; //FRAG
res[3] = (byte)(ipLength == 4 ? Socks5EnumAddressType.IPV4 : Socks5EnumAddressType.IPV6);
int index = 4;
remoteEndPoint.Address.TryWriteBytes(span.Slice(index), out _);
index += ipLength;
int port = remoteEndPoint.Port;
ref int _port = ref port;
fixed (void* p = &_port)
{
byte* pp = (byte*)p;
res[index] = *(pp + 1);
res[index + 1] = *pp;
}
index += 2;
data.CopyTo(res.AsMemory(index, data.Length));
return res;
}
public static void Return(byte[] data)
{
ArrayPool.Shared.Return(data);
}
public static EnumProxyValidateDataResult ValidateData(Socks5EnumStep step, Memory data)
{
return step switch
{
Socks5EnumStep.Request => ValidateRequestData(data),
Socks5EnumStep.Command => ValidateCommandData(data),
Socks5EnumStep.Auth => ValidateAuthData(data, Socks5EnumAuthType.Password),
Socks5EnumStep.Forward => EnumProxyValidateDataResult.Equal,
Socks5EnumStep.ForwardUdp => EnumProxyValidateDataResult.Equal,
_ => EnumProxyValidateDataResult.Equal
};
}
///
/// 验证 request数据完整性
///
///
///
public static EnumProxyValidateDataResult ValidateRequestData(ReadOnlyMemory data)
{
/*
* VERSION METHODS_COUNT METHODS
* 1字节 1字节 1到255字节,长度由METHODS_COUNT值决定
* 0x05 0x03 0x00 0x01 0x02
*/
if (data.Length < 2 || data.Length < 2 + data.Span[1])
{
return EnumProxyValidateDataResult.TooShort;
}
return EnumProxyValidateDataResult.Equal;
}
///
/// 验证command数据完整性
///
///
///
public static EnumProxyValidateDataResult ValidateCommandData(ReadOnlyMemory data)
{
/*
* VERSION COMMAND RSV ADDRESS_TYPE DST.ADDR DST.PORT
* 1 1 1 1 1-255 2
* 域名模式下 DST.ADDR第一个字节是域名长度,那么整个数据至少8个字节
*/
if (data.Length < 8) return EnumProxyValidateDataResult.TooShort;
var span = data.Span;
int addrLength = (Socks5EnumAddressType)span[3] switch
{
Socks5EnumAddressType.IPV4 => 4 + 2,
Socks5EnumAddressType.Domain => span[4] + 1 + 2, //DST.ADDR第一个字节是域名长度 剩下的才是域名数据
Socks5EnumAddressType.IPV6 => 16 + 2,
_ => throw new NotImplementedException(),
};
if (data.Length < 4 + addrLength)
{
return EnumProxyValidateDataResult.TooShort;
}
return EnumProxyValidateDataResult.Equal;
}
///
/// 验证认证数据完整性
///
///
///
///
public static EnumProxyValidateDataResult ValidateAuthData(ReadOnlyMemory data, Socks5EnumAuthType authType)
{
return authType switch
{
Socks5EnumAuthType.NoAuth => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.Password => ValidateAuthPasswordData(data),
Socks5EnumAuthType.GSSAPI => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.IANA => EnumProxyValidateDataResult.Equal,
Socks5EnumAuthType.UnKnow => EnumProxyValidateDataResult.Bad,
Socks5EnumAuthType.NotSupported => EnumProxyValidateDataResult.Bad,
_ => EnumProxyValidateDataResult.Bad,
};
}
private static EnumProxyValidateDataResult ValidateAuthPasswordData(ReadOnlyMemory data)
{
/*
VERSION USERNAME_LENGTH USERNAME PASSWORD_LENGTH PASSWORD
1字节 1字节 1到255字节 1字节 1到255字节
0x01 0x01 0x0a 0x01 0x0a
*/
var span = data.Slice(1).Span;
//至少有 USERNAME_LENGTH PASSWORD_LENGTH 字节以上
if (span.Length <= 2)
{
return EnumProxyValidateDataResult.TooShort;
}
byte nameLength = span[0];
//至少有 USERNAME_LENGTH USERNAME PASSWORD_LENGTH
if (span.Length < nameLength + 1 + 1)
{
return EnumProxyValidateDataResult.TooShort;
}
byte passwordLength = span[1 + nameLength];
if (span.Length < 1 + 1 + nameLength + passwordLength)
{
return EnumProxyValidateDataResult.TooShort;
}
return EnumProxyValidateDataResult.Equal;
}
}
}