I need to fetch the client local IP address from a web application.
For which I am using a standard RTCPeerConnection implementation to fetch. But the ice candidate that is returned does not carry the IP V4 address, but an address that look like a guid: asdf-xxxx-saass-xxxx.local
But surprisingly this chrome extension is able to fetch the same on same machine and browser.
Note: code that I used in web application is same as of the extension
This is the html code for same:
<html>
<head>
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script type="text/javascript">
function logit(msg) {
var dt = new Date(); var time = dt.getHours() + ":" + dt.getMinutes() + ":"
+ dt.getSeconds();
console.log(time + " " + msg);
};
function getChromeVersion() {
try {
var raw = navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./);
return raw ? parseInt(raw[2], 10) : false;
} catch (e) {
return null;
}
}
function getChromeManifest() {
return chrome.runtime && typeof chrome.runtime === "function" ? chrome.runtime.getManifest() : {}
}
function getUserIP(callback) {
logit(" getting user local ip ")
getLocalIPs(function (ips) {
logit(" got user local ip : " + ips)
if (ips && ips.length) return callback(ips[0]);
logit(" getting user local ip with stun ")
getLocalIPs(function (ips) {
logit(" got user local ip with stun : " + ips)
if (ips && ips.length) return callback(ips[0])
logit(" cannot get user local ip, returning null ")
callback(null)
}, true, 2000)
})
}
function getLocalIPs(callback, withStun, timeout) {
var ips = [];
var RTCPeerConnection = window.RTCPeerConnection ||
window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var pc = new RTCPeerConnection({
// Don't specify any stun/turn servers, otherwise you will
// also find your public IP addresses.
// iceServers: [],
iceServers: withStun ? [{ urls: "stun:stun.services.mozilla.com" }] : []
});
var closeAndCallback = function () {
clearTimeout(waitTimeout)
try {
if (pc && pc.close) {
pc.close();
}
} catch (e) { console.log("exception while closing pc, err: %s", err) }
callback(ips);
}
var waitTimeout = timeout ? setTimeout(closeAndCallback, timeout) : null;
// Add a media line, this is needed to activate candidate gathering.
pc.createDataChannel('');
// onicecandidate is triggered whenever a candidate has been found.
pc.onicecandidate = function (e) {
console.log(e)
if (!e.candidate) { // Candidate gathering completed.
pc.close();
closeAndCallback();
return;
}
var ip = /^candidate:.+ (\S+) \d+ typ/.exec(e.candidate.candidate)[1];
if (ips.indexOf(ip) == -1) // avoid duplicate entries (tcp/udp)
ips.push(ip);
};
pc.createOffer(function (sdp) {
pc.setLocalDescription(sdp);
}, function onerror() { });
};
function callThirdParty(server, name) {
var api = server;
logit("Connecting " + server + " ...");
$.ajax({
type: "GET",
url: api,
success: function (data) {
if (data && data['ip']) {
logit("Public IP: " + data['ip']);
}
}, error:
function (request, status, error) {
logit('Response: ' + request.responseText);
logit(' Error: ' + error);
logit(' Status: ' + status);
},
complete: function (data) {
logit(' API Finished: ' + name + " Server!");
}
});
}
document.addEventListener('DOMContentLoaded', function () {
getUserIP(function (ip) { //
ipaddress = ip;
$('#ip2').html(ipaddress);
var manifest = getChromeManifest();
logit(manifest.name);
logit("Version: " + manifest.version);
logit("Chrome Version: " + getChromeVersion());
callThirdParty("https://api.ipify.org?format=json", "ipify.org");
}, 100);
}, false);
</script>
</head>
<p>Public IPs</p>
<div id="ip"></div>
<p>Local IP</p>
<div id="ip2"></div>
<p>Logs</p>
<div id="log"></div>
<div id="log1"></div>
<div id="log2"></div>
</html>
TL;DR
It looks like local addresses are/will be anonymized using mDNS and default setting for the flag would be gradually set to
Enabled
for all Chrome users.For local development take a look here (set to
Disable
): chrome://flags/#enable-webrtc-hide-local-ips-with-mdnsUnless someone finds out some clever hack for it, you probably won't be able to revert the change for users of your webapp.
That guid is actually mDNS address. Quick search in newest WebRTC bugs in Chromium https://bugs.chromium.org/p/chromium/issues/list?can=2&q=component%3ABlink%3EWebRTC+ revealed few interesting entries, and there are few StackOverflow questions regarding anonymization not working (like this one: mDNS Support for WebRTC at Google Chrome M74).
Right now I see the effect in Chrome 75 on few computers with Windows 10 - some sites which previously were able to detect local IP flawlessly (http://net.ipcalf.com, https://ipleak.net, https://browserleaks.com/webrtc) now don't display it or show mDNS url instead.
As a sidenote: after enabling the mDNS flag, the extension you've linked wasn't able to detect my exact local IP. Instead, it showed few candidates from /24 address group. Even then, the extension could be privileged in some way, so it wouldn't be affected so much by mDNS anonymization.
EDIT (Mar 2020): it looks like Firefox could be anonymizing local IPs as well.
As of March 2020, there are two settings in
about:config
page:media.peerconnection.ice.obfuscate_host_addresses
- when set to true, it changes local IP to {uuid}.localmedia.peerconnection.ice.obfuscate_host_addresses.whitelist
- string with URLs, which are able to retrieve real IP, even with obfuscation enabledI've checked Firefox 73 and Developer Edition 74 (without any extension that could have changed the setting), first had
obfuscate_host_addresses
set to false, while dev edition had it enabled.