IPBinarySet is a fast and memory-efficient data structure for storing and querying IP address ranges
Find a file
2026-01-05 17:22:42 -08:00
.gitignore initial commit 2026-01-05 16:18:44 -08:00
example_test.go update README.md with nice example 2026-01-05 17:22:42 -08:00
go.mod initial commit 2026-01-05 16:18:44 -08:00
ipbinaryset.go text and json (un)marshalling 2026-01-05 17:22:34 -08:00
ipbinaryset_test.go text and json (un)marshalling 2026-01-05 17:22:34 -08:00
ipv4range.go initial commit 2026-01-05 16:18:44 -08:00
ipv4range_test.go text and json (un)marshalling 2026-01-05 17:22:34 -08:00
ipv6range.go text and json (un)marshalling 2026-01-05 17:22:34 -08:00
ipv6range_test.go you wouldn't test a library (working) 2026-01-05 16:49:25 -08:00
LICENSE initial commit 2026-01-05 16:18:44 -08:00
README.md update README.md with nice example 2026-01-05 17:22:42 -08:00
uint128.go you wouldn't test a library (working) 2026-01-05 16:49:25 -08:00
uint128_test.go initial commit 2026-01-05 16:18:44 -08:00

ipbinaryset

IPBinarySet is a fast and memory-efficient data structure for storing and querying IP address ranges. It maintains a sorted, merged list of IPv4 and IPv6 CIDR prefixes, making it ideal for IP blocklists, allowlists, and other IP filtering applications.

The set uses binary search for O(log n) lookup performance and automatically merges overlapping or contained ranges to minimize memory usage and maintain optimal query speed. IPv4 and IPv6 addresses are stored separately in their respective (mostly optimized) formats.

Installation

go get git.vixen.computer/lua/ipbinaryset

Functions

  • New() - Create a new empty set
  • AddAddr(addr) - Add a single IP address
  • AddPrefix(prefix) - Add a CIDR prefix
  • ContainsAddr(addr) - Check if an IP is in the set
  • ContainsPrefix(prefix) - Check if a prefix is fully contained
  • Remove(prefix) - Remove a prefix from the set
  • All() - Iterate over all prefixes
  • Len() - Get the number of prefixes
  • Copy() - Get a slice of all prefixes
  • String() - Get string representation of all prefixes
  • UnmarshalText(data) - Parse a newline-delimited list of prefixes
  • MarshalJSON() - Serialize the set as a JSON string array
  • UnmarshalJSON(data) - Deserialize the set from a JSON string array

Example

package main

import (
    "fmt"
    "net/netip"

    "git.vixen.computer/lua/ipbinaryset"
)

func main() {
    set := ipbinaryset.New()

    // Add IP ranges
    set.AddPrefix(netip.MustParsePrefix("192.168.0.0/16"))
    set.AddPrefix(netip.MustParsePrefix("10.0.0.0/8"))
    set.AddPrefix(netip.MustParsePrefix("2001:db8::/32"))

    // Add individual addresses
    set.AddAddr(netip.MustParseAddr("203.0.113.42"))

    // Check if an IP is in the set
    if set.ContainsAddr(netip.MustParseAddr("192.168.1.100")) {
        fmt.Println("IP is in blocklist")
    }

    // Iterate over all ranges
    for prefix := range set.All() {
        fmt.Println(prefix)
    }

    fmt.Printf("Total ranges: %d\n", set.Len())
}

License

Licensed under the MIT License.

Made with ❤ by Lua (foxgirl.dev).