{"record":{"id":"eaca289dfcdd0fb5","repo":"txthinking/brook","slug":"dst-too-long-eaca28","errorCode":null,"errorMessage":"dst too long","messagePattern":"dst too long","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"streamclient.go","lineNumber":54,"sourceCode":"\tca      cipher.AEAD\n\tsn      []byte\n\tsa      cipher.AEAD\n\tRB      []byte\n\tWB      []byte\n\tTimeout int\n\tnetwork string\n\tsrc     string\n\tdst     string\n}\n\nfunc NewStreamClient(network string, password []byte, src string, server net.Conn, timeout int, dst []byte) (Exchanger, error) {\n\tif timeout != 0 {\n\t\tif err := server.SetDeadline(time.Now().Add(time.Duration(timeout) * time.Second)); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t}\n\tif len(dst) > 2048-2-16-4-16 {\n\t\treturn nil, errors.New(\"dst too long\")\n\t}\n\tc := &StreamClient{network: network, Server: server, Timeout: timeout, src: src, dst: socks5.ToAddress(dst[0], dst[1:len(dst)-2], dst[len(dst)-2:])}\n\n\tc.cn = x.BP12.Get().([]byte)\n\tif _, err := io.ReadFull(rand.Reader, c.cn); err != nil {\n\t\tx.BP12.Put(c.cn)\n\t\treturn nil, err\n\t}\n\tck := x.BP32.Get().([]byte)\n\tif _, err := io.ReadFull(hkdf.New(sha256.New, password, c.cn, ClientHKDFInfo), ck); err != nil {\n\t\tx.BP12.Put(c.cn)\n\t\tx.BP32.Put(ck)\n\t\treturn nil, err\n\t}\n\tif _, err := c.Server.Write(c.cn); err != nil {\n\t\tx.BP12.Put(c.cn)\n\t\tx.BP32.Put(ck)\n\t\treturn nil, err","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/txthinking/brook/blob/5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8/streamclient.go#L36-L72","documentation":"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).","triggerScenarios":"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.","commonSituations":"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'.","solutions":["Check the dst construction: it should be [atyp, ...host..., port(2)] and normally well under 100 bytes","Validate len(dst) <= 2030 before calling NewStreamClient","Fix any code that appends the port or address-type byte repeatedly or passes a whole buffer instead of the address","Log the dst contents and length at the call site to find where the oversized address originates"],"exampleFix":"// before: passing a whole buffer instead of the parsed address\nclient, err := NewStreamClient(network, conn, src, rawPacket)\n\n// after: pass the parsed SOCKS5 address\ndst := socks5.ToAddress(packet[0], string(packet[1:n-2]), string(packet[n-2:]))\nclient, err := NewStreamClient(network, conn, src, dst)","handlingStrategy":"validation","validationCode":"func dstFits(dst []byte) bool {\n\treturn len(dst) <= 2048-2-16-4-16\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Assemble dst as [atyp, host..., port2] via socks5.ToAddress","Never pass raw buffers where a parsed address is expected","Assert len(dst) is small (<100 bytes) at construction"],"tags":["socks5","validation","address"],"backgroundTag":"argument-out-of-range","analyzedSha":"5cd13ef3b1fb574e88ebf2c1b5d95f2ebe1342c8","analyzedAt":"2026-09-06T04:35:00.432Z","contentChangedAt":"2026-09-06T04:35:00.432Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}