lazydns

IP Matching Rules Guide

Overview

The IP Set plugin in lazydns supports IP address and CIDR network matching for IP-based filtering rules. This document describes the complete IP matching rule system.

Quick Start

Basic Examples

# Load an IP list file
- name: ip_set
  tag: whitelist
  args:
    files:
      - whitelist-ips.txt

# With auto-reload for dynamic updates
- name: ip_set
  tag: blacklist
  args:
    files:
      - blacklist-ips.txt
    auto_reload: true

Rule Formats in Files

# Comments start with #
# This is a comment

# Single IPv4 address
192.168.1.1

# IPv4 CIDR network
192.168.0.0/16
10.0.0.0/8
172.16.0.0/12

# Single IPv6 address
2001:db8::1

# IPv6 CIDR network
2001:db8::/32
fe80::/10

# Empty lines are ignored

IP Address Formats

Single IPv4 Addresses

192.168.1.1          # Single host
8.8.8.8              # Google Public DNS
1.1.1.1              # Cloudflare DNS
127.0.0.1            # Localhost

Single addresses are automatically converted to /32 CIDR notation for internal matching.

IPv4 CIDR Networks

192.168.0.0/16       # Class B private network (65,536 hosts)
10.0.0.0/8           # Class A private network (16,777,216 hosts)
172.16.0.0/12        # Class B private network (1,048,576 hosts)
8.8.8.0/24           # Subnet with 256 hosts
192.168.1.128/25     # Subnet with 128 hosts

Single IPv6 Addresses

2001:db8::1          # Single host
::1                  # Localhost
fe80::1              # Link-local address

Single addresses are automatically converted to /128 CIDR notation for internal matching.

IPv6 CIDR Networks

2001:db8::/32        # Typical allocation (2^96 addresses)
fe80::/10            # Link-local addresses
ff00::/8             # Multicast addresses
::/0                 # Entire IPv6 address space (rarely used)
2001:db8:1234::/48   # Subnet allocation

Configuration Examples

Basic Configuration

- name: ip_set
  tag: whitelist
  args:
    files:
      - whitelist-ips.txt

Loads all IP addresses and CIDR ranges from the file.

Multiple Files

- name: ip_set
  tag: combined
  args:
    files:
      - trusted-networks.txt
      - partner-ips.txt
      - cdn-networks.txt
    auto_reload: true

Combines rules from multiple files with automatic reloading.

Inline IP Addresses (ips Parameter)

You can specify IP rules inline using the ips parameter instead of external files:

Single IP (string format):

- name: ip_set
  tag: local
  args:
    ips: "192.168.1.0/24"

Multiple IPs (array format):

- name: ip_set
  tag: trusted
  args:
    ips:
      - "192.168.1.0/24"
      - "10.0.0.0/8"
      - "2001:db8::/32"
      - "127.0.0.1"

Mixed files and inline addresses:

- name: ip_set
  tag: comprehensive
  args:
    files:
      - network-ranges.txt
    ips:
      - "192.168.0.0/16"
      - "10.0.0.0/8"
      - "172.16.0.0/12"
    auto_reload: true

The ips parameter supports:

# Private networks
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16

# Link-local and loopback
127.0.0.1
::1

# Data center and cloud providers
13.107.0.0/16        # Microsoft
34.64.0.0/10         # Google Cloud
18.0.0.0/7           # AWS

# Specific services
8.8.8.8              # Google DNS
1.1.1.1              # Cloudflare DNS
8.8.4.4              # Google DNS secondary

# IPv6 examples
2001:4860:4860::8888 # Google Public DNS
2606:4700:4700::1111 # Cloudflare DNS
fe80::/10            # Link-local

Matching Behavior

Exact Network Matching

IP addresses are matched against CIDR networks using network containment logic:

Rule: 192.168.0.0/24

192.168.0.0      → ✓ Match (network address)
192.168.0.1      → ✓ Match
192.168.0.128    → ✓ Match
192.168.0.255    → ✓ Match (broadcast address)
192.168.1.0      → ✗ No match (different network)
192.167.255.255  → ✗ No match

Rule: 10.0.0.0/8 (16,777,216 addresses)

10.0.0.0         → ✓ Match
10.1.2.3         → ✓ Match
10.255.255.255   → ✓ Match
11.0.0.0         → ✗ No match

Single Address Rules

Single addresses are treated as /32 (IPv4) or /128 (IPv6) networks:

Rule: 192.168.1.100 (stored internally as 192.168.1.100/32)

192.168.1.100    → ✓ Match (exact)
192.168.1.101    → ✗ No match
192.168.1.99     → ✗ No match

IPv4 and IPv6 Coexistence

Both IPv4 and IPv6 rules can coexist in the same IP Set:

- name: ip_set
  tag: dual_stack
  args:
    files:
      - dual-stack-networks.txt

File contents:

# IPv4 private ranges
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16

# IPv6 private ranges
fd00::/7
fe80::/10

# Single addresses
8.8.8.8
2001:4860:4860::8888

