SOCKS5 odgovori u .NET 7+: rukovanje djelomičnim TCP čitanjima
Pročitajte fiksni prefiks odgovora SOCKS5 naredbe i sufiks koji ovisi o ATYP-u bez oslanjanja na granice TCP upisa na poslužitelju.
SOCKS5 poslužitelj 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 autentikacije, odgovor SOCKS5 naredbe počinje s četiri bajta: verzija, rezultat, rezervirani bajt i vrsta adrese. Preostala duljina ovisi o toj vrsti 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 domene nosi bajt duljine prije imena.
Dostavite token za otkazivanje s predviđenim rokom pregovaranja. ReadExactlyAsync obrađuje kraća pojedinačna čitanja i baca iznimku kada tok završi prije tražene duljine. U slučaju neuspjeha odbacite neuspjelu vezu putem putanje čišćenja njezina vlasnika.
Na uspjehu se zaustavite na granici odgovora. Bajtovi nakon nje pripadaju protokolu odredišta. Veće spekulativno čitanje mora sačuvati višak bajtova umjesto da odbaci početak aplikacijskog toka.