{"record":{"id":"a158e142529d4b56","repo":"netbirdio/netbird","slug":"add-peer-filtering-for-s-w","errorCode":null,"errorMessage":"add peer filtering for %s: %w","messagePattern":"add peer filtering for (.+?): %w","errorType":"exception","errorClass":"firewall.ErrIPv6NotInitialized","httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/manager_linux.go","lineNumber":198,"sourceCode":"//\n// Comment will be ignored because some system this feature is not supported\nfunc (m *Manager) AddPeerFiltering(\n\tid []byte,\n\tip net.IP,\n\tproto firewall.Protocol,\n\tsPort *firewall.Port,\n\tdPort *firewall.Port,\n\taction firewall.Action,\n\tipsetName string,\n) ([]firewall.Rule, error) {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif ip.To4() != nil {\n\t\treturn m.aclMgr.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)\n\t}\n\tif !m.hasIPv6() {\n\t\treturn nil, fmt.Errorf(\"add peer filtering for %s: %w\", ip, firewall.ErrIPv6NotInitialized)\n\t}\n\treturn m.aclMgr6.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)\n}\n\nfunc (m *Manager) AddRouteFiltering(\n\tid []byte,\n\tsources []netip.Prefix,\n\tdestination firewall.Network,\n\tproto firewall.Protocol,\n\tsPort, dPort *firewall.Port,\n\taction firewall.Action,\n) (firewall.Rule, error) {\n\tm.mutex.Lock()\n\tdefer m.mutex.Unlock()\n\n\tif isIPv6RouteRule(sources, destination) {\n\t\tif !m.hasIPv6() {\n\t\t\treturn nil, fmt.Errorf(\"add route filtering: %w\", firewall.ErrIPv6NotInitialized)","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/manager_linux.go#L180-L216","documentation":"AddPeerFiltering was called with an IPv6 peer IP (ip.To4() == nil) while the manager has no v6 half: m.ipv6Client is nil because wgIface.Address().HasIPv6() was false when Create ran. It wraps the sentinel firewall.ErrIPv6NotInitialized (client/firewall/manager/firewall.go:17), so the mismatch is programmatically detectable with errors.Is. The check fails fast rather than silently installing a v6 address into the v4 chain or ipset.","triggerScenarios":"Passing a 16-byte net.IP (a v6 peer address from the network map) to AddPeerFiltering on a manager constructed while the local overlay address had no IPv6 part.","commonSituations":"Management network has an IPv6 range so peers carry v6 addresses, but this peer was assigned a v4-only address; the peer connected before v6 was enabled and was not restarted; the kernel or interface had no v6 at startup so the WgAddr lacks the v6 component.","solutions":["Give the peer an IPv6 address (enable the v6 range in the management network) and restart/reconnect so Create builds the v6 half","If v6 is unsupported locally, stop distributing v6 ACLs/routes to this peer from management","In custom callers, skip v6 peers when the interface has no v6 - the engine already does this at client/internal/engine.go:1842"],"exampleFix":"// before\nrules, err := mgr.AddPeerFiltering(id, peerIP, proto, sPort, dPort, action, ipset)\nif err != nil {\n\treturn err // v6 peer on v4-only manager aborts the whole ACL apply\n}\n\n// after\nif peerIP.To4() == nil && !wgIface.Address().HasIPv6() {\n\tlog.Debugf(\"skipping v6 peer %s: no v6 overlay\", peerIP)\n\tcontinue\n}\nrules, err := mgr.AddPeerFiltering(id, peerIP, proto, sPort, dPort, action, ipset)","handlingStrategy":"validation","validationCode":"// skip v6 peer rules before touching the firewall manager\nfunc canFilterPeer(mgrFacingV6 bool, peerIP net.IP) bool {\n    if peerIP.To4() != nil {\n        return true\n    }\n    return mgrFacingV6 // mgrFacingV6 == wgIface.Address().HasIPv6() at Create time\n}","typeGuard":"func isFilterableIP(ip net.IP, ifaceHasV6 bool) bool {\n    return ip.To4() != nil || ifaceHasV6\n}","tryCatchPattern":"rules, err := mgr.AddPeerFiltering(id, ip, proto, sPort, dPort, action, ipsetName)\nif err != nil {\n    if errors.Is(err, firewall.ErrIPv6NotInitialized) {\n        log.Debugf(\"skipping v6 peer %s: no v6 firewall\", ip)\n        continue\n    }\n    return err\n}","preventionTips":["Gate every v6 submission on wgIface.Address().HasIPv6(), the same check Create uses","Match the sentinel with errors.Is rather than string-matching the message","Keep management-side v6 ACL distribution scoped to peers that actually hold v6 addresses"],"tags":["iptables","ipv6","firewall","acl","netbird","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}