È possibile ottenere l'indirizzo IP LAN locale di un utente tramite JavaScript?


102

So che la reazione iniziale a questa domanda è "no" e "non si può fare" e "non dovresti averne bisogno, stai facendo qualcosa di sbagliato". Quello che sto cercando di fare è ottenere l'indirizzo IP LAN degli utenti e visualizzarlo sulla pagina web. Perché? Perché è di questo che tratta la pagina su cui sto lavorando, che mostra quante più informazioni possibili su di te, il visitatore: http://www.whatsmyip.org/more-info-about-you/

Quindi non sto effettivamente FACENDO nulla con l'IP, tranne mostrarlo all'utente a scopo informativo. Lo facevo utilizzando una piccola applet Java. Ha funzionato abbastanza bene. Ma in questi giorni, il browser ti fa premere d'accordo e fidarti così tante volte, per eseguire anche l'applet java più piccola, che preferirei non eseguirne affatto.

Quindi per un po 'mi sono sbarazzato di questa funzione, ma la vorrei indietro se possibile. Era qualcosa che io, come consulente informatico, usavo di tanto in tanto. È più veloce andare su questo sito Web per vedere su quale intervallo IP è in esecuzione una rete, piuttosto che andare in Preferenze di Sistema, Rete e quindi qualunque interfaccia sia attiva.

Quindi mi chiedo, sperando, se c'è un modo per farlo solo in javascript? Forse qualche nuovo oggetto a cui puoi accedere, simile al modo in cui javascript può chiedere al browser dove si trova la posizione geografica sulla terra. Forse c'è qualcosa di simile per le informazioni di rete del client? In caso contrario, forse c'è un altro modo per farlo? Gli unici modi in cui riesco a pensare sono un'applet java o un oggetto flash. Preferisco non fare nessuno di questi.


1
Tu sai la risposta. Perché chiederlo allora? È improbabile che le applet Java o gli oggetti flash siano consentiti dagli utenti (potrebbe essere solo da coloro che sono nuovi in ​​Internet), quindi non è una soluzione nel caso comune. ActiveX e le cose nelle vicinanze funzionano solo in IE e, quindi, gli utenti di altri browser non saranno interessati (e, inoltre, anche in IE esiste una politica di sicurezza che impedisce al sito web di fare cose brutte)
Alma Do

Il mio indirizzo IP viene catturato attraverso HTTP_X_FORWARDED_FORquella pagina, solo dicendo.
tomdemuyt

50
Perché chiedere allora? Perché forse, solo forse, non so tutto.
l008com

1
Questi ragazzi lo fanno: whatismyproxy.com
likebike

1
@likebike Nice one. Esaminando come lo stanno facendo.
Dominic Cerisano

Risposte:


117

A quanto pare, la recente estensione WebRTC di HTML5 consente a javascript di interrogare l'indirizzo IP del client locale. Una prova di concetto è disponibile qui: http://net.ipcalf.com

Questa caratteristica è apparentemente di progettazione e non è un bug. Tuttavia, data la sua natura controversa, sarei cauto nel fare affidamento su questo comportamento. Tuttavia, penso che affronti perfettamente e in modo appropriato lo scopo previsto (rivelando all'utente ciò che sta perdendo il suo browser).


1
Questo è stato utile. Grazie ancora!
Ansuraj Khadanga

7
Funziona solo su Chrome e Firefox, E NON su IE, Edge o Safari
ali

Stavo cercando il mio IP WAN e questo sito whatismyip.com mi ha anche fornito il mio IP locale e immagino che avesse qualcosa a che fare con JS.
Shayan

@ali Hai ragione, il sito web che ho menzionato sopra non è in grado di dire il mio IP locale su Edge.
Shayan

6
Google Chrome nasconde l'IP locale per impostazione predefinita. Mostra qualcosa di simile a e87e041d-15e1-4662-adad-7a6601fca9fb.local . Questo comportamento può essere modificato impostando la variabile # enable-webrtc-hide-local-ips-with-mdns su disabled in Chrome: // flags
injaon

81

Aggiornare

Questa soluzione non funzionerebbe più perché i browser stanno risolvendo la perdita di webrtc: per maggiori informazioni leggi quest'altra domanda: RTCIceCandidate non restituisce più l'IP


Oltre alla risposta di afourney, questo codice funziona nei browser che supportano WebRTC (Chrome e Firefox). Ho sentito che è in corso un movimento per implementare una funzionalità che fa sì che i siti richiedano l'IP (come nel caso della geolocalizzazione dell'utente o dei media utente) sebbene debba ancora essere implementata in uno di questi browser.

Ecco una versione modificata del codice sorgente , ridotte le linee, senza effettuare richieste di stordimento poiché si desidera solo l'IP locale e non l'IP pubblico:

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;
 }
};

