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.

Articole similare