Чи можете ви отримати IP-адресу локальної локальної мережі користувачів через JavaScript?


102

Я знаю, що початкова реакція на це питання - "ні" і "це не можна зробити" і "вам це не потрібно, ви робите щось не так". Що я намагаюся зробити, це отримати IP-адресу користувачів локальної мережі та відобразити її на веб-сторінці. Чому? Тому що саме над цією сторінкою я працюю, показуючи якомога більше інформації про вас, відвідувач: http://www.whatsmyip.org/more-info-about-you/

Тож я насправді нічого не роблю з IP, крім того, щоб показувати це користувачеві в інформаційних цілях. Я раніше це робив, використовуючи невеликий аплет Java. Це спрацювало досить добре. Але в ці дні браузер змушує вас погоджуватися і довіряти так багато разів, щоб запустити навіть самий незначний аплет Java, що я краще не запускати його взагалі.

Тому на деякий час я просто позбувся цієї функції, але мені б хотілося повернути її, якщо можливо. Я, як консультант з комп’ютерів, час від часу фактично використовував це. Швидше перейти на цей веб-сайт, щоб побачити, в якому діапазоні IP працює мережа, ніж увійти в «Системні налаштування», «Мережа», а потім будь-який інтерфейс активний.

Тож мені цікаво, сподіваюся, чи є якийсь спосіб зробити це тільки в JavaScript? Можливо, якийсь новий об’єкт, до якого ви можете отримати доступ, подібно до того, як javascript може запитати браузер, де географічне розташування на землі. Можливо, є щось подібне для інформації про клієнтські мережі? Якщо ні, можливо, є якийсь інший спосіб цілком це зробити? Єдині способи, які я можу придумати, - це аплет Java або флеш-об’єкт. Я б краще не робив жодного з них.


1
Ви знаєте відповідь. Чому тоді просити? Java-аплети або флеш-об’єкти навряд чи дозволять користувачі (можуть бути лише новичками в Інтернеті) - тому це не є звичайним рішенням. Активні елементи ActiveX та довколишніх ресурсів працюють лише в IE - і, таким чином, користувачі інших браузерів не будуть зачеплені (і, ще більше, навіть в IE існує політика безпеки, яка не дозволяє веб-сайту робити неприємні речі)
Alma Do

Моя IP-адреса зафіксована через HTTP_X_FORWARDED_FORцю сторінку, просто скажімо.
tomdemuyt

50
Навіщо тоді питати? Бо, може, просто, може, я не все знаю.
l008com

1
Ці хлопці роблять це: whatismyproxy.com
likebike

1
@likebike Приємний. Дивлячись, як вони це роблять.
Домінік

Відповіді:


117

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

Ця функція, мабуть , дизайн , і не є помилкою. Однак, враховуючи його суперечливий характер, я б з обережністю покладався на цю поведінку. Тим не менш, я вважаю, що це ідеально і належним чином вирішує вашу мету (розкриваючи користувачеві, що витікає їх браузер).


1
Це було корисно. Знову дякую!
Ансурай Хаданга

7
Він просто працює на хромі і світлячок, а не на IE, Краю або сафарі
али

Я шукав IP-адресу WAN, і цей веб-сайт whatismyip.com також подарував мені свій локальний IP-адрес, і, мабуть, це було пов'язане з JS.
Шаян

@ali Ви маєте рацію, веб-сайт, про який я згадував вище, не може повідомити про свій локальний IP-адрес на Edge.
Шаян

6
Google Chrome за замовчуванням приховує локальний IP-адресу. Він показує щось подібне до e87e041d-15e1-4662-adad-7a6601fca9fb.local . Цю поведінку можна змінити, встановивши змінну # enable-webrtc-hid-local-ips-with-mdns для відключеної в Chrome: // flags
injaon

81

Оновлення

Це рішення більше не працюватиме, оскільки браузери виправляють протікання webrtc: для отримання додаткової інформації про це читайте це інше питання: RTCIceCandidate більше не повертає IP


На додаток до відповіді afourney цей код працює у веб-переглядачах, які підтримують 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 користувача.

Демонстраційну версію можна знайти за адресою -> Demo


