Bir SOCKS5 sunucusu dört baytı ayrı ayrı yazar ve istemci ancak bu yazmalar birleştikten sonra çalışır. Birleştirme zamanlamayı değiştirebilir, ancak TCP hâlâ her yazma için bir okuma vaat etmiyor.

İstemcinin bir yanıt ayrıştırıcısına ihtiyacı var. Yöntem seçiminden ve gereken kimlik doğrulamadan sonra, bir SOCKS5 komut yanıtı dört baytla başlar: sürüm, sonuç, ayrılmış bayt ve adres türü. Kalan uzunluk bu adres türüne bağlıdır.

Yalnızca başarılı bir CONNECT yanıtını tüketmesi gereken bir .NET 7+ ayrıştırıcısı şunu kullanabilir:

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

Son iki bayt bağlanan bağlantı noktasıdır. IPv4 dört bayt gerektirir; IPv6 on altı gerektirir; bir alan adı adresi, adından önce bir uzunluk baytı taşır.

Amaçlanan anlaşma süresiyle birlikte bir iptal belirteci sağlayın. ReadExactlyAsync daha kısa tekil okumaları işler ve akış istenen uzunluktan önce biterse bir özel durum fırlatır. Başarısızlık durumunda, başarısız bağlantıyı sahibinin temizleme yolu üzerinden atın.

Başarı durumunda yanıt sınırında durun. Ondan sonraki baytlar hedef protokole aittir. Daha büyük bir spekülatif okuma, uygulama akışının başlangıcını atmak yerine fazla baytları korumalıdır.

İlgili makaleler