Skip to main content

How IP Ranges Work

Caddy Defender includes a comprehensive database of IP ranges from various cloud providers, AI services, and other sources. These ranges are fetched at build time and embedded directly into the binary, ensuring fast lookups without external dependencies.

IPRanges Map Structure

All IP ranges are stored in a centralized IPRanges map located in ranges/data/generated.go. This file is automatically generated by the build process:
var IPRanges = map[string][]string{
    "openai": {
        "23.102.140.112/28",
        "40.83.2.64/28",
        // ... more ranges
    },
    "aws": {
        "3.5.140.0/22",
        "13.34.37.64/27",
        // ... thousands more ranges
    },
    // ... more providers
}

Map Key Reference

The map uses lowercase string keys to identify different IP range sources:

Cloud Providers

aws, gcloud, azure, oci, vultr, digitalocean, linode, cloudflare, aliyun

AI Services

openai, deepseek, githubcopilot, mistral

Special Ranges

private, all, vpn, tor (optional)

AWS Regions

aws-us-east-1, aws-us-west-1, and other regional variants

Build-Time Generation

IP ranges are fetched and embedded during the build process using the ranges/main.go tool:
# Generate IP ranges at build time
go run ranges/main.go -format go -output ranges/data/generated.go

Generation Process

  1. Concurrent Fetching: The tool fetches IP ranges from multiple sources simultaneously using goroutines
  2. Data Sources: Each fetcher connects to official APIs or endpoints (e.g., AWS IP ranges JSON, OpenAI bot endpoints)
  3. Map Population: Results are stored in the IPRanges map with lowercase keys
  4. Code Generation: The map is serialized to Go code using text templates
  5. Binary Embedding: The generated file is compiled into the final Caddy binary
The generated file contains a comment: // Code generated by pkg.jsn.cam/caddy-defender/blob/main/ranges/main.go; DO NOT EDIT.

Using IP Ranges in Configuration

In your Caddyfile, you can reference IP ranges by their map key:
defender block {
    ranges openai gcloud aws
}
You can also mix predefined ranges with custom CIDR blocks:
defender block {
    ranges openai 203.0.113.0/24 198.51.100.0/24
}

Validation

When Caddy Defender validates your configuration (see config.go:228-240):
  1. Check for Predefined Keys: If a range matches a key in IPRanges, it’s used directly
  2. Parse Custom CIDRs: If not found in the map, it’s validated as a CIDR notation
  3. Reject Invalid Values: Invalid CIDRs or unknown keys result in configuration errors
for _, ipRange := range m.Ranges {
    // Check if the range is a predefined key (e.g., "openai")
    if _, ok := data.IPRanges[ipRange]; ok {
        continue
    }
    
    // Otherwise, treat it as a custom CIDR and validate it
    _, _, err := net.ParseCIDR(ipRange)
    if err != nil {
        return fmt.Errorf("invalid IP range %q: %v", ipRange, err)
    }
}

Performance Benefits

Since IP ranges are embedded at build time, there’s no need to fetch data from external APIs during runtime. This eliminates:
  • Network latency
  • External API dependencies
  • Rate limiting concerns
  • Potential points of failure
The IPRanges map provides O(1) lookup time for predefined ranges, making IP matching extremely fast even with thousands of CIDR blocks.
Your Caddy server doesn’t need internet access or external API keys to use IP range blocking - everything is self-contained.

Updating IP Ranges

To update the IP ranges in your Caddy Defender build:
  1. Rebuild the ranges data:
    go run ranges/main.go
    
  2. Rebuild Caddy with the updated ranges:
    xcaddy build --with github.com/jasonlovesdoggo/caddy-defender
    
Consider automating this process in your CI/CD pipeline to keep IP ranges up-to-date.

Build docs developers (and LLMs) love