Create a "My IP address" tool
I was wondering about how "My IP address" tools can get both the user's IPv4 and IPv6 address when a web page request is, by definition, done from one address only. It turns out it is a simple trick: after the page is loaded, queries are made through Javascript to webservices responding only on either IPv4 or IPv6. This in turn is made easy by the fact that we can configure Nginx to return a Json object with this info without using any backend at all.
I did found explanations on the web on how to do some parts of it, but not the whole thing, so this page explains how to create such a tool with Nginx and vanilla JS.
DNS configuration
The first step is to configure a domain name so that certain subdomains are only accessible through IPv4 or IPv6. Here is what I did for the domain ash.bzh:
ip 1800 IN A 54.37.75.168 ip 10800 IN AAAA 2001:41d0:701:1100::3ec ipv4 1800 IN A 54.37.75.168 ipv6 10800 IN AAAA 2001:41d0:701:1100::3ec
The subdomain ip.ash.bzh
can answer with both version, while ipv4.ash.bzh
can only be reached through IPv4, and ipv6.ash.bzh
through IPv6.
Nginx configuration
The Nginx configuration for the server side is also really simple to setup:
# /etc/nginx/sites-available/ip.conf server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name ip.ash.bzh ipv4.ash.bzh ipv6.ash.bzh; location / { add_header Access-Control-Allow-Origin *; default_type application/json; return 200 "{\"ip\":\"$remote_addr\"}"; } # [...] }
Here, any path on any of the three subdomains will return the same thing: a well formated, and CORS-enabled, JSON file with an ip
key and the IP used for the query as value.
HTML
Now, for the user-facing page, all we need is a call to a Javascript file that will hold all the logic, and a HTML table where the JS queries will append their results:
<!-- ip.html --> <!-- [...] --> <table id="ip-info"> <caption>IP info</caption> <tbody> </tbody> </table> <script src="/static/js/ip.js"></script> <!-- [...] -->
Javascript
The script itself is also really simple:
- A
pingIP
function is called twice, with the name of each protocol used as parameter. It fetches the JSON file, extracts the IP address and passes it to theaddRow
function. - The
addRow
function transforms the data into a table row and inserts it into the HTML table.
// static/js/ip.js function addRow(protocol, ip) { let tbody = document.getElementById('ip-info').getElementsByTagName('tbody')[0]; let new_row = tbody.insertRow(); new_row.outerHTML = `<tr><th>${protocol}</th><td>${ip}</td></tr>` } function pingIP(protocol) { let url = `https://${protocol.toLowerCase()}.ash.bzh/`; fetch(url, { headers: { 'Accept': 'application/json' } }) .then(response => response.json()) .then(json => addRow(protocol, json.ip)) } pingIP('IPv4'); pingIP('IPv6');
And that's pretty much it!
You can see the result at https://tools.ash.bzh/en/tools/ip/
Header image:
Photo of a passenger information display with diagnostic data, including an IP address, taken at Hawarden railway station, Flintshire, Wales. CC-BY-SA 3.0 Rept0n1x.