Fast, fault-tolerant public IP address retrieval from Python or CLI.
The primary goal of this project is to find the public IP address (sometimes called an external IP address) reliably. This means it works with or without UPnP, dual NAT, DNS manipulation by the ISP, a VPN, or any single public web API or STUN server. It simultaneously queries multiple external sources at random from a long list, recovers gracefully from failed queries, and does not return an IP address unless all the responses agree.
pip install myorigin
$ myorigin -v
08:54:32.904 INFO requests (need 2 matches):
08:54:33.552 INFO http://zx2c4.com/ip → 88.123.8.180 (640 ms; 33 of 34 succeeded)
08:54:33.743 INFO https://myip.dnsomatic.com/ → 429 Too Many Requests (30 of 35 succeeded)
08:54:34.573 INFO http://ip.websupport.sk/ → 88.123.8.180 (814 ms; 34 of 34 succeeded)
08:54:34.584 INFO IP found: 88.123.8.180 (2 successes, 1 failures)
88.123.8.180
$
$ myorigin --help
usage: myorigin [-h] [-t TIMEOUT] [--minimum-match MINIMUM_MATCH]
[--overkill OVERKILL] [--majority-ratio MAJORITY_RATIO]
[--max-failures MAX_FAILURES]
[--max-connections MAX_CONNECTIONS] [--dbfile DBFILE]
[--show-api-providers] [-4] [-6] [-l LOGFILE] [-q] [-v]
options:
-h, --help show this help message and exit
-t TIMEOUT, --timeout TIMEOUT approximate timeout for http and https
requests in milliseconds (default: 12000)
--minimum-match MINIMUM_MATCH an IP address is considered valid after
this number of idential responses
(default: 2)
--overkill OVERKILL number of initial requests to make beyond
minimum-match (default: 0)
--majority-ratio MAJORITY_RATIO minimum ratio needed to overrule a
conflicting response; must be an integer;
a value of 2 means 2:1, or that 6
responses of 8.7.8.7 are needed to
overrule 3 responses of 7.8.4.4 (default:
3)
--max-failures MAX_FAILURES maximum number of failed requests allowed
(default: 10)
--max-connections MAX_CONNECTIONS maximum number of simultaneous network
connections allowed (default: 10)
--dbfile DBFILE path for database file ('-' for memory-
only; default:
~/.config/myorigin/data.sqlite)
--show-api-providers display the database of IP address API
providers in a human-readable form and
exit
-4, --ipv4 use IPv4 only; note this or --ipv6 is
highly recommended if both IPv4 and IPv6
are available, in order to avoid wasteful
network traffic and unpredictable results
(sometimes --minimum-match IPv4 addresses
will be received first, and sometimes
IPv6 will win)
-6, --ipv6 use IPv6 only
-l LOGFILE, --logfile LOGFILE path for log file (default: write to
STDERR)
-q, --quiet silence warning messages
-v, --verbose increase verbosity
$
>>> import myorigin
>>> args = myorigin.MyoriginArgs()
>>> args.minimum_match = 4
>>> myorigin.my_ip(args)
'88.123.8.180'
>>>
>>> args.exception_level = 2
>>> args.ip_version = 6 # but there is no IPv6 on this LAN
>>> try:
... myorigin.my_ip(args)
... except myorigin.NetworkError as e:
... print(f"got error: {e}")
...
got error: 10 requests failed; giving up
>>>
- retrieves your IP address from any of 135 IP address providers
- confirms the correct IP address by checking muliple providers (default 2)
- recovers from failures by making additional requests of other providers
- keeps a record of past successes and prioritizes the fastest and most reliable providers from your location
- makes simultaneous IP address requests
- supports http, https, IPv4, IPv6
- has only been tested on Ubuntu Linux, though, being 100% Python, this should work on Windows, macOS, other Linux and BSDs, etc.
- has not been field-tested
- Go External IP: "a Golang library to get your external ip from multiple services"
- gip: "a command-line tool to get global IP address"; written in Rust
- Discovering public IP programmatically: Stack Overflow discussion (16 answers)
- PyNAT: "Discover external IP addresses and NAT topologies using STUN"
- pubip: "get public IP address"; written in Go
Did you find a mistake or have a suggestion? With a GitHub account, it's easy to suggest changes. ☺