{"record":{"id":"17538df60018649a","repo":"XTLS/Xray-core","slug":"connection-closed","errorCode":null,"errorMessage":"connection closed","messagePattern":"connection closed","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/tun/handler.go","lineNumber":211,"sourceCode":"\tctx = session.ContextWithContent(ctx, &session.Content{\n\t\tSniffingRequest: t.sniffingRequest,\n\t})\n\tctx = session.SubContextFromMuxInbound(ctx)\n\n\tctx = log.ContextWithAccessMessage(ctx, &log.AccessMessage{\n\t\tFrom:   inbound.Source,\n\t\tTo:     destination,\n\t\tStatus: log.AccessAccepted,\n\t\tReason: \"\",\n\t})\n\terrors.LogInfo(ctx, \"processing from \", source, \" to \", destination)\n\n\tlink := &transport.Link{\n\t\tReader: &buf.TimeoutWrapperReader{Reader: buf.NewReader(conn)},\n\t\tWriter: buf.NewWriter(conn),\n\t}\n\tif err := t.dispatcher.DispatchLink(ctx, destination, link); err != nil {\n\t\terrors.LogError(ctx, errors.New(\"connection closed\").Base(err))\n\t}\n}\n\n// Close implements common.Closable.\nfunc (t *Handler) Close() error {\n\treturn errors.Combine(common.CloseIfExists(t.stack), common.CloseIfExists(t.tun))\n}\n\n// Network implements proxy.Inbound\n// and exists only to comply to proxy interface, declaring it doesn't listen on any network,\n// making the process not open any port for this inbound (input will be network interface)\nfunc (t *Handler) Network() []net.Network {\n\treturn []net.Network{}\n}\n\n// Process implements proxy.Inbound\n// and exists only to comply to proxy interface, which should never get any inputs due to no listening ports\nfunc (t *Handler) Process(ctx context.Context, network net.Network, conn stat.Connection, dispatcher routing.Dispatcher) error {","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/tun/handler.go#L193-L229","documentation":"The tun inbound handler logs this when dispatcher.DispatchLink fails for a connection extracted from the TUN/gVisor stack. 'connection closed' is the wrapper; the real cause (Base err) is the dispatch failure — invalid destination, routing block, or outbound dial error. The client conn is then closed by the deferred Close.","triggerScenarios":"An app on the tun interface connects to a destination that routing blocks or an outbound cannot dial; DNS resolution inside dispatch fails; the destination derived from the packet is invalid (e.g. unroutable literal).","commonSituations":"tun-mode (TUN mode) with routing rules sending everything to a dead outbound; system apps probing link-local or multicast addresses that reach the tun stack; misconfigured sockopt/interface rules after enabling tun.","solutions":["Read the Base error in the same log line to get the dispatch failure reason","Check routing rules for unintended matches (geoip:private, broadcast/multicast ranges) and route them to direct/block explicitly","Verify the outbound referenced by the matched rule is alive and can resolve/dial","Enable routing debug logs to see which rule matched the failing destination"],"exampleFix":"// json: keep local/multicast traffic off the proxy while using tun\n\"routing\": {\"rules\": [\n  {\"type\": \"field\", \"ip\": [\"geoip:private\", \"224.0.0.0/3\", \"ff00::/8\"], \"outboundTag\": \"direct\"}\n]}","handlingStrategy":"try-catch","validationCode":"// guard dispatch of tun connections\nif !validDest(destination) {\n    errors.LogInfo(ctx, \"dropping invalid destination \", destination)\n    return\n}","typeGuard":null,"tryCatchPattern":"if err := t.dispatcher.DispatchLink(ctx, destination, link); err != nil {\n    // per-flow failure: log with cause and let deferred conn.Close() clean up\n    errors.LogError(ctx, errors.New(\"connection closed\").Base(err))\n}","preventionTips":["Route private/multicast/link-local ranges to direct or block explicitly before generic rules","Validate outbounds at startup (tag existence, dialability) when running tun mode","Monitor these per-flow logs at debug level; a flood indicates routing/outbound misconfiguration, not per-connection bugs"],"tags":["tun","dispatch","routing"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}