Respostes SOCKS5 a .NET 7+: gestionar lectures TCP parcials
Llegeix el prefix fix de la resposta d'ordre SOCKS5 i el sufix dependent d'ATYP sense dependre de les fronteres d'escriptura TCP del servidor.
Un servidor SOCKS5 escriu quatre bytes per separat, i el client només funciona quan aquestes escriptures s'han combinat. Combinar-les pot canviar el moment, però TCP continua sense prometre una lectura per escriptura.
El client necessita un analitzador de respostes. Després de la selecció de mètode i qualsevol autenticació necessària, una resposta d'ordre SOCKS5 comença amb quatre bytes: versió, resultat, byte reservat i tipus d'adreça. La longitud restant depèn d'aquest tipus d'adreça.
Un analitzador per a .NET 7+ que només ha de consumir una resposta CONNECT correcta pot fer servir:
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);
}
Els dos últims bytes són el port vinculat. IPv4 necessita quatre bytes; IPv6 en necessita setze; una adreça de domini porta un byte de longitud abans del nom.
Proporciona un testimoni de cancel·lació amb el termini de negociació previst. ReadExactlyAsync gestiona lectures individuals més curtes i llança una excepció quan el flux acaba abans de la longitud sol·licitada. En cas de fallada, descarta la connexió fallida pel camí de neteja del seu propietari.
En cas d'èxit, atura't a la frontera de la resposta. Els bytes posteriors pertanyen al protocol de destinació. Una lectura especulativa més gran ha de conservar els bytes sobrants en lloc de llençar l'inici del flux d'aplicació.