txthinking/brook · error

Expired request

Error message

Expired request

What it means

NewSimpleStreamServer reads a 4-byte BigEndian Unix timestamp at the start of the payload (b[:4]) and rejects the request if it is more than 60 seconds in the past, returning 'Expired request'. This prevents replay of captured handshakes.

Source

Thrown at simplestreamserver.go:69

	if bytes.Compare(password, b[:32]) != 0 {
		x.BP2048.Put(b)
		WaitReadErr(s.Client)
		return nil, errors.New("Password is wrong")
	}
	l := int(binary.BigEndian.Uint16(b[32:34]))
	if l > 2048 {
		x.BP2048.Put(b)
		return nil, errors.New("data too long")
	}
	if _, err := io.ReadFull(s.Client, b[:l]); err != nil {
		x.BP2048.Put(b)
		return nil, err
	}
	i := int64(binary.BigEndian.Uint32(b[:4]))
	if time.Now().Unix()-i > 60 {
		x.BP2048.Put(b)
		WaitReadErr(s.Client)
		return nil, errors.New("Expired request")
	}
	if i%2 == 0 {
		s.network = "tcp"
		s.RB = b
		s.WB = x.BP2048.Get().([]byte)
	}
	if i%2 == 1 {
		s.network = "udp"
		s.Timeout = udptimeout
		s.RB = x.BP65507.Get().([]byte)
		copy(s.RB[:l], b[:l])
		x.BP2048.Put(b)
		s.WB = x.BP65507.Get().([]byte)
	}
	s.dst = socks5.ToAddress(s.RB[4], s.RB[4+1:l-2], s.RB[l-2:])
	return ServerGate(s)
}

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Enable NTP on the client so clocks agree within 60 seconds
  2. Regenerate the timestamp (time.Now().Unix()) for every handshake, honoring the tcp odd/even parity scheme
  3. Do not reuse cached handshake buffers containing old timestamps on reconnect
  4. Investigate and eliminate network delays exceeding 60s (offline queuing, buffering proxies)

Example fix

// before (client reuses old handshake buffer)
conn.Write(cachedHandshake)
// after
i := time.Now().Unix()
binary.BigEndian.PutUint32(b[36:40], uint32(i))
conn.Write(b[:36+4+len(dst)])
Defensive patterns

Strategy: validation

Validate before calling

i := time.Now().Unix()
if binary.BigEndian.Uint32(handshake[36:40]) != uint32(i) || time.Now().Unix()-int64(i) > 55 {
    return errors.New("handshake timestamp stale; rebuild before sending")
}

Try / catch

s, err := NewSimpleStreamServer(password, conn, ...)
if err != nil && err.Error() == "Expired request" {
    log.Printf("expired handshake from %s (clock skew or replay?)", conn.RemoteAddr())
    conn.Close()
}

Prevention

When it happens

Trigger: The timestamp decoded from b[:4] satisfies time.Now().Unix()-i > 60 — replayed handshake capture, client clock more than a minute behind the server, or delayed delivery of the request.

Common situations: Clock skew between client and server (NTP off, VM suspended); resending a recorded handshake (replay attack); long-lived queued/proxied connections exceeding the 60s window; client caching the timestamp across reconnects.

Related errors


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