SOCKS5 odgovori u .NET 7+: rukovanje djelimičnim TCP čitanjima
Pročitajte fiksni prefiks odgovora SOCKS5 komande i sufiks koji zavisi od ATYP-a bez oslanjanja na granice TCP upisa na serveru.
SOCKS5 server zapisuje četiri bajta odvojeno, a klijent radi tek nakon što se ti upisi spoje. Spajanje može promijeniti vrijeme, ali TCP još uvijek ne obećava jedno čitanje po upisu.
Klijentu treba parser odgovora. Nakon odabira metode i bilo koje potrebne autentifikacije, odgovor SOCKS5 komande počinje s četiri bajta: verzija, rezultat, rezervisani bajt i tip adrese. Preostala dužina zavisi od tog tipa adrese.
Parser za .NET 7+ koji treba potrošiti samo uspješan CONNECT odgovor može koristiti:
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);
}
Posljednja dva bajta su vezani port. IPv4 zahtijeva četiri bajta; IPv6 šesnaest; adresa domena nosi bajt dužine prije imena.
Dostavite token za otkazivanje s predviđenim rokom pregovaranja. ReadExactlyAsync obrađuje kraća pojedinačna čitanja i baca izuzetak kada tok završi prije tražene dužine. U slučaju neuspjeha odbacite neuspješnu vezu kroz putanju čišćenja njenog vlasnika.
Na uspjehu se zaustavite na granici odgovora. Bajti nakon nje pripadaju protokolu odredišta. Veće spekulativno čitanje mora sačuvati višak bajtova umjesto da odbaci početak aplikacijskog toka.