Можете ли вы получить IP-адрес локального локального пользователя через JavaScript?

Я знаю, что первоначальная реакция на этот вопрос "нет" и "это невозможно сделать" и "вам не нужно, вы делаете что-то неправильно". То, что я пытаюсь сделать, это получить IP-адрес пользователей LAN и отобразить его на веб-странице. Зачем? Поскольку это то, на чем я работаю, рассказывает о максимально возможной информации о вас, посетителя: http://www.whatsmyip.org/more-info-about-you/

Итак, я на самом деле ничего не делаю с IP, кроме как показывать его пользователю в информационных целях. Я использовал это, используя небольшой Java-апплет. Он работал очень хорошо. Но в наши дни браузер заставляет вас ударить и доверять так много раз, чтобы запустить даже самый младший Java-апплет, и я бы предпочел не запускать его вообще.

Итак, какое-то время я просто избавился от этой функции, но мне хотелось бы вернуться, если это возможно. Это было то, что я, как компьютерный консультант, фактически использовал бы время от времени. Быстрее перейти на этот веб-сайт, чтобы узнать, какой диапазон IP-сети работает, чем идти в Системные настройки, Сеть, а затем какой-либо интерфейс активен.

Так что мне интересно, надеюсь, если есть какой-то способ сделать это только в javascript? Может быть, какой-то новый объект, к которому вы можете получить доступ, подобно тому, как javascript может спросить браузер, где находится географическое местоположение на земле. Может быть, что-то похожее на информацию о сети для клиентов? Если нет, возможно, другой способ сделать это? Единственные способы, о которых я могу думать, это Java-апплет или Flash-объект. Я бы предпочел не делать этого.

Ответ 1

Как выясняется, последнее расширение HTML5 WebRTC позволяет javascript запрашивать IP-адрес локального клиента. Доказательство концепции доступно здесь: http://net.ipcalf.com

Эта функция, по-видимому, по дизайну, и не является ошибкой. Однако, учитывая его спорный характер, я был бы осторожен в том, чтобы полагаться на это поведение. Тем не менее, я думаю, что он идеально подходит и соответствует вашим намеченным целям (показывая пользователю, что их браузер протекает).

Ответ 2

В дополнение к последнему ответу этот код работает в браузерах, которые поддерживают WebRTC (Chrome и Firefox). Я слышал, что идет движение к реализации функции, которая заставляет сайты запрашивать IP-адрес (как в случае географического местоположения пользователя или пользовательского носителя), хотя он еще не реализован ни в одном из этих браузеров.

Вот модифицированная версия исходного кода, сокращена количество строк, не делается никаких запросов на оглушение, поскольку требуется только локальный IP, а не публичный 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;
 }
};

Мы создаем фиктивное одноранговое соединение, чтобы удаленный узел мог связаться с нами. Обычно мы обмениваемся кандидатами на лед и, читая кандидатов на лед, можем сообщить IP-адрес пользователя.

Вы можете найти демо на → Демо

Ответ 3

Я почистил мидо пост, а затем убрал функцию, которую они нашли. Это вернет либо false, либо array. При тестировании помните, что вам нужно свернуть массив в консоли веб-разработчика, иначе его неинтуитивное поведение по умолчанию может ввести вас в заблуждение, полагая, что он возвращает пустой 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;
}

Кроме того, имейте в виду, что это не что-то старое, как CSS border-radius, хотя один из тех битов, который не поддерживается IE11 и старше. Всегда используйте обнаружение объектов, тестируйте в достаточно старых браузерах (например, Firefox 4, IE9, Opera 12.1) и убедитесь, что ваши новые скрипты не нарушают ваши новые биты кода. Кроме того, всегда сначала определяйте совместимый со стандартами код, поэтому, если есть что-то, скажем, префикс CSS, сначала определите стандартный код без префикса, а затем отступите, поскольку в долгосрочной перспективе поддержка в конечном итоге будет стандартизирована до конца его существования.

Ответ 4

WebRTC API можно использовать для получения локального IP-адреса клиента.

Однако браузер может не поддерживать его, или клиент может отключить его по соображениям безопасности. В любом случае, не стоит полагаться на этот "взлом" в долгосрочной перспективе, так как он может быть исправлен в будущем (см. ответ каллен Пушистый Дженнингс).

Код ECMAScript 6 ниже демонстрирует, как это сделать.

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

Обратите внимание, я пишу return resolve(..) или return reject(..) в качестве ярлыка. Обе эти функции ничего не возвращают.

Тогда у вас может быть что-то такое:

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

Ответ 5

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)

Ответ 6

Вы можете найти дополнительную информацию о том, какие ограничения, вероятно, будут добавлены браузерами для смягчения этого и того, что делает IETF, а также почему это необходимо в IETF SPEC для обработки IP-адресов