{"record":{"id":"f0d57b32ce816586","repo":"netbirdio/netbird","slug":"write-to-raw-conn-w","errorCode":null,"errorMessage":"write to raw conn: %w","messagePattern":"write to raw conn: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/iface/wgproxy/udp/rawsocket.go","lineNumber":96,"sourceCode":"\treturn f.rawSocket.Close()\n}\n\nfunc (f *SrcFaker) SendPkg(data []byte) (int, error) {\n\tdefer func() {\n\t\tif err := f.layerBuffer.Clear(); err != nil {\n\t\t\tlog.Errorf(\"failed to clear layer buffer: %s\", err)\n\t\t}\n\t}()\n\n\tpayload := gopacket.Payload(data)\n\n\terr := gopacket.SerializeLayers(f.layerBuffer, serializeOpts, f.ipH, f.udpH, payload)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"serialize layers: %w\", err)\n\t}\n\tn, err := f.rawSocket.WriteTo(f.layerBuffer.Bytes(), f.localHostAddr)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"write to raw conn: %w\", err)\n\t}\n\treturn n, nil\n}\n\nfunc prepareHeaders(dstPort int, srcAddr *net.UDPAddr) (gopacket.SerializableLayer, gopacket.SerializableLayer, error) {\n\tvar ipH gopacket.SerializableLayer\n\tvar networkLayer gopacket.NetworkLayer\n\n\t// Check if source IP is IPv4 or IPv6\n\tif srcAddr.IP.To4() != nil {\n\t\t// IPv4\n\t\tipv4 := &layers.IPv4{\n\t\t\tDstIP:    localHostNetIPAddrV4.IP,\n\t\t\tSrcIP:    srcAddr.IP,\n\t\t\tVersion:  4,\n\t\t\tTTL:      64,\n\t\t\tProtocol: layers.IPProtocolUDP,\n\t\t}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/iface/wgproxy/udp/rawsocket.go#L78-L114","documentation":"Returned by SrcFaker.SendPkg when rawSocket.WriteTo to 127.0.0.1 (v4 faker) or ::1 (v6 faker) fails. The raw socket is bound to lo with SO_MARK and header-include; a sendto on it can still fail with ENETUNREACH/EAFNOSUPPORT when the loopback family is disabled on the host, EBADF when the socket was closed concurrently, or EPERM from security modules. The v6 path is the fragile one: choosing the IPv6 faker (source address not v4-mapped) on a host with `net.ipv6.conf.all.disable_ipv6=1` makes ::1 unreachable.","triggerScenarios":"IPv6 faker selected (peer endpoint is v6) while IPv6 is disabled kernel-side; SrcFaker closed by Work()/RedirectAs() while proxyToLocal is still inside SendPkg (the pausedCond lock narrows but does not eliminate this); SELinux/AppArmor denying raw sends.","commonSituations":"Hosts hardened with ipv6.disable=1 or disable_ipv6 sysctls peering over v6 management/relays; rapid direct<->relay redirects during ICE negotiation. The proxyToLocal loop logs it at debug and continues, so throughput degrades rather than dies.","solutions":["Verify loopback for the family in use: `ping -c1 127.0.0.1` and `ping -c1 ::1`; if ::1 fails, enable IPv6 (`sysctl -w net.ipv6.conf.all.disable_ipv6=0`) or peer over v4 endpoints","If errors cluster right after redirect changes, treat as the known swap race - upgrading the agent usually reduces it","Check dmesg/audit for SELinux denials on the netbird process sending raw packets"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before creating a v6 SrcFaker, confirm v6 loopback is usable\nfunc ipv6LoopbackAvailable() bool {\n    c, err := net.Dial(\"udp6\", \"[::1]:9\"): // discard port\n    if err != nil {\n        return false\n    }\n    _ = c.Close()\n    return true\n}","typeGuard":"func isUsableSrcAddr(a *net.UDPAddr) bool {\n    if a.IP.To4() != nil {\n        return true\n    }\n    return ipv6LoopbackAvailable()\n}","tryCatchPattern":"if _, err := f.rawSocket.WriteTo(b, f.localHostAddr); err != nil {\n    if errors.Is(err, syscall.ENETUNREACH) || errors.Is(err, syscall.EAFNOSUPPORT) {\n        log.Debugf(\"family loopback unavailable, dropping faked packet: %v\", err)\n        return 0, nil // degrade, do not kill the proxy loop\n    }\n    return 0, fmt.Errorf(\"write to raw conn: %w\", err)\n}","preventionTips":["Enable IPv6 loopback (`net.ipv6.conf.all.disable_ipv6=0`) when peering over v6 endpoints","Prefer v4 relay/direct endpoints on hosts where IPv6 is administratively disabled","Treat single write failures during redirect swaps as transient; only act on persistent failure"],"tags":["go","netbird","raw-socket","ipv6","loopback","udp-proxy"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}