package job import ( "net/netip" "strings" ) // An address that matches is neither counted towards a client's IP limit nor // banned: counting it would still cut the shared network it protects (#5378). type ipLimitAllowlist struct { prefixes []netip.Prefix addrs []netip.Addr } // Comma-separated, each entry a CIDR or a bare address. Unparseable entries are // skipped: the validator uses these same rules, so only a hand-edited DB differs. func parseIpLimitAllowlist(raw string) ipLimitAllowlist { var list ipLimitAllowlist for _, field := range strings.Split(raw, ",") { field = strings.TrimSpace(field) if field == "" { continue } if prefix, err := netip.ParsePrefix(field); err == nil { // Unmapped: contains() unmaps the queried address, and Prefix.Contains // is false whenever the bit lengths disagree. if addr := prefix.Addr(); addr.Is4In6() { if p4, perr := addr.Unmap().Prefix(prefix.Bits() - 96); perr == nil { prefix = p4 } } list.prefixes = append(list.prefixes, prefix.Masked()) continue } if addr, err := netip.ParseAddr(field); err == nil { list.addrs = append(list.addrs, addr.Unmap()) } } return list } func (l ipLimitAllowlist) empty() bool { return len(l.prefixes) == 0 && len(l.addrs) == 0 } func (l ipLimitAllowlist) contains(ip string) bool { if l.empty() { return false } addr, err := netip.ParseAddr(strings.TrimSpace(ip)) if err != nil { return false } addr = addr.Unmap() for _, allowed := range l.addrs { if allowed == addr { return true } } for _, prefix := range l.prefixes { if prefix.Contains(addr) { return true } } return false } // split separates the entries an allowlist protects from the ones the limit // still applies to, preserving the caller's ordering in both. func (l ipLimitAllowlist) split(entries []IPWithTimestamp) (limited, allowed []IPWithTimestamp) { if l.empty() { return entries, nil } limited = make([]IPWithTimestamp, 0, len(entries)) for _, entry := range entries { if l.contains(entry.IP) { allowed = append(allowed, entry) continue } limited = append(limited, entry) } return limited, allowed }