The plugin automatically detects and handles both address families.

Performance Characteristics

Time Complexity

Network lookup: O(n)
Where n = number of CIDR rules

Matching algorithm: Linear scan of all networks
No optimization for sorted/indexed lookups

Typical query times:

Space Complexity

IPv4 networks: ~12 bytes each
IPv6 networks: ~20 bytes each
Single IPs stored as /32 or /128

Memory per 10,000 networks:

Best Practices

Design Considerations

  1. Use CIDR notation for ranges instead of listing individual IPs ```yaml

    Good: efficient

    • name: ip_set args: ips: - “192.168.0.0/24”

    Bad: wasteful

    • name: ip_set args: ips: - “192.168.0.1” - “192.168.0.2” - “192.168.0.3” # … 250+ more entries ```
  2. Organize by scope: public, private, datacenter, CDN ```yaml
    • name: ip_set tag: private args: ips: - “10.0.0.0/8” - “172.16.0.0/12” - “192.168.0.0/16”

    • name: ip_set tag: public_cdn args: ips: - “8.8.8.0/24” - “1.1.1.0/24” ```

  3. Use files for large lists (>1000 entries) ```yaml
    • name: ip_set tag: large_list args: files: - cdn-ip-ranges.txt auto_reload: true ```
  4. Inline for small, frequently changed rules ```yaml
    • name: ip_set tag: exceptions args: ips: - “203.0.113.45” # Current exception ```

Documentation

# Example file structure
trusted-networks.txt:
  - 10.0.0.0/8          # Internal corporate
  - 192.168.0.0/16      # Office locations

partner-ips.txt:
  - 203.0.113.0/24      # Partner A
  - 198.51.100.0/24     # Partner B

Troubleshooting

IP Not Matching

Problem: Expected IP to match but it doesn’t

Common causes:

  1. IP notation error (missing CIDR prefix) ```yaml

    Wrong: missing /32

    ips:

    • “192.168.1.100” # Actually works - auto-converted to /32

    Correct: explicit CIDR

    ips:

    • “192.168.1.100/32” ```
  2. Wrong address family ```yaml

    IPv4 rule won’t match IPv6

    ips:

    • “192.168.1.0/24” # Only matches IPv4

    Need both for dual-stack

    ips:

    • “192.168.1.0/24”
    • “2001:db8::/32” ```
  3. Network contains check is exclusive of wrong boundaries
    • 10.0.0.0/24 matches 10.0.0.1 through 10.0.0.254
    • Broadcast address 10.0.0.255 is technically in the network but not always matched depending on kernel

File Load Errors

Problem: Rules not loading from file

Check:

  1. File path is correct and readable
  2. File contains valid IP addresses or CIDR notation
  3. Enable debug logging to see parsing errors
  4. Invalid entries are skipped with debug log messages

Performance Issues

Problem: DNS queries are slow with IP Set plugin

Solutions:

  1. Reduce number of rules (1000+ rules → ~100µs per query)
  2. Use CIDR notation instead of individual IPs
  3. Order most-frequently-matched rules first (hint: no optimization exists currently)
  4. Consider splitting into multiple IP Sets by category

API Reference

Plugin Configuration

- name: ip_set
  tag: <unique-identifier>
  args:
    files:                    # Optional: list of files to load
      - path/to/file1.txt
      - path/to/file2.txt
    ips:                      # Optional: inline IP addresses/networks
      - "192.168.0.0/24"
      - "10.0.0.0/8"
      - "127.0.0.1"
      - "::1"
    auto_reload: true         # Optional: auto-reload files (default: false)
    # auto_reload interval: ~200ms (not configurable)

Parameters

Parameter Type Required Default Description
tag string Yes - Unique plugin identifier
files array No empty File paths containing IP rules
ips array/string No empty Inline IP addresses or networks
auto_reload bool No false Auto-reload files on change

Return Value

All IP Set plugin operations return a boolean:

true   → IP is in the matched set
false  → IP is not in the set

Examples

Whitelist Model

Allow only specific networks:

- name: ip_set
  tag: whitelist
  args:
    ips:
      - "10.0.0.0/8"           # Internal
      - "203.0.113.0/24"       # Partner

Blacklist Model

Deny specific networks:

- name: ip_set
  tag: blacklist
  args:
    files:
      - blocked-ranges.txt
    ips:
      - "192.0.2.0/24"         # Malicious actor

CDN Detection

Match against CDN provider networks:

- name: ip_set
  tag: cdn_networks
  args:
    files:
      - cdn-ip-ranges.txt      # Updated regularly
    auto_reload: true

Geolocation-based Filtering

Combined with other plugins to filter by region (basic approach):

- name: ip_set
  tag: china_ips
  args:
    files:
      - china-ip-ranges.txt
    auto_reload: true

Multi-region Whitelist

Allow traffic from specific regions only:

- name: ip_set
  tag: allowed_regions
  args:
    ips:
      - "198.51.100.0/24"      # US region
      - "203.0.113.0/24"       # EU region
      - "192.0.2.0/24"         # APAC region