Skip to main content

Reliable WAN/LAN IP discovery and Cloudflare DNS synchronization

Project description

ip-reporter

ip-reporter is a dependency-free Python package and CLI for discovering local LAN addresses, public WAN addresses, and public addresses obtained through HTTP/2 or HTTP/3. It can synchronize one or many A/AAAA records in Cloudflare.

The import name is ip_reporter; the installed command is ip-reporter.

Install with uv

Install the command as a uv tool:

uv tool install ip-reporter
ip-reporter --scope wan --family ipv4

Use it as a library dependency:

uv add ip-reporter

For HTTP/2 and HTTP/3 probing on macOS, install Homebrew curl. The package rejects /usr/bin/curl on macOS so the system curl cannot silently disable those probes.

brew install curl
export IP_REPORTER_CURL="$(brew --prefix curl)/bin/curl"

The selected curl must report HTTP2 or HTTP3 in curl --version depending on the requested probe. HTTP/3 requires a curl build with HTTP/3 support.

CLI

With no subcommand, the CLI performs discovery. The default family is IPv4.

# Public IPv4; text output includes the scope, family, and transport.
ip-reporter --scope wan --family ipv4

# LAN IPv4 and IPv6.
ip-reporter discover --scope lan --family ipv4 --family ipv6

# Force HTTP/3 over IPv4 and IPv6.
ip-reporter --scope wan --family h3ipv4 --family h3ipv6

# Structured output for scripts.
ip-reporter --scope both --family ipv4 --family ipv6 --format json

# Print only address values, one per line.
ip-reporter --scope wan --family ipv4 --format values

WAN probing has independent failover endpoints. The defaults include two providers for IPv4, two for IPv6, and two candidates for each HTTP/3 family. Override them with repeated --wan-endpoint options or with the Python RemoteEndpoint API.

Cloudflare DNS

Use an API token with the DNS Write permission. Prefer environment variables so credentials do not enter shell history:

export CLOUDFLARE_API_TOKEN="..."
export CLOUDFLARE_ZONE_ID="..."

Update one existing record:

ip-reporter dns update \
  --record home.example.com \
  --family ipv4

Update many names and both address families:

ip-reporter dns update \
  --record home.example.com \
  --record vpn.example.com \
  --family ipv4 \
  --family ipv6 \
  --ttl 60 \
  --not-proxied

Existing records are updated with PATCH and unchanged values are skipped. Missing records are not created unless --create-missing is supplied. Stale records are not deleted. Use --dry-run to inspect discovery without changing Cloudflare.

If you have a zone name rather than an ID, pass --zone-name; the client can resolve it through the Cloudflare API. Relative names and @ are accepted when the zone name is supplied:

ip-reporter dns update \
  --zone-name example.com \
  --record home \
  --family ipv4 \
  --create-missing

h3ipv4 writes an A record and h3ipv6 writes an AAAA record. The HTTP/3 transport is discovery metadata; the DNS type is determined from the resulting IP address.

Python API

The structured API is suitable for another package, a scheduler, or a daemon:

from ip_reporter import AddressFamily, IPReporter

reporter = IPReporter()
report = reporter.discover(
    scope="wan",
    families=(AddressFamily.IPV4, AddressFamily.IPV6),
)

for address in report.wan:
    print(address.value, address.family.value, address.protocol.value)

# Convenience methods return only strings.
wan_ipv4 = reporter.get_wan(families=(AddressFamily.IPV4,))
lan_ipv6 = reporter.get_lan(families=(AddressFamily.IPV6,))

The discovery dependencies are injectable, which makes applications and tests independent of the network:

from ip_reporter import AddressDiscovery, AddressFamily, IPReporter, RemoteEndpoint

class Probe:
    def fetch_ip(self, url, family):
        return ("203.0.113.10", "http2")

reporter = IPReporter(
    AddressDiscovery(
        wan_probe=Probe(),
        endpoints=(RemoteEndpoint("https://probe.example/ip", (AddressFamily.IPV4,)),),
    )
)

Synchronize Cloudflare from the same service:

from ip_reporter import AddressFamily, IPReporter

updates = IPReporter().update_cloudflare_dns(
    ["home.example.com", "vpn.example.com"],
    zone_id="your-zone-id",
    families=(AddressFamily.IPV4, AddressFamily.IPV6),
    create_missing=True,
)
print(updates.as_dict())

CloudflareClient.from_env() uses CLOUDFLARE_API_TOKEN, or the legacy CLOUDFLARE_EMAIL and CLOUDFLARE_API_KEY pair. A custom HTTP transport can be injected into CloudflareClient for testing.

Build and publish

From a checkout:

uv sync --extra dev
uv run pytest
uv build
uv publish

Set UV_PUBLISH_TOKEN before uv publish, or configure another uv-supported PyPI credential method. Bump project.version in pyproject.toml for each release.

Cloudflare API details: DNS record create, DNS record update.

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

ip_reporter-0.1.1.tar.gz (29.3 kB view details)

Uploaded Source

Built Distribution

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

ip_reporter-0.1.1-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file ip_reporter-0.1.1.tar.gz.

File metadata

  • Download URL: ip_reporter-0.1.1.tar.gz
  • Upload date:
  • Size: 29.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ip_reporter-0.1.1.tar.gz
Algorithm Hash digest
SHA256 e9c27a83105d219fc97bd5327eba52d037a2c69659464accceb6deb0bf199e68
MD5 fd963a0dfc60ca39b325fb8710c6d516
BLAKE2b-256 60ed5a164b18a7d6edb6d6d508d2b953ec72bf476f3e808a75fc84b5d598dce2

See more details on using hashes here.

File details

Details for the file ip_reporter-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: ip_reporter-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 22.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ip_reporter-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 6d903425868d4ccfd24f9596526223838cb584cd8635920b6777691a0a7281d7
MD5 659c7b7f588bacc5e7dcd2a12619499f
BLAKE2b-256 39da4c268abf55e3c2d8f7c3ffd81fd3626f6d6fc31083288f5d7006d8ca8568

See more details on using hashes here.

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