Skip to main content

CIDR-aware IP anonymizer with prefix-preserving permutation

Project description

ipanon

A deterministic, CIDR-aware IP anonymizer for log sanitization. Replaces IPv4 and IPv6 addresses in text while maintaining CIDR prefix relationships and respecting reserved/private range boundaries.

Features

  • Prefix-preserving permutation — IPs sharing a /8 or larger subnet stay grouped after anonymization; subnet relationships are preserved at every prefix length
  • Three-tier classification — private ranges stay private, loopback/multicast pass through unchanged, public IPs get fully anonymized
  • Subnet-aware host-bit locking — preserves host bits within known subnets, preventing broadcast/network address collisions in router configs
  • Deterministic — same salt always produces the same output, enabling cross-log correlation
  • IPv4 + IPv6 — full support for both protocols including CIDR notation
  • Streaming — reads stdin, writes stdout; works in pipelines
  • No dependencies — pure Python, stdlib only

Installation

pip install ipanon

Or from source:

pip install .

Quick Start

# Anonymize a log file (auto-generated random salt printed to stderr)
cat access.log | ipanon > anonymized.log

# Reproducible anonymization with a fixed salt
ipanon --salt mysecret input.log output.log

# Save the IP mapping for later analysis
ipanon --salt mysecret -m mapping.json < input.log > output.log

How It Works

Every IP address is classified into one of three categories:

Category Behavior Examples
A — Range-preserved Prefix bits locked, remaining bits permuted. 10.x.y.z stays in 10.0.0.0/8, 172.16.x.y stays in 172.16.0.0/12, etc. 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10, 169.254.0.0/16, fc00::/7, fe80::/10
B — Pass-through Returned unchanged. 127.0.0.1, 0.0.0.0/8, 224.0.0.0/4, ::1, ff00::/8
C — Public First octet permuted within a safe pool, lower 24 bits prefix-preserving permuted. Two IPs in the same /8 map to the same anonymized /8. 8.8.8.8, 1.1.1.1, 2001:db8::1

Public IPs are guaranteed never to land in Category A or B address space after anonymization.

Mixed First-Octets

Six IPv4 first-octets (100, 169, 172, 192, 198, 203) contain both reserved sub-ranges and public IPs — for example, 172.16.0.0/12 is private but 172.217.x.x (Google) is public. Because these octets can't safely participate in the normal first-octet permutation pool, public IPs from mixed octets keep their first octet unchanged by default (with a warning).

To get collision-free anonymization for these IPs, use --remap to redirect them to a dedicated pure-public octet:

# Redirect public 172.x IPs to the 42.x range
ipanon --salt s --remap 172=42 < input.log

# Redirect multiple mixed octets
ipanon --salt s --remap 172=42 --remap 192=43 < input.log

Alternatively, use --ignore-subnets to remove the sub-/8 private ranges entirely, which eliminates the mixed-octet problem by treating those IPs as fully public:

# Only 10.0.0.0/8 stays private; 172.16.x, 192.168.x, etc. treated as public
ipanon --salt s --ignore-subnets < input.log

CLI Reference