Stiamo creando una connessione peer fittizia per consentire al peer remoto di contattarci. In genere ci scambiamo tra loro candidati di ghiaccio e leggendo i candidati di ghiaccio possiamo dire l'ip dell'utente.

Puoi trovare una demo su -> Demo


Grazie per questo Mido! Molto apprezzato.
Sujay Phadke

1
@dampee - Credo che Edge non supporti i canali dati al momento.
MichaelB76

Cos'è un canale dati fasullo? Non riesco a trovare alcun riferimento su Google
AmazingTurtle

2
nota che l'API createOffer è passata per essere basata su Promise invece di successCallback e failCallback come parametri, quindi potrebbe non funzionare su versioni più recenti, vedere: developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/…
Dickeylth

10

L' API WebRTC può essere utilizzata per recuperare l'IP locale del client.

Tuttavia, il browser potrebbe non supportarlo o il client potrebbe averlo disabilitato per motivi di sicurezza. In ogni caso, non si dovrebbe fare affidamento su questo "hack" a lungo termine in quanto è probabile che venga aggiornato in futuro (vedere la risposta di Cullen Fluffy Jennings).

Il codice ECMAScript 6 di seguito mostra come farlo.

/* 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();
    };
} );

Nota che scrivo return resolve(..)o return reject(..)come scorciatoia. Entrambe queste funzioni non restituiscono nulla.

Quindi potresti avere qualcosa di questo:

<!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>

9

Ho ripulito il post di mido e poi ho ripulito la funzione che hanno trovato. Questo tornerà falseo un file array. Durante il test ricorda che devi comprimere l'array nella console dello sviluppatore web altrimenti il ​​suo comportamento predefinito non intuitivo potrebbe farti pensare che stia restituendo un vuoto array.

function ip_local()
{
 var ip = false;
 window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection || false;

 if (window.RTCPeerConnection)
 {
  ip = [];
  var pc = new RTCPeerConnection({iceServers:[]}), noop = function(){};
  pc.createDataChannel('');
  pc.createOffer(pc.setLocalDescription.bind(pc), noop);

  pc.onicecandidate = function(event)
  {
   if (event && event.candidate && event.candidate.candidate)
   {
    var s = event.candidate.candidate.split('\n');
    ip.push(s[0].split(' ')[4]);
   }
  }
 }

 return ip;
}

Inoltre si prega di tenere a mente che la gente non si tratta di qualcosa di vecchio-nuovo come CSS border-radiusanche se una di quelle punte che è a titolo definitivo , non supportata da IE11 e più anziani. Usa sempre il rilevamento degli oggetti, prova in browser ragionevolmente meno recenti (ad esempio Firefox 4, IE9, Opera 12.1) e assicurati che i tuoi script più recenti non danneggino i tuoi nuovi bit di codice. Inoltre, rileva sempre prima il codice conforme agli standard, quindi se c'è qualcosa con diciamo un prefisso CSS rileva prima il codice standard non prefissato e poi ripiega perché a lungo termine il supporto sarà standardizzato per il resto della sua esistenza.


stai ridichiarando ip- riga 3 e riga 8.
user2757813

@Anu WebRTC non è stato introdotto fino a Internet Explorer 15 (o "Edge 15") quindi no. Questo è il motivo per cui sulla quarta riga sopra se nessuno degli oggetti esiste, la funzione restituirà false. Se c'è un altro modo per ottenere questo risultato in IE, non ne sono a conoscenza in questo momento.
John

@ John - come passiamo il valore di ritorno a una variabile php? Tramite un post nascosto?
MarcoZen

@MarcoZen È possibile utilizzare <input name="example1" type="hidden" value="whatever" />o utilizzare un AJAX POST in una situazione del genere. Consiglio vivamente di studiare la mia ajax()funzione qui: jabcreations.com/docs/javascript
John

Ho appena scoperto che alcuni browser (ad esempio Chrome) ora bloccano la fornitura dell'IP: lo stesso codice ora si risolve in un nome host mDNS, se non è richiesta l'autorizzazione per video / audio. Vedi groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Christoph Bimminger

6

function getUserIP(onNewIP) { //  onNewIp - your listener function for new IPs
  //compatibility for firefox and chrome
  var myPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
  var pc = new myPeerConnection({
      iceServers: []
    }),
    noop = function() {},
    localIPs = {},
    ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3}|[a-f0-9]{1,4}(:[a-f0-9]{1,4}){7})/g,
    key;

  function iterateIP(ip) {
    if (!localIPs[ip]) onNewIP(ip);
    localIPs[ip] = true;
  }
  onNewIP
  //create a bogus data channel
  pc.createDataChannel("");

  // create offer and set local description
  pc.createOffer().then(function(sdp) {
    sdp.sdp.split('\n').forEach(function(line) {
      if (line.indexOf('candidate') < 0) return;
      line.match(ipRegex).forEach(iterateIP);
    });

    pc.setLocalDescription(sdp, noop, noop);
  }).catch(function(reason) {
    // An error occurred, so handle the failure to connect
  });

  //listen for candidate events
  pc.onicecandidate = function(ice) {
    if (!ice || !ice.candidate || !ice.candidate.candidate || !ice.candidate.candidate.match(ipRegex)) return;
    ice.candidate.candidate.match(ipRegex).forEach(iterateIP);
  };
}
getUserIP(console.log)


Utilizza le opzioni dell'editor per formattare il codice in modo appropriato.
31piy

3
Sarebbe fantastico se non solo rilasciassi del codice, ma fornisse anche una spiegazione di cosa sta succedendo nel suo e nel tuo codice. Aiuta l'autore della domanda e altri utenti. Va bene se funziona, ma sapere perché è ancora più importante secondo me.
davejal

qualche soluzione compatibile con IE?
Anu

1
Il commento è una copia incolla di questo articolo: ourcodeworld.com/articles/read/257/…
Darkshifty

Ho appena scoperto che alcuni browser (ad esempio Chrome) ora bloccano la fornitura dell'IP: lo stesso codice ora si risolve in un nome host mDNS, se non è richiesta l'autorizzazione per video / audio. Vedi groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Christoph Bimminger

5

Chrome 76+

L'anno scorso ho utilizzato la risposta di Linblow (2018-ott-19) per scoprire con successo il mio IP locale tramite javascript. Tuttavia, i recenti aggiornamenti di Chrome (76?) Hanno vinto questo metodo in modo che ora restituisca un IP offuscato, come ad esempio:1f4712db-ea17-4bcf-a596-105139dfd8bf.local

Se hai il pieno controllo del tuo browser, puoi annullare questo comportamento disattivandolo in Chrome Flags, digitando questo nella barra degli indirizzi:

chrome://flags

e DISATTIVARE la bandiera Anonymize local IPs exposed by WebRTC

Nel mio caso, ho bisogno dell'IP di uno script TamperMonkey per determinare la mia posizione attuale e fare cose diverse in base alla mia posizione. Ho anche il pieno controllo sulle impostazioni del mio browser (nessuna politica aziendale, ecc.). Quindi per me, cambiando il filechrome://flags impostazione fa il trucco.

fonti:

https://groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU

https://codelabs.developers.google.com/codelabs/webrtc-web/index.html


quella bandiera potrebbe sparire. Al momento sembra che le estensioni ottengano ancora gli IP, quindi potresti provare a ottenerlo dallo script in background. Tuttavia, a lungo termine tutte le scommesse sono disattivate.
Philipp Hancke

1
Secondo groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU , l'IP dovrebbe comunque essere restituito se implementi la tua soluzione che richiede l'autorizzazione audio / video.
Christoph Bimminger


0

Una RTCPeerConnectionpuò essere utilizzato. In browser come Chrome in cui getUserMediaè richiesta un'autorizzazione , possiamo semplicemente rilevare i dispositivi di input disponibili e richiederli.

const internalIp = async () => {
    if (!RTCPeerConnection) {
        throw new Error("Not supported.")
    }

    const peerConnection = new RTCPeerConnection({ iceServers: [] })

    peerConnection.createDataChannel('')
    peerConnection.createOffer(peerConnection.setLocalDescription.bind(peerConnection), () => { })

    peerConnection.addEventListener("icecandidateerror", (event) => {
        throw new Error(event.errorText)
    })

    return new Promise(async resolve => {
        peerConnection.addEventListener("icecandidate", async ({candidate}) => {
            peerConnection.close()

            if (candidate && candidate.candidate) {
                const result = candidate.candidate.split(" ")[4]
                if (result.endsWith(".local")) {
                    const inputDevices = await navigator.mediaDevices.enumerateDevices()
                    const inputDeviceTypes = inputDevices.map(({ kind }) => kind)

                    const constraints = {}

                    if (inputDeviceTypes.includes("audioinput")) {
                        constraints.audio = true
                    } else if (inputDeviceTypes.includes("videoinput")) {
                        constraints.video = true
                    } else {
                        throw new Error("An audio or video input device is required!")
                    }

                    const mediaStream = await navigator.mediaDevices.getUserMedia(constraints)
                    mediaStream.getTracks().forEach(track => track.stop())
                    resolve(internalIp())
                }
                resolve(result)
            }
        })
    })
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.