תגובות SOCKS5 ב-.NET 7+: טיפול בקריאות TCP חלקיות
קרא את הקידומת הקבועה של תגובת פקודת SOCKS5 ואת הסיומת התלויה ב-ATYP בלי להסתמך על גבולות הכתיבה של TCP בשרת.
שרת 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 מטפל בקריאות בודדות קצרות יותר וזורק חריגה כשהזרם מסתיים לפני האורך המבוקש. בכישלון, השלך את החיבור הכושל דרך נתיב הניקוי של הבעלים שלו.
בהצלחה, עצור בגבול התגובה. הבתים שאחריו שייכים לפרוטוקול היעד. קריאה ספקולטיבית גדולה יותר חייבת לשמר את הבתים העודפים במקום לזרוק את תחילת זרם היישום.