ipanon [OPTIONS] [INPUT] [OUTPUT]
Option Description
-s, --salt SALT Reproducible anonymization salt (random if omitted, printed to stderr)
--salt-env ENVNAME Read salt from environment variable. Mutually exclusive with --salt
--remap MIXED=TARGET Redirect public IPs from a mixed first-octet to a dedicated pure-public target (see Mixed First-Octets). Can repeat
--pass-through CIDR Don't anonymize IPs matching CIDR prefix. /8 prefixes are excluded from the permutation pool (guaranteed collision-free); narrower prefixes use post-hoc detection. Can repeat
--allow-pt-collisions Downgrade pass-through collision errors to warnings
--ignore-subnets Treat sub-/8 IPv4 private ranges as public. Only 10.0.0.0/8 stays range-preserved; Cat B and IPv6 are unaffected
--ignore-reserved Remove ALL reserved range handling (Cat A and Cat B). Every IP — including loopback, multicast, private — gets fully anonymized. Affects both IPv4 and IPv6
--networks CIDRS Comma-separated CIDRs for subnet-aware host-bit locking (e.g., 10.0.0.0/8-24), or auto to collect from input. Preserves host bits within each subnet. Supports range notation and interface notation. Can combine with --network-file
--network-file FILE File with one CIDR per line for subnet-aware host-bit locking. Blank lines and # comments ignored. Can combine with --networks
-m, --mapping FILE Write JSON mapping of original-to-anonymized IPs to FILE. Includes network list when --networks/--network-file used
-v, --verbose Print stats to stderr. -vv also prints all mappings
-q, --quiet Suppress all warnings. Overrides -v/-vv

Examples

# Don't anonymize your monitoring subnet
ipanon --salt s --pass-through 10.0.0.0/8 < input.log

# Only keep 10.0.0.0/8 private; treat 172.16.x, 192.168.x, etc. as public
ipanon --salt s --ignore-subnets < input.log

# Treat ALL IPs as public (ignore private/reserved ranges entirely)
ipanon --salt s --ignore-reserved < input.log

# Salt from environment variable
export ANON_SALT="my-secret-salt"
ipanon --salt-env ANON_SALT < input.log

Subnet-Aware Host-Bit Locking

When anonymizing router configurations, the permutation can map valid host addresses onto broadcast or network addresses — which routers reject. The --networks flag prevents this by preserving host bits within known subnets:

# Plain CIDR: host bits within /29 are preserved
ipanon --salt s --networks 192.168.1.0/29 < router.conf

# Range notation: within the /8 block, preserve host bits at /24 boundary
# Bits 8-23 are permuted, bits 24-31 are preserved
ipanon --salt s --networks 10.0.0.0/8-24 < router.conf

# Networks file for multi-router consistency
cat > subnets.txt <<EOF
# Large blocks with /24 host boundary
10.0.0.0/8-24
172.16.0.0/12-24
# Specific small subnets
192.168.1.0/29
# IPv6
2001:db8::/32-64
EOF
ipanon --salt s --network-file subnets.txt rtrA.conf > rtrA.anon
ipanon --salt s --network-file subnets.txt rtrB.conf > rtrB.anon

# Auto-collect subnets from input (one-off convenience)
ipanon --salt s --networks auto < router.conf

Interface notation is accepted — 10.1.2.65/29 is interpreted as network 10.1.2.64/29.

The network list is part of the anonymization configuration alongside the salt. For reproducible multi-device anonymization, save both the salt and the networks file.

Use Cases

Log Sanitization

Anonymize IP addresses in log files before sharing with vendors or publishing:

# Nginx access logs
ipanon --salt "$SECRET" < /var/log/nginx/access.log > sanitized-access.log

