ginuerzh/gost · error
not a packet connection
Error message
not a packet connection
What it means
When routing UDP-like traffic through the TUN stack, the code takes the established connection cc and asserts it to net.PacketConn. If the underlying connection doesn't implement PacketConn (it's a stream conn), it returns "not a packet connection" and logs it with the tun prefix. This guards the packet-forwarding path which requires WriteTo/ReadFrom semantics.
Source
Thrown at tuntap.go:178
return
}
}
var tempDelay time.Duration
for {
err := func() error {
var err error
var pc net.PacketConn
// fake tcp mode will be ignored when the client specifies a chain.
if raddr != nil && !h.options.Chain.IsEmpty() {
cc, err := h.options.Chain.DialContext(context.Background(), "udp", raddr.String())
if err != nil {
return err
}
var ok bool
pc, ok = cc.(net.PacketConn)
if !ok {
err = errors.New("not a packet connection")
log.Logf("[tun] %s - %s: %s", conn.LocalAddr(), raddr, err)
return err
}
} else {
if h.options.TCPMode {
if raddr != nil {
pc, err = tcpraw.Dial("tcp", raddr.String())
} else {
pc, err = tcpraw.Listen("tcp", h.options.Node.Addr)
}
} else {
laddr, _ := net.ResolveUDPAddr("udp", h.options.Node.Addr)
pc, err = net.ListenUDP("udp", laddr)
}
}
if err != nil {
return err
}View on GitHub (pinned to a33fdbf4c9)
Solutions
- Use a UDP-capable transport/relay (one that returns net.PacketConn) for tun UDP routes
- Check the connection type before forwarding and fall back to a packet-capable relay chain
- If TCPMode is intended, ensure UDP flows aren't routed through this code path (route/filter them at the tun option level)
Example fix
// before
pc, ok := cc.(net.PacketConn)
if !ok { return errors.New("not a packet connection") }
// after
pc, ok := cc.(net.PacketConn)
if !ok {
pc, err = dialPacketConn(raddr) // use a UDP-capable dialer
if err != nil { return err }
} Defensive patterns
Strategy: type-guard
Validate before calling
pc, ok := cc.(net.PacketConn)
if !ok {
// route via a UDP-capable relay before entering the packet path
return errors.New("transport does not support packet connections")
} Type guard
func toPacketConn(c net.Conn) (net.PacketConn, bool) {
pc, ok := c.(net.PacketConn)
return pc, ok
} Try / catch
if err := forward(conn, raddr); err != nil {
if err.Error() == "not a packet connection" {
// fall back to a UDP-capable relay chain
return forwardViaPacketRelay(conn, raddr)
}
return err
} Prevention
- Configure tun UDP routes to use UDP-capable transports/relays only
- Verify chain hops support net.PacketConn before enabling tun UDP mode
- Don't mix TCPMode transports with UDP tun routing
When it happens
Trigger: TUN in non-TCP mode forwarding a UDP flow whose relayed connection cc is a stream-oriented net.Conn (e.g. a TCP/mux relay) rather than a net.PacketConn; config routes UDP traffic over a TCP-only transport.
Common situations: Routing tun UDP traffic through a TCP-mode relay/chain; version or config change where the UDP relay dialer started returning stream conns; mixing TCPMode with UDP routes.
Related errors
- kcp: wrong connection type
- accpet on closed listener
- wrong connection type
- ciphertext too short
- not a TCP connection
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/44f13bc69119634e.
Report an issue: GitHub.