{"record":{"id":"71a62e41bd80ed91","repo":"netbirdio/netbird","slug":"add-inbound-dnat-w","errorCode":null,"errorMessage":"add inbound DNAT: %w","messagePattern":"add inbound DNAT: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/manager_linux.go","lineNumber":472,"sourceCode":"\t}\n\n\tif m.hasIPv6() && len(v6Prefixes) > 0 {\n\t\tif err := m.router6.UpdateSet(set, v6Prefixes); err != nil {\n\t\t\treturn fmt.Errorf(\"update v6 set: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// AddInboundDNAT adds an inbound DNAT rule redirecting traffic from NetBird peers to local services.\nfunc (m *Manager) AddInboundDNAT(localAddr netip.Addr, protocol firewall.Protocol, originalPort, translatedPort uint16) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif localAddr.Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn fmt.Errorf(\"add inbound DNAT: %w\", firewall.ErrIPv6NotInitialized)\n\t\t}\n\t\treturn m.router6.AddInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n\t}\n\treturn m.router.AddInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n}\n\n// RemoveInboundDNAT removes an inbound DNAT rule.\nfunc (m *Manager) RemoveInboundDNAT(localAddr netip.Addr, protocol firewall.Protocol, originalPort, translatedPort uint16) error {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif localAddr.Is6() {\n\t\tif !m.hasIPv6() {\n\t\t\treturn fmt.Errorf(\"remove inbound DNAT: %w\", firewall.ErrIPv6NotInitialized)\n\t\t}\n\t\treturn m.router6.RemoveInboundDNAT(localAddr, protocol, originalPort, translatedPort)\n\t}\n\treturn m.router.RemoveInboundDNAT(localAddr, protocol, originalPort, translatedPort)","sourceCodeStart":454,"sourceCodeEnd":490,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/manager_linux.go#L454-L490","documentation":"AddInboundDNAT was asked to redirect traffic for a v6 local address (localAddr.Is6()) into the overlay, but the manager has no v6 half. Wraps the sentinel firewall.ErrIPv6NotInitialized - the inbound PREROUTING DNAT is refused rather than half-installed.","triggerScenarios":"Calling AddInboundDNAT with a v6 netip.Addr on a manager whose Create ran with a v4-only WgAddr.","commonSituations":"Exposing a local service over v6 (peer-to-service forwarding) on a peer without a v6 overlay address; service config listing :: addresses alongside v4.","solutions":["Assign the peer a v6 address and restart the agent","Filter v6 local addresses out of the inbound-DNAT setup when the interface lacks v6","Verify the overlay actually has v6: check the interface address, not just the config"],"exampleFix":"// before\nif err := mgr.AddInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n\treturn err\n}\n\n// after\nif localAddr.Is6() && !wgIface.Address().HasIPv6() {\n\tlog.Debugf(\"skipping v6 inbound DNAT: no v6 overlay\")\n\treturn nil\n}\nif err := mgr.AddInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n\treturn err\n}","handlingStrategy":"validation","validationCode":"if localAddr.Is6() && !wgIface.Address().HasIPv6() {\n    return nil // v6 inbound DNAT cannot be programmed\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.AddInboundDNAT(localAddr, proto, origPort, xlatePort); err != nil {\n    if errors.Is(err, firewall.ErrIPv6NotInitialized) {\n        log.Debugf(\"skipping v6 inbound DNAT: no v6 firewall\")\n        return nil\n    }\n    return err\n}","preventionTips":["Gate v6 local addresses on the interface's HasIPv6() accessor before adding inbound DNAT","Prefer netip.Addr (Is6()) over string parsing for family checks","Re-validate after interface address changes rather than caching the capability"],"tags":["iptables","ipv6","firewall","dnat","netbird","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}