{"record":{"id":"8da7ae604418ff83","repo":"netbirdio/netbird","slug":"add-ip-to-ipset-s-w","errorCode":null,"errorMessage":"add IP to ipset %s: %w","messagePattern":"add IP to ipset (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/firewall/iptables/acl_linux.go","lineNumber":573,"sourceCode":"\n\tlog.Debugf(\"created ipset %s with type hash:net\", name)\n\treturn nil\n}\n\nfunc (m *aclManager) addToIPSet(name string, ip net.IP) error {\n\tcidr := uint8(32)\n\tif ip.To4() == nil {\n\t\tcidr = 128\n\t}\n\n\tentry := &ipset.Entry{\n\t\tIP:      ip,\n\t\tCIDR:    cidr,\n\t\tReplace: true,\n\t}\n\n\tif err := ipset.Add(name, entry); err != nil {\n\t\treturn fmt.Errorf(\"add IP to ipset %s: %w\", name, err)\n\t}\n\n\treturn nil\n}\n\nfunc (m *aclManager) delFromIPSet(name string, ip net.IP) error {\n\tcidr := uint8(32)\n\tif ip.To4() == nil {\n\t\tcidr = 128\n\t}\n\n\tentry := &ipset.Entry{\n\t\tIP:   ip,\n\t\tCIDR: cidr,\n\t}\n\n\tif err := ipset.Del(name, entry); err != nil {\n\t\treturn fmt.Errorf(\"delete IP from ipset %s: %w\", name, err)","sourceCodeStart":555,"sourceCodeEnd":591,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/firewall/iptables/acl_linux.go#L555-L591","documentation":"The addToIPSet helper builds an ipset Entry with the IP, CIDR 32 (v4) or 128 (v6), and Replace:true, then ipset.Add fails at netlink level. Replace makes duplicate elements safe, so realistic failures are: the named set does not exist in the kernel, the entry's family does not match the set's family, or insufficient privileges. Wrapped by callers as 'add IP to ipset: add IP to ipset <name>: ...'.","triggerScenarios":"Calling Add after the set was destroyed externally; calling the v6 manager's add path with a v4 net.IP (To4() != nil selects CIDR 32 inside an inet6 set); unprivileged process; seccomp blocking netlink ADD ops.","commonSituations":"External ipset janitors; dual-stack rule application routing families to the wrong manager instance; container security profiles.","solutions":["Ensure the set exists immediately before Add (the manager's flush-probe pattern), recreating on ErrSetNotExist.","Validate ip.To4() nil-ness against the manager's v6 flag and reject/skip mismatched families at the API boundary.","Run with CAP_NET_ADMIN.","Remove external ipset mutation from the host."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// family must match before Add: v4 -> CIDR 32 set, v6 -> CIDR 128 set\nisV4 := ip.To4() != nil\nif isV4 == mgrIsV6 {\n    return errors.New(\"IP family mismatch: refuse add to avoid netlink EINVAL\")\n}","typeGuard":null,"tryCatchPattern":"if err := addPeerRule(); err != nil {\n    if strings.Contains(err.Error(), \"add IP to ipset\") {\n        if errors.Is(err, ipset.ErrSetNotExist) {\n            // set vanished: recreate then retry the add once\n        }\n        if errors.Is(err, unix.EPERM) {\n            // privilege problem: escalate to deployment fix, do not retry\n        }\n    }\n}","preventionTips":["Validate IP family against the manager family at the API boundary before any ipset call.","Run the agent privileged so netlink ADD succeeds.","Prevent external destroy/flush of NETBIRD sets between create and add.","Add integration tests covering v4-in-v6-manager misuse to catch routing bugs early."],"tags":["go","linux","ipset","netlink","firewall","permissions","netbird"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}