Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/ ippy Public

Fast and flexible IPv4 pattern matching library for Go

License

Notifications You must be signed in to change notification settings

AzraelSec/ippy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

2 Commits

Repository files navigation

ippy

Go Version License

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.

Features

  • 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

Installation

go get github.com/azraelsec/ippy

Quick Start

package main
import (
 "fmt"
 "log"
 "github.com/azraelsec/ippy/pkg/ipexpr"
)
func main() {
 // Parse a pattern
 expr, err := ipexpr.Parse("192.168.1.*")
 if err != nil {
 log.Fatal(err)
 }
 // Test IP addresses
 ips := []string{"192.168.1.1", "192.168.1.255", "10.0.0.1"}
 for _, ip := range ips {
 matches, err := expr.Matches(ip)
 if err != nil {
 log.Printf("Error matching %s: %v", ip, err)
 continue
 }
 if matches {
 fmt.Printf("✓ %s matches the pattern\n", ip)
 } else {
 fmt.Printf("✗ %s does not match the pattern\n", ip)
 }
 }
}

Pattern Syntax

The pattern syntax supports flexible expressions for each octet of an IPv4 address:

Basic Patterns

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

Complex Patterns

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.1

API Reference

Functions

Parse(expr string) (*IPExpr, error)

Parses an IP pattern expression and returns an IPExpr instance.

expr, err := ipexpr.Parse("192.168.1.*")
if err != nil {
 // Handle parsing error
}

Parameters:

  • expr string: IPv4 pattern expression (e.g., "192.168.1.*")

Returns:

  • *IPExpr: Parsed expression ready for matching
  • error: Parsing error if the pattern is invalid

(ie IPExpr) Matches(ip string) (bool, error)

Tests whether an IP address matches the parsed pattern.

matches, err := expr.Matches("192.168.1.100")
if err != 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 pattern
  • error: Matching error if IP format is invalid

(ie IPExpr) Generate() iter.Seq2[int, ip.IPv4]

Generates all IP addresses that match the pattern using Go's iterator interface.

expr, _ := ipexpr.Parse("192.168.1.1-3")
for i, ip := range expr.Generate() {
 fmt.Printf("%d: %s\n", i, ip)
}
// Output:
// 0: 192.168.1.1
// 1: 192.168.1.2
// 2: 192.168.1.3

Returns:

  • iter.Seq2[int, ip.IPv4]: Iterator yielding index and IP address pairs

Command Line Tool

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 pattern

Installation via go install

go install github.com/azraelsec/ippy/cmd/ippy-validator@latest

Examples

Corporate Network Matching

// Match corporate network ranges
patterns := []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 := range patterns {
 expr, err := ipexpr.Parse(pattern)
 if err != nil {
 log.Printf("Invalid pattern %s: %v", pattern, err)
 continue
 }
 // Test against your IPs
 testIP := "172.20.1.50"
 if matches, _ := expr.Matches(testIP); matches {
 fmt.Printf("%s matches corporate network pattern: %s\n", testIP, pattern)
 break
 }
}

Load Balancer Health Check

// Define health check IP ranges
healthCheckPattern := "10.0.1.1-10,20-30,100"
expr, err := ipexpr.Parse(healthCheckPattern)
if err != nil {
 log.Fatal(err)
}
func isHealthCheckIP(clientIP string) bool {
 matches, err := expr.Matches(clientIP)
 if err != nil {
 log.Printf("Error checking health check IP %s: %v", clientIP, err)
 return false
 }
 return matches
}

Security Filtering

// Block suspicious IP ranges
suspiciousPatterns := []string{
 "0.0.0.0", // Invalid source
 "127.*.*.*", // Loopback
 "169.254.*.*", // Link-local
 "224-255.*.*.*", // Multicast and reserved
}
func isIPSuspicious(ip string) bool {
 for _, pattern := range suspiciousPatterns {
 expr, err := ipexpr.Parse(pattern)
 if err != nil {
 continue
 }
 if matches, _ := expr.Matches(ip); matches {
 return true
 }
 }
 return false
}

IP Range Generation

// Generate all IPs in a pattern
expr, err := ipexpr.Parse("192.168.1.1-5,10")
if err != nil {
 log.Fatal(err)
}
fmt.Println("Generated IPs:")
for i, ip := range expr.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.10

Performance

The 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

Architecture

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

Key Design Decisions

  • 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

License

This project is licensed under the MIT License - see the LICENSE file for details.


Built with ❤️ in Go

About

Fast and flexible IPv4 pattern matching library for Go

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

AltStyle によって変換されたページ (->オリジナル) /