SOCKS5 одговори у .NET 7+: руковање делимичним TCP читањима
Прочитајте фиксни префикс одговора SOCKS5 команде и суфикс који зависи од ATYP-а без ослањања на границе TCP уписа на серверу.
SOCKS5 сервер записује четири бајта одвојено, а клијент ради тек након што се ти уписи споје. Спајање може променити време, али TCP још увек не обећава једно читање по упису.
Клијенту је потребан парсер одговора. Након избора методе и било које потребне аутентификације, одговор SOCKS5 команде почиње са четири бајта: верзија, резултат, резервисани бајт и тип адресе. Преостала дужина зависи од тог типа адресе.
Парсер за .NET 7+ који треба да потроши само успешан CONNECT одговор може да користи:
static async Task ReadConnectReply(Stream stream, CancellationToken ct)
{
byte[] prefix = new byte[4];
await stream.ReadExactlyAsync(prefix, ct);
if (prefix[0] != 5 || prefix[2] != 0)
throw new IOException("Invalid SOCKS5 reply");
if (prefix[1] != 0)
throw new IOException($"SOCKS5 request failed: {prefix[1]}");
int remaining;
switch (prefix[3])
{
case 1: remaining = 4 + 2; break;
case 4: remaining = 16 + 2; break;
case 3:
byte[] length = new byte[1];
await stream.ReadExactlyAsync(length, ct);
remaining = length[0] + 2;
break;
default:
throw new IOException("Unknown SOCKS5 address type");
}
await stream.ReadExactlyAsync(new byte[remaining], ct);
}
Последња два бајта су везани порт. IPv4 захтева четири бајта; IPv6 шеснаест; адреса домена носи бајт дужине пре имена.
Доставите токен за отказивање са предвиђеним роком преговарања. ReadExactlyAsync обрађује краћа појединачна читања и баца изузетак када се ток заврши пре тражене дужине. У случају неуспеха одбаците неуспешну везу кроз путању чишћења њеног власника.
На успеху се зауставите на граници одговора. Бајтови након ње припадају протоколу одредишта. Веће спекулативно читање мора сачувати вишак бајтова уместо да одбаци почетак апликационог тока.