# Batch-process multiple log files with the same salt for cross-log correlation
for f in /var/log/app/*.log; do
    ipanon --salt "$SECRET" "$f" "sanitized/$(basename "$f")"
done

# Pipe from journald
journalctl -u myservice --no-pager | ipanon --salt "$SECRET" > sanitized.log

# Apache combined log format — structure is preserved, only IPs change
# Before: 203.0.113.50 - - [10/Oct/2024:13:55:36 -0700] "GET /index.html HTTP/1.1" 200 2326
# After:  71.142.89.50 - - [10/Oct/2024:13:55:36 -0700] "GET /index.html HTTP/1.1" 200 2326

# Save the mapping so you can look up the original IP if needed
ipanon --salt "$SECRET" -m mapping.json < access.log > sanitized.log
cat mapping.json
# {"203.0.113.50": "71.142.89.50", "10.0.1.5": "10.218.94.5", ...}

Config File Sanitization

Scrub IP addresses from configuration files before committing or sharing:

# Sanitize firewall rules
ipanon --salt cfg < iptables-rules.txt > iptables-rules.sanitized.txt

# Sanitize network configs, keeping internal structure visible
# --pass-through keeps your well-known subnets readable
ipanon --salt cfg --pass-through 10.0.0.0/8 < network.conf > network.sanitized.conf

# Sanitize DNS zone files
ipanon --salt cfg < db.example.com > db.example.sanitized.com

# Sanitize Kubernetes manifests or Terraform state
ipanon --salt cfg < terraform.tfstate > terraform.sanitized.tfstate

# Sanitize Ansible inventories
ipanon --salt cfg < hosts.ini > hosts.sanitized.ini

Sharing Diagnostic Output

Clean up diagnostic output before pasting into bug reports or support tickets:

# Sanitize traceroute output
traceroute example.com | ipanon --salt diag

# Sanitize tcpdump captures (text output)
tcpdump -nn -r capture.pcap | ipanon --salt diag > sanitized-capture.txt

# Sanitize `ss` or `netstat` output
ss -tunap | ipanon --salt diag

# Sanitize `ip addr` output
ip addr show | ipanon --salt diag

CI/CD Pipelines

# Set salt once per pipeline run for consistent anonymization across steps
export ANON_SALT="$(openssl rand -hex 16)"

# Anonymize test artifacts before uploading
ipanon --salt-env ANON_SALT < test-output.log > sanitized-output.log
ipanon --salt-env ANON_SALT < network-diag.txt > sanitized-diag.txt

Python API

See API.md for complete API documentation.

from ipanon import Anonymizer, scan_and_replace

# Single IP anonymization
anon = Anonymizer(salt="mysecret")
anon.anonymize("8.8.8.8")        # → "143.57.192.12" (deterministic)
anon.anonymize("10.1.2.3")       # → "10.187.42.5" (stays in 10.0.0.0/8)
anon.anonymize("127.0.0.1")      # → "127.0.0.1" (pass-through)

# Bulk text replacement
text = "Server 8.8.8.8 connected to 10.0.1.5 via 192.168.1.1"
scan_and_replace(text, anon)
# → "Server 143.57.192.12 connected to 10.187.42.5 via 192.168.78.201"

Requirements

  • Python >= 3.9
  • No external dependencies

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ipanon-0.3.3.tar.gz (36.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ipanon-0.3.3-py3-none-any.whl (21.4 kB view details)

Uploaded Python 3

File details

Details for the file ipanon-0.3.3.tar.gz.

File metadata

  • Download URL: ipanon-0.3.3.tar.gz
  • Upload date:
  • Size: 36.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ipanon-0.3.3.tar.gz
Algorithm Hash digest
SHA256 886219983fcaea38f8284cd0b5848d520b53d6f368f8d443be16ad1ee364b6a4
MD5 38c2c635564f400b6c9632234bc0e40a
BLAKE2b-256 02b64084c89eb599eb68a704dff4428589d5e3480f9226a27cf82a5457e6d7c0

See more details on using hashes here.

Provenance

The following attestation bundles were made for ipanon-0.3.3.tar.gz:

Publisher: publish.yml on dg-i/ipanon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ipanon-0.3.3-py3-none-any.whl.

File metadata

  • Download URL: ipanon-0.3.3-py3-none-any.whl
  • Upload date:
  • Size: 21.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for ipanon-0.3.3-py3-none-any.whl
Algorithm Hash digest
SHA256 7c3fb5cbf324ec4e5777b93453277feb0161248807a8f1db453cb0d34989c45e
MD5 452951ce3ba0e931a38cac3873dea477
BLAKE2b-256 4ac9c883d2a8b577361688d4cb0aec3c5841c3907879d84e83e30a369b62b3f4

See more details on using hashes here.

Provenance

The following attestation bundles were made for ipanon-0.3.3-py3-none-any.whl:

Publisher: publish.yml on dg-i/ipanon

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page