En SOCKS5-server skriver fyra byte separat, och klienten fungerar först när dessa skrivningar har slagits samman. Sammanslagning kan ändra timingen, men TCP lovar fortfarande inte en läsning per skrivning.

Klienten behöver en svarsparser. Efter metodval och eventuell nödvändig autentisering börjar ett SOCKS5-kommandosvar med fyra byte: version, resultat, reserverad byte och adresstyp. Den återstående längden beror på den adresstypen.

En parser för .NET 7+ som bara behöver förbruka ett lyckat CONNECT-svar kan använda:

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 två sista byten är den bundna porten. IPv4 kräver fyra byte; IPv6 kräver sexton; en domänadress bär en längdbyte före namnet.

Tillhandahåll en avbrytandetoken med den avsedda förhandlingsfristen. ReadExactlyAsync hanterar kortare enskilda läsningar och kastar ett undantag när strömmen slutar före den begärda längden. Vid fel, kasta bort den misslyckade anslutningen via ägarens städväg.

Vid framgång, stanna vid svarsgränsen. Byten efter den tillhör destinationsprotokollet. En större spekulativ läsning måste bevara överskottsbyten i stället för att kasta bort början av applikationsströmmen.

Relaterade artiklar