.NET 7+ SOCKS5 उत्तर: आंशिक TCP पढ़त संभालना
सर्वर की TCP लेखन सीमाओं पर निर्भर हुए बिना SOCKS5 कमांड उत्तर का निश्चित उपसर्ग और ATYP-निर्भर प्रत्यय पढ़ें।
एक SOCKS5 सर्वर चार बाइट अलग-अलग लिखता है, और क्लाइंट तभी काम करता है जब वे लेखन जुड़ जाते हैं। जोड़ने से समय बदल सकता है, लेकिन TCP अब भी हर लेखन के लिए एक पढ़त का वादा नहीं करता।
क्लाइंट को उत्तर पार्सर चाहिए। विधि चयन और किसी भी आवश्यक प्रमाणीकरण के बाद, SOCKS5 कमांड उत्तर चार बाइट से शुरू होता है: संस्करण, परिणाम, आरक्षित बाइट और पता प्रकार। शेष लंबाई उसी पता प्रकार पर निर्भर करती है।
एक .NET 7+ पार्सर जिसे केवल सफल CONNECT उत्तर उपभोग करना है, यह उपयोग कर सकता है:
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 छोटी व्यक्तिगत पढ़तें संभालता है और माँगी गई लंबाई से पहले स्ट्रीम समाप्त होने पर अपवाद फेंकता है। विफलता पर, विफल कनेक्शन को उसके स्वामी के सफ़ाई मार्ग से हटा दें।
सफलता पर, उत्तर की सीमा पर रुकें। उसके बाद की बाइट गंतव्य प्रोटोकॉल की हैं। बड़ी अनुमानित पढ़त को अधिक बाइट संरक्षित करनी चाहिए, अनुप्रयोग स्ट्रीम की शुरुआत फेंकनी नहीं।