txthinking/brook · error

dst too long

Error message

dst too long

What it means

NewStreamClient validates that the destination address (dst) fits into the fixed protocol frame, which reserves 2+16+4+16 bytes of the 2048-byte buffer for length, nonce/timestamp and tag overhead. If dst exceeds 2030 bytes the client refuses to build the request rather than silently truncating. dst here is a SOCKS5-style address (ATYP byte + host + port).

Source

Thrown at streamclient.go:54

	ca      cipher.AEAD
	sn      []byte
	sa      cipher.AEAD
	RB      []byte
	WB      []byte
	Timeout int
	network string
	src     string
	dst     string
}

func NewStreamClient(network string, password []byte, src string, server net.Conn, timeout int, dst []byte) (Exchanger, error) {
	if timeout != 0 {
		if err := server.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second)); err != nil {
			return nil, err
		}
	}
	if len(dst) > 2048-2-16-4-16 {
		return nil, errors.New("dst too long")
	}
	c := &StreamClient{network: network, Server: server, Timeout: timeout, src: src, dst: socks5.ToAddress(dst[0], dst[1:len(dst)-2], dst[len(dst)-2:])}

	c.cn = x.BP12.Get().([]byte)
	if _, err := io.ReadFull(rand.Reader, c.cn); err != nil {
		x.BP12.Put(c.cn)
		return nil, err
	}
	ck := x.BP32.Get().([]byte)
	if _, err := io.ReadFull(hkdf.New(sha256.New, password, c.cn, ClientHKDFInfo), ck); err != nil {
		x.BP12.Put(c.cn)
		x.BP32.Put(ck)
		return nil, err
	}
	if _, err := c.Server.Write(c.cn); err != nil {
		x.BP12.Put(c.cn)
		x.BP32.Put(ck)
		return nil, err

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Check the dst construction: it should be [atyp, ...host..., port(2)] and normally well under 100 bytes
  2. Validate len(dst) <= 2030 before calling NewStreamClient
  3. Fix any code that appends the port or address-type byte repeatedly or passes a whole buffer instead of the address
  4. Log the dst contents and length at the call site to find where the oversized address originates

Example fix

// before: passing a whole buffer instead of the parsed address
client, err := NewStreamClient(network, conn, src, rawPacket)

// after: pass the parsed SOCKS5 address
dst := socks5.ToAddress(packet[0], string(packet[1:n-2]), string(packet[n-2:]))
client, err := NewStreamClient(network, conn, src, dst)
Defensive patterns

Strategy: validation

Validate before calling

func dstFits(dst []byte) bool {
	return len(dst) <= 2048-2-16-4-16
}

Prevention

When it happens

Trigger: Calling NewStreamClient (directly or via CreateExchanger/TCPHandle/UDPHandle) with a dst slice longer than 2030 bytes - practically only possible with an absurdly long hostname or a corrupted address buffer.

Common situations: Passing an uninitialized or wrongly-assembled dst buffer; constructing the SOCKS5 address manually with host and port slices concatenated incorrectly; a bug in upstream code producing a multi-KB 'hostname'.

Related errors


AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06). Data as JSON: /api/errors/eaca289dfcdd0fb5. Report an issue: GitHub.