{"record":{"id":"215d82a123b918fb","repo":"netbirdio/netbird","slug":"src-faker-raw-conn-s","errorCode":null,"errorMessage":"src faker raw conn: %s","messagePattern":"src faker raw conn: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/iface/wgproxy/udp/proxy.go","lineNumber":200,"sourceCode":"\n\tp.cancel()\n\n\tp.pausedCond.L.Lock()\n\tp.paused = false\n\tp.pausedCond.Signal()\n\tp.pausedCond.L.Unlock()\n\n\tif err := p.remoteConn.Close(); err != nil && !errors.Is(err, net.ErrClosed) {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"remote conn: %s\", err))\n\t}\n\n\tif err := p.localConn.Close(); err != nil {\n\t\tresult = multierror.Append(result, fmt.Errorf(\"local conn: %s\", err))\n\t}\n\n\tif p.srcFakerConn != nil {\n\t\tif err := p.srcFakerConn.Close(); err != nil {\n\t\t\tresult = multierror.Append(result, fmt.Errorf(\"src faker raw conn: %s\", err))\n\t\t}\n\t}\n\n\treturn cerrors.FormatErrorOrNil(result)\n}\n\n// proxyToRemote proxies from Wireguard to the RemoteKey\nfunc (p *WGUDPProxy) proxyToRemote(ctx context.Context) {\n\tdefer func() {\n\t\tif err := p.close(); err != nil {\n\t\t\tlog.Warnf(\"error in proxy to remote loop: %s\", err)\n\t\t}\n\t}()\n\n\tbuf := make([]byte, p.mtu+bufsize.WGBufferOverhead)\n\tfor ctx.Err() == nil {\n\t\tn, err := p.localConn.Read(buf)\n\t\tif err != nil {","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/wgproxy/udp/proxy.go#L182-L218","documentation":"Appended to the close() multierror when SrcFaker.Close() (which just closes the underlying raw socket) fails. The SrcFaker exists only while the proxy was redirected to fake packet source addresses (RedirectAs, used for direct peerings to keep the WG socket bound to one port); it may already be nil if no redirect ever happened or Work() closed it during un-redirect.","triggerScenarios":"Close racing with Work()/RedirectAs() swapping srcFakerConn (they close the old one under pausedCond, close() runs under closeMu, and the two locks do not serialize each other); raw socket fd already invalid.","commonSituations":"Peer transitions relay->direct->relay; shutdown right after a redirect switch. Because Work() and RedirectAs nil out srcFakerConn after closing it, the residual error usually means a double close slipped through the race window.","solutions":["Treat as benign teardown noise; the closed flag prevents repeated closes from close() itself","If raw-socket fd leaks are suspected, track `ls /proc/$(pgrep -x netbird)/fd` across redirects","Upgrade the agent - redirect/close interleaving has been a churn area"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := p.srcFakerConn.Close(); err != nil {\n    if errors.Is(err, syscall.EBADF) || errors.Is(err, net.ErrClosed) {\n        log.Debugf(\"src faker already closed during redirect swap: %v\", err)\n    } else {\n        result = multierror.Append(result, fmt.Errorf(\"src faker raw conn: %w\", err))\n    }\n}","preventionTips":["Serialize RedirectAs/Work/close against each other - they coordinate via different locks (pausedCond vs closeMu) and can race on srcFakerConn","Nil out srcFakerConn immediately after closing so a second close path sees nil instead of a dead socket","Monitor raw-socket fd counts during rapid direct/relay transitions"],"tags":["go","netbird","udp-proxy","raw-socket","teardown","race"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}