The SOCKS4 connection request succeeds, but the application never sees the server's opening greeting. One place to look is the connector's first read. A sixteen-byte read is too large for an eight-byte SOCKS4 reply.

Reply fieldBytes
Reply version field1
Result code1
Port field2
Address field4

The result code 0x5a indicates that the request was granted. SOCKS4a changes how the request carries a hostname; it does not turn the reply into sixteen bytes.

After the reply, the same TCP stream carries the destination protocol. A mail server may send its greeting immediately. A read that consumes sixteen available bytes can therefore take the complete proxy reply plus the first eight bytes of that greeting. If nothing follows yet, an oversized blocking read can instead add an unnecessary wait.

Exact length is a parser responsibility

Requesting eight bytes once is not sufficient evidence that eight bytes arrived. Stream reads can return less. Collect exactly the reply's length under a deadline, stop on a closed or failed stream, inspect the reply, and leave subsequent bytes for the application.

If the connector uses a larger buffered read, preserve everything after the boundary and pass it to the next consumer. Discarding the surplus is the same data loss with a different read size.

SOCKS5 needs its own parser. Its reply address can have different lengths according to the address type. Replacing every proxy read with a fixed eight-byte read would fix one protocol while breaking another.

Artiglyn mynjee