Răspunsuri SOCKS5 în .NET 7+: gestionarea citirilor TCP parțiale
Citește prefixul fix al răspunsului la comanda SOCKS5 și sufixul dependent de ATYP fără a te baza pe limitele de scriere TCP ale serverului.
Un server SOCKS5 scrie patru octeți separat, iar clientul funcționează abia după ce aceste scrieri sunt combinate. Combinarea poate schimba sincronizarea, dar TCP încă nu promite o citire pentru fiecare scriere.
Clientul are nevoie de un parser de răspuns. După selectarea metodei și orice autentificare necesară, un răspuns la comanda SOCKS5 începe cu patru octeți: versiune, rezultat, octet rezervat și tip de adresă. Lungimea rămasă depinde de acel tip de adresă.
Un parser pentru .NET 7+ care trebuie să consume doar un răspuns CONNECT reușit poate folosi:
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);
}
Ultimii doi octeți sunt portul legat. IPv4 necesită patru octeți; IPv6 necesită șaisprezece; o adresă de domeniu poartă un octet de lungime înaintea numelui.
Furnizează un token de anulare cu termenul de negociere prevăzut. ReadExactlyAsync gestionează citiri individuale mai scurte și aruncă o excepție când fluxul se termină înainte de lungimea solicitată. În caz de eșec, aruncă conexiunea eșuată prin calea de curățare a proprietarului ei.
În caz de succes, oprește-te la granița răspunsului. Octeții de după aparțin protocolului de destinație. O citire speculativă mai mare trebuie să păstreze octeții în plus în loc să arunce începutul fluxului aplicației.