Kan du få en användares lokala LAN-IP-adress via JavaScript?


Jag vet att den första reaktionen på denna fråga är "nej" och "det kan inte göras" och "du borde inte behöva det, du gör något fel". Vad jag försöker göra är att få användarens LAN-IP-adress och visa den på webbsidan. Varför? För det är vad sidan jag arbetar med handlar om, att visa så mycket information som möjligt om dig, besökaren: https://www.whatsmyip.org/more-info-about-you/

Så jag gör faktiskt ingenting med IP:n, förutom att visa den för användaren i informationssyfte. Jag brukade göra detta genom att använda en liten Java-applet. Det fungerade ganska bra. Men nuförtiden måste webbläsare få dig att godkänna och lita på så många gånger, för att ens köra den minsta Java-applet, att jag hellre inte kör någon alls.

Så under en tid tog jag bara bort den här funktionen, men jag skulle vilja ha den tillbaka om möjligt. Det var något som jag, som IT-konsult, faktiskt skulle använda ibland. Det är snabbare att gå till den här webbplatsen för att se vilket IP-intervall ett nätverk använder än att gå in i Systeminställningar, Nätverk och sedan vilken gränssnitt som är aktiverad.

Så jag undrar, hoppas, om det finns något sätt att göra det enbart i javascript? Kanske något nytt objekt du kan komma åt, liknande hur javascript kan fråga webbläsaren var den geografiska platsen på jorden är. Kanske finns det något liknande för klientnätverksinformation? Om inte, kanske det finns något helt annat sätt att göra det? De enda sätt jag kan komma på är en java-applet eller ett flash-objekt. Jag skulle helst inte göra något av de två.

Svar #1

Visade det sig att den senaste WebRTC-förlängningen av HTML5 tillåter javascript att fråga efter den lokala klientens IP-adress. Ett konceptbevis finns tillgängligt här: http://net.ipcalf.com

Denna funktion är uppenbarligen avsiktlig och är inte en bugg. Med tanke på dess kontroversiella natur skulle jag dock vara försiktig med att förlita mig på detta beteende. Ändå tycker jag att det perfekt och lämpligt uppfyller ditt avsedda syfte (att avslöja för användaren vad deras webbläsare läcker).

Svar #2

Uppdatering

Denna lösning skulle inte längre fungera eftersom webbläsare åtgärdar WebRTC-läckor: för mer information om det, läs denna andra fråga: RTCIceCandidate returnerar inte längre IP

Förutom afourneys svar fungerar den här koden i webbläsare som stöder WebRTC (Chrome och Firefox). Jag har hört att det pågår en rörelse för att implementera en funktion som gör att webbplatser begär IP-adressen (som i fallet med användarens geolokalisation eller användarmedier), även om den ännu inte har implementerats i någon av dessa webbläsare.

Här är en modifierad version av källkoden, reducerade raderna, gör inga stun-förfrågningar eftersom du bara vill ha lokal IP och inte den offentliga IP:

window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;//compatibility for Firefox and chrome
var pc = new RTCPeerConnection({iceServers:[]}), noop = function(){};      
pc.createDataChannel('');//create a bogus data channel
pc.createOffer(pc.setLocalDescription.bind(pc), noop);// create offer and set local description
pc.onicecandidate = function(ice)
{
 if (ice && ice.candidate && ice.candidate.candidate)
 {
  var myIP = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/.exec(ice.candidate.candidate)[1];
  console.log('my IP: ', myIP);   
  pc.onicecandidate = noop;
 }
};

Vi skapar en dummy peer-anslutning för att den fjärranslutna parten ska kunna kontakta oss. Vi utbyter vanligtvis ice-kandidater med varandra och genom att läsa ice-kandidaterna kan vi se användarens IP-adress.

Du kan hitta en demo på --> Demo

Svar #3

WebRTC API:et kan användas för att hämta klientens lokala IP.

Men webbläsaren kanske inte stöder det, eller så kan klienten ha inaktiverat det av säkerhetsskäl. I vilket fall som helst bör man inte förlita sig på detta "hack" på lång sikt eftersom det sannolikt kommer att åtgärdas i framtiden (se Cullen Fluffy Jennings:s svar).

ECMAScript 6-koden nedan visar hur man gör det.

/* ES6 */
const findLocalIp = (logInfo = true) => new Promise( (resolve, reject) => {
    window.RTCPeerConnection = window.RTCPeerConnection 
                            || window.mozRTCPeerConnection 
                            || window.webkitRTCPeerConnection;

    if ( typeof window.RTCPeerConnection == 'undefined' )
        return reject('WebRTC not supported by browser');

    let pc = new RTCPeerConnection();
    let ips = [];

    pc.createDataChannel("");
    pc.createOffer()
     .then(offer => pc.setLocalDescription(offer))
     .catch(err => reject(err));
    pc.onicecandidate = event => {
        if ( !event || !event.candidate ) {
            // All ICE candidates have been sent.
            if ( ips.length == 0 )
                return reject('WebRTC disabled or restricted by browser');

            return resolve(ips);
        }

        let parts = event.candidate.candidate.split(' ');
        let [base,componentId,protocol,priority,ip,port,,type,...attr] = parts;
        let component = ['rtp', 'rtpc'];

        if ( ! ips.some(e => e == ip) )
            ips.push(ip);

        if ( ! logInfo )
            return;

        console.log(" candidate: " + base.split(':')[1]);
        console.log(" component: " + component[componentId - 1]);
        console.log("  protocol: " + protocol);
        console.log("  priority: " + priority);
        console.log("        ip: " + ip);
        console.log("      port: " + port);
        console.log("      type: " + type);

        if ( attr.length ) {
            console.log("attributes: ");
            for(let i = 0; i < attr.length; i += 2)
                console.log("> " + attr[i] + ": " + attr[i+1]);
        }

        console.log();
    };
} );

Notera att jag skriver return resolve(..) eller return reject(..) som en genväg. Ingen av dessa funktioner returnerar något.

Då kan du ha något så här:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Local IP</title>
</head>
<body>
    <h1>My local IP is</h1>
    <p id="ip">Loading..</p>
    <script src="ip.js"></script>
    <script>
    let p = document.getElementById('ip');
    findLocalIp().then(
        ips => {
            let s = '';
            ips.forEach( ip => s += ip + '<br>' );
            p.innerHTML = s;
        },
        err => p.innerHTML = err
    );
    </script>
</body>
</html>

Relaterade artiklar