JavaScript経由でユーザーのローカルLAN IPアドレスを取得できますか?


102

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

そのため、情報提供のためにユーザーに表示する以外は、実際にはIPで何もしていません。以前は、小さなJavaアプレットを使用してこれを行っていました。それはかなりうまくいきました。しかし最近では、ブラウザは同意と信頼に何度もぶつかり、最もマイナーなJavaアプレットでさえ実行するようになっているので、まったく実行したくありません。

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

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


1
あなたは答えを知っています。なぜそれを尋ねるのですか?Javaアプレットまたはフラッシュオブジェクトがユーザーによって許可されることはほとんどありません(インターネットに初めてアクセスするユーザーのみが許可する可能性があります)。そのため、一般的な解決策ではありません。ActiveXとその周辺のものはIEでのみ機能します-したがって、他のブラウザーのユーザーは影響を受けません(さらに、IEでさえ、Webサイトが厄介なことをするのを防ぐセキュリティポリシーがあります)
Alma Do

私のIPアドレスはHTTP_X_FORWARDED_FOR、そのページでキャプチャされます。
tomdemuyt 2013年

50
なぜ尋ねるのですか?たぶん、たぶん、私はすべてを知っているわけではないからです。
l008com 2013年

1
これらの人はそれをします: whatismyproxy.com
likebike

1
@likebikeいいね。彼らがこれをどのように行っているかを調べます。
Dominic Cerisano

回答:


117

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

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


1
これは役に立ちました。再度、感謝します!
Ansuraj Khadanga 2016年

7
IE、Edge、Safariではなく、ChromeとFirefoxでのみ機能します
アリ

私は自分のWAN IPを調べていましたが、このウェブサイトwhatismyip.comからもローカルIPが提供されたので、JSと関係があると思います。
シャヤン

@ali正解です。上記のウェブサイトではEdgeのローカルIPを認識できません。
シャヤン

6
Google ChromeはデフォルトでローカルIPを非表示にしています。e87e041d-15e1-4662-adad-7a6601fca9fb.localのようなものを示しています。この動作は、変数#enable-webrtc-hide-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を伝えることができる氷の候補を読み取ります。

あなたはでデモを見つけることができます- > デモ


このミドをありがとう!とても有難い。
Sujay Phadke

1
@dampee-現在、Edgeはデータチャネルをサポートしていないと思います。
MichaelB76

偽のデータチャネルとは何ですか?グーグルで参照を見つけることができません
AmazingTurtle

2
注意createOffer APIはのparamsとして代わりにsuccessCallbackとfailCallbackの約束に基づいてされるように切り替えたので、これは新しいバージョンの作業は、見えないことがあります。developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/...を
ディッケルス

10

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>

9

midoの投稿をクリーンアップし、見つかった機能をクリーンアップしました。これは、falseまたはを返しarrayます。テストするときは、Web開発者コンソールで配列を折りたたむ必要があることを忘れないでください。そうしないと、直感的でないデフォルトの動作により、空のが返されていると思われてしまう可能性があります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ただし、これらのビットの1つは、IE11以前でサポートされていません常にオブジェクト検出を使用し、かなり古いブラウザ(Firefox 4、IE9、Opera 12.1など)でテストし、新しいスクリプトが新しいコードを壊していないことを確認してください。また、常に標準規格に準拠したコードを検出する最初の CSSプレフィックスは標準的な非接頭辞コードを検出すると言うと、何かがある場合はその最初と、最終的にそれの存在の残りのために標準化される長期的なサポートのようにフォールバックします。


再宣言していますip-3行目と8行目
user2757813 '13

@Anu WebRTCはInternet Explorer 15(または「エッジ15」)まで導入されなかったため、導入されていません。そのため、上記の4行目でオブジェクトが存在しない場合、関数はfalseを返します。IEでこれを達成する別の方法がある場合、私は現時点ではそれを知りません。
John

@John-戻り値をどのようにphp変数に渡すのですか?非表示の投稿を介して?
MarcoZen

@MarcoZenこの<input name="example1" type="hidden" value="whatever" />ような状況では、AJAX POSTを使用することも使用することもできます。ajax()ここで自分の機能を研究することを強くお勧めします:jabcreations.com/docs/javascript
John

一部のブラウザー(Chromeなど)がIPの提供をブロックしていることがわかりました。ビデオ/オーディオの権限が要求されていない場合、同じコードがmDNSホスト名に解決されるようになりました。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)


エディターオプションを使用して、コードを適切にフォーマットしてください。
31piy 2017年

3
いくつかのコードをドロップするだけでなく、彼とあなたのコードで何が行われているのかを説明するのもよいでしょう。質問の作成者や他のユーザーを支援します。それがうまくいけばいいのですが、私の考えでは、なぜそれがより重要であるかを知ることが重要です。
davejal 2017年

IE互換のソリューションはありますか?
Anu

1
コメントは、この資料のコピーペーストです:ourcodeworld.com/articles/read/257/...
Darkshifty

一部のブラウザー(Chromeなど)がIPの提供をブロックしていることがわかりました。ビデオ/オーディオの権限が要求されていない場合、同じコードがmDNSホスト名に解決されるようになりました。groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
Christoph Bimminger

5

Chrome 76以降

昨年、私はLinblowの回答(2018-Oct-19)を使用して、javascript経由でローカルIPを発見しました。ただし、最近のChromeの更新(76?)では、この方法が採用され、次のような難読化されたIPが返されるようになりました。1f4712db-ea17-4bcf-a596-105139dfd8bf.local

ブラウザを完全に制御できる場合は、アドレスバーに次のように入力して、Chromeフラグでオフにすることでこの動作を元に戻すことができます。

chrome://flags

フラグを無効にする Anonymize local IPs exposed by WebRTC

私の場合、TamperMonkeyスクリプトが現在の場所を特定し、自分の場所に基づいてさまざまなことを行うには、IPが必要です。また、自分のブラウザ設定を完全に制御できます(企業ポリシーなどはありません)。したがって、私にとっては、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は返されるはずです。
Christoph Bimminger


0

RTCPeerConnection使用することができます。getUserMedia許可が必要なChromeのようなブラウザで、使用可能な入力デバイスを検出して要求するだけです。

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)
            }
        })
    })
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.