একটি SOCKS5 সার্ভার চারটি বাইট আলাদাভাবে লেখে, এবং ক্লায়েন্ট কাজ করে কেবল সেই লেখাগুলো একত্র হওয়ার পরেই। একত্র করলে সময় বদলাতে পারে, তবে TCP এখনও প্রতি লেখায় একটি পাঠের প্রতিশ্রুতি দেয় না।

ক্লায়েন্টের একটি উত্তর পার্সার দরকার। পদ্ধতি নির্বাচন ও প্রয়োজনীয় প্রমাণীকরণের পরে SOCKS5 কমান্ড উত্তর চারটি বাইট দিয়ে শুরু হয়: সংস্করণ, ফলাফল, সংরক্ষিত বাইট এবং ঠিকানার ধরন। বাকি দৈর্ঘ্য সেই ঠিকানার ধরনের উপর নির্ভর করে।

কেবল একটি সফল CONNECT উত্তর গ্রহণ করতে হবে এমন একটি .NET 7+ পার্সার ব্যবহার করতে পারে:

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

শেষ দুটি বাইট হলো বাঁধা পোর্ট। IPv4-এর চারটি বাইট লাগে; IPv6-এর ষোলোটি লাগে; একটি ডোমেইন ঠিকানা নামের আগে একটি দৈর্ঘ্য বাইট বহন করে।

উদ্দিষ্ট দরকষাকষির সময়সীমা সহ একটি বাতিল টোকেন দিন। ReadExactlyAsync খাটো আলাদা পাঠ সামলায় এবং চাওয়া দৈর্ঘ্যের আগে স্ট্রিম শেষ হলে ত্রুটি ছোড়ে। ব্যর্থ হলে ব্যর্থ সংযোগটি তার মালিকের পরিষ্কার পথে বাদ দিন।

সফল হলে উত্তরের সীমায় থামুন। এর পরের বাইটগুলো গন্তব্য প্রোটোকলের। বড় অনুমানমূলক পাঠ উদ্বৃত্ত বাইট সংরক্ষণ করবে, অ্যাপ্লিকেশন স্ট্রিমের শুরু ফেলে দেবে না।

সম্পর্কিত নিবন্ধ