web-dev-qa-db-ja.com

JavaScriptを使用してユーザーのローカルLAN IPアドレスを取得できますか?

この質問に対する最初の反応は「いいえ」と「できない」であり、「あなたはそれを必要とすべきではない、あなたは何か間違ったことをしている」ことです。私がやろうとしているのは、ユーザーのLAN IPアドレスを取得し、Webページに表示することです。どうして?それが私が取り組んでいるページのすべてであり、あなたについて可能な限り多くの情報を表示しているため、訪問者: http://www.whatsmyip.org/more-info-about-you/ =

ですから、実際にIPを使って何もしていません。情報目的でユーザーに見せること以外は。以前は小さなJavaアプレットを使用してこれを行っていました。かなりうまくいきました。しかし、最近では、ブラウザーは同意と信頼を何度も繰り返して、最も小さなJavaアプレットを実行するため、まったく実行しないほうがよいでしょう。

そのため、しばらくの間この機能を削除しましたが、可能であれば元に戻したいと思います。私は、コンピューターコンサルタントとして、時々実際に使用するものでした。このWebサイトにアクセスして、ネットワークが実行されているIP範囲を確認する方が、システム環境設定、ネットワーク、アクティブなインターフェイスに移動するよりも高速です。

だから私は、javascriptだけでそれを行う方法があるかどうかを望んでいますか?おそらく、JavaScriptがブラウザに地球上の地理的位置を尋ねる方法と同様に、アクセスできる新しいオブジェクトがあります。クライアントのネットワーク情報についても同様のものがありますか?そうでない場合、おそらくそれを行うための他の方法がありますか?私が考えることができる唯一の方法は、Javaアプレット、またはフラッシュオブジェクトです。どちらもやらないほうがいい。

79
l008com

結局のところ、HTML5の最近のWebRTC拡張機能により、javascriptはローカルクライアントのIPアドレスを照会できます。概念実証はこちらから入手できます。 http://net.ipcalf.com

この機能は明らかに 設計上 であり、バグではありません。しかし、物議を醸す性質を考えると、私はこの振る舞いに依存することに慎重になるでしょう。それにもかかわらず、私はそれがあなたの意図した目的に完全かつ適切に対応していると思います(ブラウザが漏らしているものをユーザーに明らかにする)。

100
afourney

Afourneyの答えに加えて、このコードはWebRTC(ChromeおよびFirefox)をサポートするブラウザーで機能します。サイトのIPを要求する機能(ユーザーの地理的位置やユーザーメディアの場合など)を実装する動きがあると聞きましたが、これらのブラウザーのいずれにもまだ実装されていません。

以下は ソースコード の修正版です。パブリックIPではなくローカルIPのみが必要なため、stun要求を行わずに行を減らしました。

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 でデモを見つけることができます

72
mido

Midoの投稿を整理し、見つかった機能を整理しました。これは、falseまたはarrayを返します。 Web開発者コンソールで配列を折りたたむ必要があることをrememberでテストすると、空の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以前では完全にnotがサポートされています。 常にオブジェクト検出を使用し、かなり古いブラウザー(例:Firefox 4、IE9、Opera 12.1)でテストし、新しいスクリプトが新しいコードを壊さないことを確認します。さらにalways標準に準拠したコードを検出first CSSプレフィックスが付いているものがある場合、標準の非プレフィックスコードを検出firstしてからフォールバック長期的なサポートは最終的には残りの部分について標準化されるためです。

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

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

WebRTC API を使用して、クライアントのローカルIPを取得できます。

ただし、ブラウザがサポートしていないか、クライアントがセキュリティ上の理由で無効にしている可能性があります。いずれにせよ、将来的にパッチが適用される可能性が高いため、長期的にはこの「ハック」に依存しないでください(Cullen Fluffy Jenningsの回答を参照)。

以下の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>
4
Linblow

ブラウザがこれを緩和するために追加する可能性のある制限と、IETFがそれに対して行っていること、およびこれが必要な理由についての詳細情報は、 IP処理に関するIETF SPEC で見つけることができます。