Дякую за це Мідо! Цінується.
Суджай Фадке

1
@dampee - Я вважаю, що наразі Edge не підтримує канали передачі даних.
MichaelB76

Що таке хибний канал даних? Неможливо знайти будь-яку посилання на Google
AmazingTurtle

2
зверніть увагу на апі createOffer переключився грунтуватися на Promise замість successCallback і failCallback як Params, так що це не може працювати на більш нові версії, див: developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection / ...
Dickeylth

10

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>

9

Я прибирав посаду Mido, а потім прибирав функцію, яку вони знайшли. Це повернеться 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 спочатку виявляє стандартний нефіксований код, а потім повертається назад, оскільки в перспективі підтримка в кінцевому підсумку буде стандартизована до кінця його існування.


ви переосмислюєте ip- рядок 3 та рядок 8.
user2757813

@Anu WebRTC не було введено доти, поки Internet Explorer 15 (або "Edge 15") так ні. Ось чому в четвертому рядку вище, якщо жоден з об'єктів не існує, функція поверне помилкову. Якщо є інший спосіб досягти цього в IE, я наразі про це не знаю.
Джон

@John - як ми можемо передати повернене значення змінній php? Через прихований пост?
MarcoZen

@MarcoZen У такій ситуації ви можете використовувати <input name="example1" type="hidden" value="whatever" />або використовувати AJAX POST. Я настійно рекомендую вивчити свою ajax()функцію тут: jabcreations.com/docs/javascript
Іван

Щойно з’ясували, що деякі браузери (наприклад, Chrome) тепер блокують надання IP - той самий код тепер вирішує ім’я хоста mDNS, якщо дозволу на відео / аудіо не вимагається. Перегляньте groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Крістоф Біммінгер

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)


Будь ласка, використовуйте параметри редактора, щоб правильно відформатувати свій код.
31пій

3
Було б чудово, якби ви не просто кинули якийсь код, а й пояснили, що відбувається в його та вашому коді. Це допомагає автору запитання та іншим користувачам. Добре, якщо це працює, але знати, чому на мою думку ще важливіше.
davejal

будь-які сумісні з IE рішення?
Ану

1
Коментар - це копія вставки цієї статті: ourcodeworld.com/articles/read/257/…
Darkshifty

Щойно з’ясували, що деякі браузери (наприклад, Chrome) тепер блокують надання IP - той самий код тепер вирішує ім’я хоста mDNS, якщо дозволу на відео / аудіо не вимагається. Перегляньте groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Крістоф Біммінгер

5

Chrome 76+

Минулого року я використовував відповідь Лінблоу (2018-жовтень-19) для успішного виявлення моєї локальної IP-адреси через javascript. Однак останні оновлення Chrome (76?) Перемогли цей метод, і тепер він повертає заплутаний IP, наприклад:1f4712db-ea17-4bcf-a596-105139dfd8bf.local

Якщо ви повністю контролюєте свій веб-переглядач, ви можете скасувати цю поведінку, вимкнувши її у прапорах Chrome, ввівши це у свій адресний рядок:

chrome://flags

та ВІДМОВЛЕННЯ прапора Anonymize local IPs exposed by WebRTC

У моєму випадку я вимагаю IP для скрипту TamperMonkey, щоб визначити моє теперішнє місце розташування та робити різні речі на основі мого місцезнаходження. Я також маю повний контроль над власними налаштуваннями браузера (відсутність корпоративної політики тощо). Тож для мене зміна chrome://flagsналаштування робить трюк.

Джерела:

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

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


цей прапор може зійти. Наразі здається, що розширення все ще отримують IP-адреси, тому ви можете спробувати отримати його з фонового сценарію. Довгострокові всі ставки знищені.
Philipp Hancke

1
Відповідно до groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU , IP все одно слід повернути, якщо ви реалізуєте рішення, яке вимагає дозволу на аудіо / відео.
Крістоф Біммінгер


0

RTCPeerConnectionМоже бути використаний. У таких браузерах, як Chrome, де потрібен getUserMediaдозвіл , ми можемо просто виявити наявні пристрої введення та запитувати їх.

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)
            }
        })
    })
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.