ginuerzh/gost · error

not a TCP connection

Error message

not a TCP connection

What it means

getOriginalDstAddr needs to access OS-specific socket options that only exist on *net.TCPConn to recover the original destination address of a transparently redirected connection. If the underlying connection is not a TCP connection, the retrieval cannot proceed and this error is returned.

Source

Thrown at redirect.go:102

		return
	}

	// only ipv4 support
	ip := net.IPv4(mreq.Multiaddr[4], mreq.Multiaddr[5], mreq.Multiaddr[6], mreq.Multiaddr[7])
	port := uint16(mreq.Multiaddr[2])<<8 + uint16(mreq.Multiaddr[3])
	addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", ip.String(), port))
	if err != nil {
		return
	}

	cc, err := net.FileConn(fc)
	if err != nil {
		return
	}

	c, ok := cc.(*net.TCPConn)
	if !ok {
		err = errors.New("not a TCP connection")
	}
	return
}

type udpRedirectHandler struct {
	options *HandlerOptions
}

// UDPRedirectHandler creates a server Handler for UDP transparent server.
func UDPRedirectHandler(opts ...HandlerOption) Handler {
	h := &udpRedirectHandler{}
	h.Init(opts...)

	return h
}

func (h *udpRedirectHandler) Init(options ...HandlerOption) {
	if h.options == nil {

View on GitHub (pinned to a33fdbf4c9)

Solutions

  1. Ensure the redirect handler only receives raw TCP connections (check listener type)
  2. Unwrap custom conn wrappers to the underlying *net.TCPConn before handling
  3. For UDP traffic, use the UDP redirect handler instead

Example fix

// before
go tcpHandler.Handle(conn) // conn may be a wrapped/UDP conn
// after
if tc, ok := conn.(*net.TCPConn); ok {
    go tcpHandler.Handle(tc)
} else {
    log.Log("skipping non-TCP conn in redirect handler")
}
Defensive patterns

Strategy: type-guard

Type guard

func asTCPConn(c net.Conn) (*net.TCPConn, bool) {
    tc, ok := c.(*net.TCPConn)
    return tc, ok
}

Try / catch

if _, ok := conn.(*net.TCPConn); !ok {
    // route to the appropriate (e.g. UDP) handler or skip
    return
}

Prevention

When it happens

Trigger: Handle is invoked on a connection whose underlying type fails the type assertion cc.(*net.TCPConn) — e.g. a UDP flow or a wrapped/tunneled conn passed to a TCP redirect handler.

Common situations: Wiring a UDP listener's connections into the TCP redirect handler, or wrapping conns in a custom type that doesn't expose the inner *net.TCPConn via Unwrap-style access.

Related errors


AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02). Data as JSON: /api/errors/2eb612867d206fd8. Report an issue: GitHub.