SOCKS5-server kirjutab neli baiti eraldi ja klient töötab alles siis, kui need kirjutused on ühendatud. Ühendamine võib ajastust muuta, kuid TCP ei taga endiselt ühte lugemist ühe kirjutuse kohta.

Kliendil on vaja vastuse parsijat. Pärast meetodi valikut ja võimalikku autentimist algab SOCKS5-käsu vastus nelja baidiga: versioon, tulemus, reserveeritud bait ja aadressitüüp. Ülejäänud pikkus sõltub sellest aadressitüübist.

Parsija .NET 7+ jaoks, mis peab tarbima ainult õnnestunud CONNECT-vastust, võib kasutada:

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

Viimased kaks baiti on seotud port. IPv4 vajab nelja baiti; IPv6 vajab kuusteist; domeeniaadress kannab enne nime pikkusbaiti.

Anna tühistamistoken kavandatud läbirääkimistähtajaga. ReadExactlyAsync käsitleb lühemaid üksiklugemisi ja viskab erindi, kui voog lõpeb enne nõutud pikkust. Ebaõnnestumise korral visake ebaõnnestunud ühendus kõrvale selle omaniku koristusteega.

Õnnestumise korral peatu vastuse piiril. Selle järel olevad baidid kuuluvad sihtprotokollile. Suurem spekulatiivne lugemine peab ülejäävad baidid alles hoidma, mitte rakenduse voo algust ära viskama.

Seotud artiklid