ippy is a fast and flexible IPv4 pattern matching library for Go. It allows you to define complex IP address patterns using a simple expression syntax and efficiently match IPv4 addresses against those patterns.
- Flexible Pattern Syntax: Support for ranges, wildcards, and comma-separated values in IP expressions
- High Performance: Uses bit vectors for efficient pattern matching with O(1) lookup time
- Simple API: Easy-to-use interface with parse-once, match-many semantics
- IP Generation: Generate all IPs that match a given pattern with iterator support
- Zero Dependencies: Pure Go implementation with no external dependencies
- Comprehensive Testing: Well-tested with extensive unit tests
- Command Line Tool: Includes a validator tool for testing patterns
go get github.com/azraelsec/ippypackage main
import (
"fmt""log""github.com/azraelsec/ippy/pkg/ipexpr"
)
funcmain() {
// Parse a patternexpr, err:=ipexpr.Parse("192.168.1.*")
iferr!=nil {
log.Fatal(err)
}
// Test IP addressesips:= []string{"192.168.1.1", "192.168.1.255", "10.0.0.1"}
for_, ip:=rangeips {
matches, err:=expr.Matches(ip)
iferr!=nil {
log.Printf("Error matching %s: %v", ip, err)
continue
}
ifmatches {
fmt.Printf("✓ %s matches the pattern\n", ip)
} else {
fmt.Printf("✗ %s does not match the pattern\n", ip)
}
}
}The pattern syntax supports flexible expressions for each octet of an IPv4 address:
| Pattern | Description | Example Matches |
|---|---|---|
* | Matches any value (0-255) | 192.168.1.* matches 192.168.1.1, 192.168.1.255 |
123 | Matches exact value | 192.168.1.123 matches only 192.168.1.123 |
1-10 | Matches range (inclusive) | 192.168.1.1-10 matches 192.168.1.1 through 192.168.1.10 |
1,3,5 | Matches multiple values | 192.168.1.1,3,5 matches 192.168.1.1, 192.168.1.3, 192.168.1.5 |
You can combine different pattern types within a single octet:
// Mixed patterns"192.168.1.1,10-20,100,200-255"// Matches 1, 10-20, 100, and 200-255"10.0-50.*.1-254"// Matches 10.0-50.anything.1-254"172.16,20.0.1"// Matches 172.16.0.1 and 172.20.0.1Parses an IP pattern expression and returns an IPExpr instance.
expr, err:=ipexpr.Parse("192.168.1.*")
iferr!=nil {
// Handle parsing error
}Parameters:
expr string: IPv4 pattern expression (e.g., "192.168.1.*")
Returns:
*IPExpr: Parsed expression ready for matchingerror: Parsing error if the pattern is invalid
Tests whether an IP address matches the parsed pattern.
matches, err:=expr.Matches("192.168.1.100")
iferr!=nil {
// Handle matching error (invalid IP format, etc.)
}Parameters:
ip string: IPv4 address to test (e.g., "192.168.1.1")
Returns:
bool: Whether the IP matches the patternerror: Matching error if IP format is invalid
Generates all IP addresses that match the pattern using Go's iterator interface.
expr, _:=ipexpr.Parse("192.168.1.1-3")
fori, ip:=rangeexpr.Generate() {
fmt.Printf("%d: %s\n", i, ip)
}
// Output:// 0: 192.168.1.1// 1: 192.168.1.2// 2: 192.168.1.3Returns:
iter.Seq2[int, ip.IPv4]: Iterator yielding index and IP address pairs
The library includes a command-line validator tool:
# Build the tool
go build -o ippy-validator ./cmd/ippy-validator
# Test if an IP matches a pattern
./ippy-validator -pattern "192.168.1.*" -ip "192.168.1.100"# Output: ip matches the given pattern
./ippy-validator -pattern "192.168.1.*" -ip "10.0.0.1"# Output: ip does not match the given patterngo install github.com/azraelsec/ippy/cmd/ippy-validator@latest// Match corporate network rangespatterns:= []string{
"10.*.*.*", // Private Class A"172.16-31.*.*", // Private Class B"192.168.*.*", // Private Class C"203.0.113.1-100", // Specific public range
}
for_, pattern:=rangepatterns {
expr, err:=ipexpr.Parse(pattern)
iferr!=nil {
log.Printf("Invalid pattern %s: %v", pattern, err)
continue
}
// Test against your IPstestIP:="172.20.1.50"ifmatches, _:=expr.Matches(testIP); matches {
fmt.Printf("%s matches corporate network pattern: %s\n", testIP, pattern)
break
}
}// Define health check IP rangeshealthCheckPattern:="10.0.1.1-10,20-30,100"expr, err:=ipexpr.Parse(healthCheckPattern)
iferr!=nil {
log.Fatal(err)
}
funcisHealthCheckIP(clientIPstring) bool {
matches, err:=expr.Matches(clientIP)
iferr!=nil {
log.Printf("Error checking health check IP %s: %v", clientIP, err)
returnfalse
}
returnmatches
}// Block suspicious IP rangessuspiciousPatterns:= []string{
"0.0.0.0", // Invalid source"127.*.*.*", // Loopback"169.254.*.*", // Link-local"224-255.*.*.*", // Multicast and reserved
}
funcisIPSuspicious(ipstring) bool {
for_, pattern:=rangesuspiciousPatterns {
expr, err:=ipexpr.Parse(pattern)
iferr!=nil {
continue
}
ifmatches, _:=expr.Matches(ip); matches {
returntrue
}
}
returnfalse
}// Generate all IPs in a patternexpr, err:=ipexpr.Parse("192.168.1.1-5,10")
iferr!=nil {
log.Fatal(err)
}
fmt.Println("Generated IPs:")
fori, ip:=rangeexpr.Generate() {
fmt.Printf("%d: %s\n", i, ip)
}
// Output:// 0: 192.168.1.1// 1: 192.168.1.2// 2: 192.168.1.3// 3: 192.168.1.4// 4: 192.168.1.5// 5: 192.168.1.10The library uses bit vectors for efficient pattern matching, providing:
- O(1) time complexity for matching operations
- O(n) preprocessing time for pattern compilation where n is the number of intervals
- Constant memory usage per octet (256 bits = 32 bytes)
- Efficient generation with iterator-based IP enumeration
The library consists of several internal components:
- Lexer: Tokenizes IP pattern expressions into tokens (numbers, ranges, wildcards, commas)
- Parser: Parses tokens into interval structures representing valid ranges
- Bit Vector: Uses 256-bit vectors (32 bytes) per octet for O(1) membership testing
- IP Parser: Validates and parses IPv4 addresses into octets
- IPExpr: High-level API that orchestrates the components and provides matching/generation
- Bit Vectors over BST: Replaced binary search trees with bit vectors for constant-time lookups
- Iterator-based Generation: Uses Go 1.23+ iterators for memory-efficient IP generation
- Parse-once Semantics: Patterns are parsed once and can be reused for multiple matches
- Zero Dependencies: Pure Go implementation using only standard library
This project is licensed under the MIT License - see the LICENSE file for details.
Built with ❤️ in Go