En SOCKS5-server skriver fire byte separat, og klienten virker først når disse skrivingene er slått sammen. Sammenslåing kan endre tidspunktet, men TCP lover fortsatt ikke én lesing per skriving.

Klienten trenger en svarparser. Etter metodevalg og eventuell påkrevd autentisering begynner et SOCKS5-kommandosvar med fire byte: versjon, resultat, reservert byte og adressetype. Den resterende lengden avhenger av den adressetypen.

En .NET 7+-parser som bare trenger å forbruke et vellykket CONNECT-svar, kan bruke:

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

De to siste bytene er den bundne porten. IPv4 trenger fire byte; IPv6 trenger seksten; en domeneadresse bærer en lengdebyte før navnet.

Oppgi et avbrytelsestoken med den planlagte forhandlingsfristen. ReadExactlyAsync håndterer kortere enkeltlesinger og kaster et unntak når strømmen slutter før den forespurte lengden. Ved feil, forkast den mislykkede tilkoblingen via eierens oppryddingsvei.

Ved suksess, stopp ved svargrensen. Bytene etter den tilhører målprotokollen. En større spekulativ lesing må bevare overflødige byte i stedet for å kaste begynnelsen av applikasjonsstrømmen.

Relaterte artikler