1

When trying to find out my public IP address using a public STUN server, it works for IPv4 but not for IPv6, regardless of the STUN server I use.

I only get stuff like "59aeb370-1d93-44ee-a526-27d639256cf4.local" under candidate.address. Is there any way to get the public IPv6 via javascript using STUN?

The code I use is:

(don't mind the IPv4 regex; the entire 'candidate' is console logged anyway)

var ip_dups = {};

function getRTCPeerConnection () {
    var iframe, content_window, rtc_peer_con = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.msRTCPeerConnection;
    return rtc_peer_con || (iframe = document.createElement("iframe"), iframe.style.display = "none", document.body.appendChild(iframe), content_window = iframe.contentWindow, rtc_peer_con = content_window.RTCPeerConnection || content_window.mozRTCPeerConnection || content_window.webkitRTCPeerConnection || content_window.msRTCPeerConnection), rtc_peer_con
};

var n = getRTCPeerConnection();
servers = {
    iceServers: [{
        urls: "stun:stun.l.google.com:19302"
    }]
};  
mediaConstraints = {
    optional: [{
        RTCPChannel: true
    }]
};
        
pc = new n(servers, mediaConstraints);

function handleCandidate(candidate){
    console.log(candidate);
    //match just the IP address
    var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
    var ip_addr = ip_regex.exec(candidate)[1];
    if(ip_dups[ip_addr] === undefined) {
        console.log(ip_addr);
        ip_dups[ip_addr] = true;
    }
    pc.close()
}

pc.onicecandidate = function(ice){
    //skip non-candidate events
    console.log(ice)
    if(ice.candidate) {
        handleCandidate(ice.candidate.candidate);
    }
};

pc.createDataChannel("");

void pc.createOffer(function(e) {
    console.log(e)
    console.log(e.sdp)
    pc.setLocalDescription(e, function() {}, function() {})
}, function() {})

EDIT:

seems like in some cases I do get my IPv6 in the response when running the code inside the consoles of some web pages.

But then when accessing the same page from chrome incognito for example, it doesn't work, so it's not because of the domain or anything like that.

No permissions are involved too.

So what the hell is going on? What's the logic behind it? Is there anything can do so my webpage will always cause its visitors to receive their IPv6 addresses?

Ref Fil
  • 19
  • 1
  • 3
  • You do not need STUN (Session Traversal Utilities for NAT) with IPv6 because you do not use NAT with IPv6. Hosts get Global IPv6 addresses, so all the addresses are public addresses. – Ron Maupin Jan 20 '21 at 22:37
  • Thanks for your reply! That's what I was thinking. However IPv6 seems to be a valid response for an 'address': https://developer.mozilla.org/en-US/docs/Web/API/RTCIceCandidateStats/address Was anything changed on the javascript API? Because it used to be received (at least in some cases?) https://stackoverflow.com/questions/48069862/stun-ip-address-javascript – Ref Fil Jan 20 '21 at 23:42
  • @RefFil I answered below. Please check the answer mark if this solved your problem. – divinelemon Jan 21 '21 at 00:38
  • @RefFil this is not returning a IPv6 address, you want to research [the difference between IPv4 and IPv6](https://www.guru99.com/difference-ipv4-vs-ipv6.html#:~:text=KEY%20DIFFERENCE,separated%20by%20a%20colon(%3A).). Please research a little more and edit your post. – divinelemon Jan 22 '21 at 17:08
  • However, I edited my post and gave you the answer. – divinelemon Jan 22 '21 at 17:11
  • @divinelemon Have you executed the javascript code that I posted? I don't think you have. Please execute it so you'll see that the XOR and all those stuff are irrelevant. I get my IPv4 almost all the time. And I get my IPv6 only rarely. My question is what's the algorithm behind it. I'm only asking about STUN, other methods (via http for example) are not relevant – Ref Fil Jan 24 '21 at 15:23
  • @RefFil I have. It returns nothing. It returns the obfuscated string for me. Their is not an algorithm, it is certain browsers have yet to fully patch this bug. – divinelemon Jan 25 '21 at 23:20
  • @RefFil please read this [great article](https://bloggeek.me/psa-mdns-and-local-ice-candidates-are-coming/) about exactly what you need. I also will edit my post. – divinelemon Jan 28 '21 at 19:05

1 Answers1

1

To quote a great article about your issue:

Ignoring that fact, Google has been running mDNS as an experiment for a few Chrome releases already. As an experiment, two things were decided:

  • It runs almost “randomly” on Chrome browsers of users without any real control of the user or the service that this is happening (not something automated and obvious at least)
  • It was added only when local IP addresses had to be shared and no permission for the camera or microphone were asked for (receive only scenarios)

Basically, Chrome has been rolling out mDNS IP obfuscation. This means that if your script does not call getUserMedia, the candidate line will be obfuscated. Please read the entire article here

OLD ANSWER:

Due to security concerns originating with the Chrome team, IP addresses are now obfuscated (hidden, definition). If you look at the date on the post you commented (in 2018, three years ago), you can see how outdated this question and solution is.

However, you can use a UDP transport which will reliably return a user's IPv4 address. Consider the following snippet:

iceServers: [{
    urls: "stun:stun.l.google.com:19302?transport=udp"
}]

That being said, you can also reliably get a user's IP address with a 3rd part API like Abstract (see the full list of 3rd party IP lookups here). Alternatively, you can use Node.js to do the same thing. Here are some relevant code samples and articles:

How to Get User’s IP Details in ExpressJS - Article

geoip-lite - Node.js module

Simple ip detection in Node.js:

const express = require('express');
const app = express();
const router = express.Router();

router.get('/someroute', (req,res) => {
  const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  console.log(ip); // ip address of the user
});

app.use('/', router);
app.listen(5000);

(found here)

References:

Wikipedia:

The basic protocol operates essentially as follows: The client, typically operating inside a private network, sends a binding request to a STUN server on the public Internet. The STUN server responds with a success response that contains the IP address and port number of the client, as observed from the server's perspective. The result is obfuscated through exclusive or (XOR) mapping to avoid translation of the packet content by application layer gateways (ALGs) that perform deep packet inspection in an attempt to perform alternate NAT traversal methods.

RFC 5389:

The XOR-MAPPED-ADDRESS attribute is identical to the MAPPED-ADDRESS attribute, except that the reflexive transport address is obfuscated through the XOR function.

Here is the final code:

var ip_dups = {};

function getRTCPeerConnection () {
    var iframe, content_window, rtc_peer_con = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || window.msRTCPeerConnection;
    return rtc_peer_con || (iframe = document.createElement("iframe"), iframe.style.display = "none", document.body.appendChild(iframe), content_window = iframe.contentWindow, rtc_peer_con = content_window.RTCPeerConnection || content_window.mozRTCPeerConnection || content_window.webkitRTCPeerConnection || content_window.msRTCPeerConnection), rtc_peer_con
};

var n = getRTCPeerConnection();
servers = {
    iceServers: [{
        urls: "stun:stun.l.google.com:19302?transport=udp"
    }]
};  
mediaConstraints = {
    optional: [{
        RTCPChannel: true
    }]
};
        
pc = new n(servers, mediaConstraints);

function handleCandidate(candidate){
    console.log(candidate);
    //match just the IP address
    var ip_regex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/
    var ip_addr = ip_regex.exec(candidate)[1];
    if(ip_dups[ip_addr] === undefined) {
        console.log(ip_addr);
        ip_dups[ip_addr] = true;
    }
    pc.close()
}

pc.onicecandidate = function(ice){
    //skip non-candidate events
    console.log(ice)
    if(ice.candidate) {
        handleCandidate(ice.candidate.candidate);
    }
};
// now you have to create a data channel with a name
pc.createDataChannel("fake_data_channel");

void pc.createOffer(function(e) {
    console.log(e)
    console.log(e.sdp)
    pc.setLocalDescription(e, function() {}, function() {})
}, function() {})
Community
  • 1
  • 1
divinelemon
  • 1,925
  • 2
  • 23
  • 1. "IP addresses are now obfuscated" - are they? IPv4, using the code above, is received perfectly well, not obfuscated or anything. 2. I know that the post I've mentioned is old, if you read my last comment again you can see that I refer to it in past tense ("it used to be received"), and asking whether anything was changed between then and now. The fact that it is an old post is part of the question. – Ref Fil Jan 21 '21 at 10:22
  • The XOR obfuscation is irrelevant. It is sent XORed but the javascript API deobfuscates it. And BTW seems like in some cases I do get my IPv6 in the response when running the code inside the consoles of some web pages. But then when accessing the same page from chrome incognito for example, it doesn't work, so it's not because of the domain or anything like that. No permissions are involved too. So what the hell is going on? What's the logic behind it? Is there anything can do so my webpage will always cause its visitors to receive their IPv6 addresses? – Ref Fil Jan 21 '21 at 10:42
  • @RefFil Thanks for responding! How are you hosting this server? Is it pure HTML, CSS, and JS? If not, are you using PHP? If you are using a custom server option like PHP or Node.js, you can get the user's IP address and set it as a cookie so your JS script can read it. However, I haven't found any evidence that the XORed IP is deobfuscated by the user, in all cases I have found it is deobfuscated by the STUN server. Also, I have found working examples of getting a user's IPv4 address, however, nothing with IPv6. – divinelemon Jan 21 '21 at 22:21
  • STUN is a different protocol than HTTP(S), I'm running it on its own, without any relation to a webserver – Ref Fil Jan 24 '21 at 15:26
  • @RefFil the code you gave me uses an ice server. – divinelemon Jan 24 '21 at 16:18
  • @RefFil I added the solution. Please mark this as an answer. – divinelemon Jan 24 '21 at 16:25