We know that there is no way to detect local ip address in JavaScript unless using a public api. But now, with WebRTC api in browser, it's possible with limitations.
WebRTC is used to establish p2p connection. To achieve that, each peer need to collect its local addresses and send it to each other. Then WebRTC could use this information to try to connect each other. We can use this process to get local ips from it.
The code is simple. We initialize candidate collection process by faking that we want to use datachannel. Candidate is a term used in WebRTC to denote an address.
(async () => {
const pc = new RTCPeerConnection(null);
// fake that we want to use datachannel
pc.createDataChannel("");
pc.onicecandidate = ice => {
if (!ice.candidate) return;
// local ip is in candidate object
console.log(ice.candidate.address);
}
// fake the media negotiation process
const offer = await pc.createOffer()
await pc.setLocalDescription(offer);
})()
Execute this code in browser, and we could get addresses like this.
100.100.5.179
100.100.35.231
100.100.5.179
100.100.35.231
Yes, we get ip addresses. But we can see that the result is not ideal. Because we are behind NAT, the ip addresses is LAN ips. Usually, what we want is public ip.
We could deploy a STUN/TURN server, and let WebRTC get public address from there. Or we can just use the free STUN server deployed by Google.
(async () => {
const iceServers = [{ urls: "stun:stun.l.google.com:19302" }];
const pc = new RTCPeerConnection({ iceServers });
pc.createDataChannel("");
pc.onicecandidate = ice => {
if (!ice.candidate) return;
console.log(ice.candidate.address);
}
const offer = await pc.createOffer()
await pc.setLocalDescription(offer);
})()
Execute this code in browser, and finally we get what we want.
100.100.5.179
100.100.35.231
69.172.67.64
100.100.5.179
100.100.35.231