SOCKS5-válaszok .NET 7+-ban: részleges TCP-olvasások kezelése
Olvasd be a SOCKS5-parancsválasz rögzített előtagját és az ATYP-től függő utótagot anélkül, hogy a kiszolgáló TCP-írási határaira hagyatkoznál.
A SOCKS5-kiszolgáló négy bájtot ír külön, és a kliens csak akkor működik, ha ezek az írások egyesültek. Az egyesítés megváltoztathatja az időzítést, de a TCP továbbra sem ígér egy olvasást írásonként.
A kliensnek válaszelemzőre van szüksége. A metódus kiválasztása és az esetleges hitelesítés után a SOCKS5-parancsválasz négy bájttal kezdődik: verzió, eredmény, fenntartott bájt és címtípus. A fennmaradó hossz ettől a címtípustól függ.
Egy .NET 7+-elemző, amelynek csak egy sikeres CONNECT-választ kell feldolgoznia, ezt használhatja:
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);
}
Az utolsó két bájt a kötött port. Az IPv4 négy bájtot igényel; az IPv6 tizenhatot; a tartománycím egy hosszbájtot hordoz a név előtt.
Adj meg egy megszakítási tokent a tervezett egyeztetési határidővel. A ReadExactlyAsync kezeli a rövidebb egyedi olvasásokat, és kivételt dob, ha a stream a kért hossz előtt véget ér. Hiba esetén a sikertelen kapcsolatot a tulajdonosának tisztítási útvonalán keresztül dobja el.
Siker esetén állj meg a válasz határán. Az utána következő bájtok a célprotokollhoz tartoznak. A nagyobb spekulatív olvasásnak meg kell őriznie a felesleges bájtokat, nem pedig eldobni az alkalmazásfolyam elejét.