Balasan SOCKS5 di .NET 7+: menangani pembacaan TCP parsial
Baca prefiks tetap balasan perintah SOCKS5 dan sufiks yang bergantung pada ATYP tanpa mengandalkan batas penulisan TCP server.
Server SOCKS5 menulis empat byte secara terpisah, dan klien baru bekerja setelah tulisan tersebut digabungkan. Penggabungan dapat mengubah waktu, tetapi TCP tetap tidak menjanjikan satu pembacaan per penulisan.
Klien memerlukan parser balasan. Setelah pemilihan metode dan autentikasi apa pun yang diperlukan, balasan perintah SOCKS5 dimulai dengan empat byte: versi, hasil, byte cadangan, dan jenis alamat. Panjang sisanya bergantung pada jenis alamat tersebut.
Parser .NET 7+ yang hanya perlu mengonsumsi balasan CONNECT yang berhasil dapat menggunakan:
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);
}
Dua byte terakhir adalah port terikat. IPv4 membutuhkan empat byte; IPv6 membutuhkan enam belas; alamat domain membawa byte panjang sebelum namanya.
Berikan token pembatalan dengan tenggat negosiasi yang dimaksud. ReadExactlyAsync menangani pembacaan individual yang lebih pendek dan melempar pengecualian ketika aliran berakhir sebelum panjang yang diminta. Jika gagal, buang koneksi yang gagal melalui jalur pembersihan pemiliknya.
Jika berhasil, berhenti di batas balasan. Byte setelahnya milik protokol tujuan. Pembacaan spekulatif yang lebih besar harus mempertahankan byte berlebih alih-alih membuang awal aliran aplikasi.