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; } } }