Server SOCKS5 zapisuje štyri bajty oddelene a klient funguje až po spojení týchto zápisov. Spojenie môže zmeniť časovanie, ale TCP stále nesľubuje jedno čítanie na jeden zápis.

Klient potrebuje parser odpovede. Po voľbe metódy a prípadnej autentifikácii začína odpoveď príkazu SOCKS5 štyrmi bajtmi: verzia, výsledok, rezervovaný bajt a typ adresy. Zvyšná dĺžka závisí od tohto typu adresy.

Parser pre .NET 7+, ktorý má spotrebovať iba úspešnú odpoveď CONNECT, môže použiť:

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

Posledné dva bajty sú pripojený port. IPv4 vyžaduje štyri bajty; IPv6 ich vyžaduje šestnásť; adresa domény nesie pred názvom bajt dĺžky.

Odovzdajte token zrušenia s plánovaným termínom vyjednávania. ReadExactlyAsync zvládne kratšie jednotlivé čítania a vyhodí výnimku, keď sa tok skončí pred požadovanou dĺžkou. Pri zlyhaní zahoďte neúspešné pripojenie cestou upratovania jeho vlastníka.

Pri úspechu sa zastavte na hranici odpovede. Bajty za ňou patria protokolu cieľa. Väčšie špekulatívne čítanie musí prebytočné bajty zachovať, namiesto toho aby zahodilo začiatok aplikačného toku.

Súvisiace články