txthinking/brook · error

Expired request

Error message

Expired request

What it means

This error is thrown in the packet server's Handle function when the Unix timestamp embedded at bytes 32-36 of the incoming request packet is more than 60 seconds older than the server's current time. It is an anti-replay measure: clients must include a fresh timestamp so stale or replayed packets are rejected.

Source

Thrown at simplepacketserverconn.go:49

}

func NewSimplePacketServerConnFactory() *SimplePacketServerConnFactory {
	return &SimplePacketServerConnFactory{
		Conns: make(map[string]*PacketConn),
		Lock:  &sync.Mutex{},
	}
}

func (f *SimplePacketServerConnFactory) Handle(addr *net.UDPAddr, b, p []byte, w func([]byte) (int, error), timeout int) (net.Conn, []byte, error) {
	if len(b) < 32+4 {
		return nil, nil, errors.New("data too small")
	}
	if bytes.Compare(p, b[:32]) != 0 {
		return nil, nil, errors.New("Password is wrong")
	}
	i := int64(binary.BigEndian.Uint32(b[32 : 32+4]))
	if time.Now().Unix()-i > 60 {
		return nil, nil, errors.New("Expired request")
	}
	a, h, p, err := socks5.ParseBytesAddress(b[32+4:])
	if err != nil {
		return nil, nil, err
	}
	dst := socks5.ToAddress(a, h, p)
	f.Lock.Lock()
	c, ok := f.Conns[addr.String()+dst]
	f.Lock.Unlock()
	if ok {
		_ = c.In(b[32+4+1+len(h)+2:])
		return nil, nil, nil
	}
	f.Lock.Lock()
	c = NewPacketConn(b[32+4+1+len(h)+2:], w, timeout, func() {
		f.Lock.Lock()
		delete(f.Conns, addr.String()+dst)
		f.Lock.Unlock()

View on GitHub (pinned to 5cd13ef3b1)

Solutions

  1. Sync the client's clock (enable NTP) so its Unix time matches the server within 60 seconds
  2. Ensure the client regenerates the timestamp for every request instead of reusing/caching packets
  3. Check for network paths (queued proxies, offline buffering) that delay packets more than 60s and reduce latency or retransmit promptly
  4. Verify the client writes the timestamp at offset 32 in BigEndian uint32, matching the server's read position

Example fix

// before (client caches/stale timestamp)
i := cachedTimestamp
binary.BigEndian.PutUint32(b[32:36], uint32(i))
// after
i := time.Now().Unix()
binary.BigEndian.PutUint32(b[32:36], uint32(i))
Defensive patterns

Strategy: validation

Validate before calling

ts := int64(binary.BigEndian.Uint32(req[32:36]))
if time.Now().Unix()-ts > 55 {
    return errors.New("request would be rejected: timestamp older than 60s")
}

Try / catch

dst, h, p, err := conn.Handle(req)
if err != nil && err.Error() == "Expired request" {
    // resync clock and rebuild the request with a fresh timestamp
}

Prevention

When it happens

Trigger: A UDP packet arrives whose embedded 4-byte BigEndian timestamp (b[32:36]) is older than 60 seconds, e.g. a replayed capture, a client with a skewed clock, or a packet delayed in transit beyond the 60s window.

Common situations: Client machine clock drifts behind the server by more than a minute; a proxy or queuing network delays datagrams; automated replay of captured packets; NTP disabled or misconfigured on the client.

Related errors


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