ip-discovery - Fast public IP lookup
A Rust library and CLI to detect your public IP address using DNS, STUN, or HTTP — with built-in fallback across trusted providers.
Why ip-discovery?
Most machines don't know their own public IP. If you're behind NAT, a load balancer, or a cloud VPC, your OS only sees a private address like 10.x.x.x or 192.168.x.x. This library solves that — reliably, fast, and with zero configuration.
Common use cases:
-
Self-hosted servers with dynamic IPs — Your home server or office NAS gets a new IP every time the ISP rotates it. Use
ip-discoveryto detect the change and update your DNS record (dynamic DNS), notify clients, or refresh firewall rules — automatically. -
WebRTC / P2P connection setup — When building WebRTC applications, you need your public IP to generate SDP offers/answers and ICE candidates.
ip-discoveryuses the same STUN protocol that browsers use, giving you the public-facing address for direct peer connections without relying on a browser environment. -
NAT traversal & hole punching — Building a peer-to-peer system (game server, file sharing, VPN)? You need to know your public IP and the type of NAT you're behind before you can punch through it.
-
Server self-registration — Microservices or edge nodes that spin up in dynamic cloud environments (auto-scaling groups, spot instances) and need to register their public address with a service registry or coordination layer.
-
Security & audit logging — Record the public IP of the machine at the time of an event for compliance or forensics. Use
Consensusstrategy to cross-verify across multiple providers and guard against a single provider being spoofed. -
CLI diagnostics — Quickly check "what IP does the internet see me as?" during debugging, without opening a browser or remembering which
curlendpoint to hit.
Why not just curl an IP-echo service?
Calling a single HTTP endpoint works for a quick manual check, but falls short in production:
| HTTP IP-echo services | ip-discovery |
|
|---|---|---|
| Single point of failure | If that one service is down or slow, you get nothing | Automatic fallback across 9 providers and 3 protocols |
| Rate limiting | Many free services aggressively throttle or block automated requests | DNS and STUN are lightweight UDP queries — far less likely to be throttled than HTTP APIs |
| Latency | Full TCP + TLS handshake every time (~200–500ms) | DNS & STUN use raw UDP — typically <50ms, 2–3× faster |
| Result verification | You trust one provider blindly — it could return stale data or be spoofed | Consensus strategy cross-checks across multiple providers |
| IPv6 support | Depends on the endpoint; many only return IPv4 | First-class IPv4 and IPv6 support across DNS and STUN |
| Dependency in code | Needs shell-out or an HTTP client just to get an IP | Embeddable Rust library, no HTTP dependency needed (DNS + STUN only) |
| Offline-friendly | Requires an HTTP-capable environment / TLS stack | DNS and STUN work in minimal environments with just UDP |
💡 Note: Some strict enterprise networks block outbound UDP entirely. In those environments, DNS and STUN won't work. Enable the
httpfeature to add HTTP-based providers as a fallback — the library will automatically try them if UDP-based providers fail.
CLI Tool — ipd
A command-line tool powered by this library. Get your public IP in one command:
Install
Homebrew (macOS):
Shell (macOS & Linux):
|
PowerShell (Windows):
powershell -ExecutionPolicy Bypass -c "irm https://github.com/zer0horizon/ip-discovery/releases/latest/download/ipd-installer.ps1 | iex"
Cargo:
CLI Usage
Library
Features
- DNS and STUN via raw UDP sockets (zero network library dependencies)
- HTTP/HTTPS via reqwest (optional)
- Built-in providers from Google, Cloudflare, AWS, and OpenDNS
- IPv4 and IPv6
- Sequential fallback, race, or consensus strategies
- Custom synchronous providers via
BlockingProvider - Optional async API via the
tokio/asyncfeature
Usage
Add to your Cargo.toml:
[]
= "0.5"
The default API is blocking and does not require Tokio:
use ;
For the Tokio async API, opt in explicitly:
[]
= { = "0.5", = ["async"] }
= { = "1", = ["macros", "rt-multi-thread"] }
use ;
async
The blocking API is callable from a Tokio application too. Because it blocks
the current thread, run network lookups inside tokio::task::spawn_blocking,
or use the async API above when Tokio integration is preferred.
To lookup local private IP addresses (synchronously and offline-friendly):
use ;
if let Some = get_private_ip
if let Some = get_private_ipv6
Node.js / npm
The library can also be used in Node.js environments via prebuilt native bindings.
Install
Usage (JavaScript/TypeScript)
const = require;
// Simple lookup (Public IP)
const result = await ;
console.log;
// Local lookup (Private IP - Synchronous)
console.log;
console.log;
// Custom configuration using type-safe enums
const config = ;
const customResult = await ;
console.log;
Exported Enums
The package exports type-safe enums matching the Rust configuration options:
IpVersion:V4,V6,AnyStrategy:First,Race,ConsensusProtocol:Dns,Http,StunBuiltinProvider:GoogleStun,GoogleStun1,GoogleStun2,CloudflareStun,GoogleDns,CloudflareDns,OpenDns,CloudflareHttp,Aws
Configuration
The defaults (Cloudflare STUN → Cloudflare DNS → Google STUN/DNS → OpenDNS; 10s timeout) work well for most cases. If you need more control:
use ;
use get_ip_with;
use Duration;
// DNS only, race all DNS providers
let config = builder
.protocols
.strategy
.timeout
.build;
let result = get_ip_with?;
// Pick specific providers
let config = builder
.providers
.build;
// Consensus — require at least 2 providers to agree
let config = builder
.strategy
.build;
Strategies
| Strategy | Description |
|---|---|
First (default) |
Try providers in order, return first success |
Race |
Query all concurrently, return fastest |
Consensus { min_agree } |
Require N providers to agree on the same IP |
Providers
All built-in providers are from tier-1 infrastructure companies:
| Provider | Protocol | IPv4 | IPv6 |
|---|---|---|---|
Google STUN (stun.l.google.com) |
STUN | ✅ | ✅ |
Google STUN 1 (stun1.l.google.com) |
STUN | ✅ | ✅ |
Google STUN 2 (stun2.l.google.com) |
STUN | ✅ | ✅ |
Cloudflare STUN (stun.cloudflare.com) |
STUN | ✅ | ✅ |
Google DNS (o-o.myaddr.l.google.com) |
DNS | ✅ | ✅ |
Cloudflare DNS (whoami.cloudflare) |
DNS | ✅ | ✅ |
OpenDNS (myip.opendns.com) |
DNS | ✅ | ❌ |
Cloudflare HTTP (1.1.1.1/cdn-cgi/trace) |
HTTP | ✅ | ❌ |
AWS (checkip.amazonaws.com) |
HTTP | ✅ | ❌ |
Cargo Features
| Feature | Default | Description |
|---|---|---|
dns |
✅ | DNS detection (raw UDP, no extra deps) |
stun |
✅ | STUN detection (raw UDP, no extra deps) |
http |
❌ | HTTP detection (pulls in reqwest + rustls) |
tokio |
❌ | Enable the Tokio-based async API |
async |
❌ | Alias for tokio |
all |
❌ | Enable all protocols and the Tokio async API |
native-tls |
❌ | Add reqwest's OS-native TLS backend (requires http; rustls remains enabled) |
By default, only DNS and STUN are enabled — zero network library dependencies, fast compile times. To also use HTTP providers:
= { = "0.5", = ["http"] }
Or enable everything:
= { = "0.5", = ["all"] }
Timeout behavior
The configured timeout is per provider for First. Race and Consensus
share one caller-visible deadline while their providers run concurrently.
Blocking providers execute on worker threads so the caller returns at the
deadline even if a custom provider ignores its timeout. Rust cannot forcibly
cancel that custom code, so its worker may continue briefly in the background.
Network lookup requires connectivity. In an offline or UDP-blocked environment, the call returns an error after the applicable deadline; local private-IP helpers remain available without contacting a remote service.
Performance
STUN and DNS use raw UDP — no TLS handshake — so they're typically 2–3× faster than HTTP. Default provider order prioritizes UDP-based protocols with IPv4 + IPv6 support first, then falls back to IPv4-only HTTP providers.
💡 Tip: Latency varies significantly by region and network environment. Run the benchmark on your own infrastructure to find the optimal provider and strategy for your use case.
# Run the benchmark to find the best config for your network
Examples
MSRV
Rust 1.85 or later.
Contributing and security
See CONTRIBUTING.md for development setup and required checks. Report vulnerabilities privately according to SECURITY.md. Maintainer-only manual publishing steps are in RELEASING.md.
License
Licensed under either of Apache License, Version 2.0 or MIT License, at your option.