Strežnik SOCKS5 zapiše štiri bajte ločeno in odjemalec deluje šele po združitvi teh zapisov. Združevanje lahko spremeni časovno uskladitev, vendar TCP še vedno ne obljublja enega branja na zapis.

Odjemalec potrebuje razčlenjevalnik odziva. Po izbiri metode in morebitni potrebni overitvi se odziv ukaza SOCKS5 začne s štirimi bajti: različica, rezultat, rezervirani bajt in vrsta naslova. Preostala dolžina je odvisna od te vrste naslova.

Razčlenjevalnik za .NET 7+, ki mora porabiti le uspešen odziv CONNECT, lahko uporabi:

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

Zadnja dva bajta sta vezana vrata. IPv4 potrebuje štiri bajte; IPv6 jih potrebuje šestnajst; naslov domene nosi bajt dolžine pred imenom.

Zagotovite žeton za preklic z načrtovanim rokom pogajanja. ReadExactlyAsync obdeluje krajša posamezna branja in vrže izjemo, ko se tok konča pred zahtevano dolžino. Ob napaki zavrzite neuspešno povezavo prek poti čiščenja njenega lastnika.

Ob uspehu se ustavite na meji odziva. Bajti za njo pripadajo ciljnemu protokolu. Večje špekulativno branje mora ohraniti presežne bajte, namesto da bi zavrglo začetek aplikacijskega toka.

Sorodni članki