【问题标题】:Can You Get A Users Local LAN IP Address Via JavaScript?您可以通过 JavaScript 获取用户本地 LAN IP 地址吗?
【发布时间】:2013-12-10 06:38:10
【问题描述】:

我知道对这个问题的最初反应是“不”、“不能做”和“你不应该需要它,你做错了什么”。我要做的是获取用户的 LAN IP 地址,并将其显示在网页上。为什么?因为这就是我正在处理的页面的全部内容,显示尽可能多的关于您的信息,访问者: https://www.whatsmyip.org/more-info-about-you/

所以我实际上并没有对 IP 做任何事情,除了将其展示给用户以供参考。我曾经使用一个小的 Java 小程序来做到这一点。它工作得很好。但是这些天,浏览器让你多次点击同意和信任,即使是最次要的 java 小程序也能运行,我宁愿一个也不运行。

所以有一段时间我刚刚摆脱了这个功能,但如果可能的话我希望它回来。这是我,作为一名计算机顾问,实际上会不时使用的东西。访问此网站查看网络运行的 IP 范围比进入系统偏好设置、网络以及任何处于活动状态的界面要快。

所以我想知道,希望是否有某种方法可以仅在 javascript 中做到这一点?也许您可以访问一些新对象,类似于 javascript 可以询问浏览器的方式,地球上的地理位置在哪里。也许客户端网络信息有类似的东西?如果没有,也许还有其他方法可以完全做到这一点?我能想到的唯一方法是 java applet 或 flash 对象。我宁愿不做这两件事。

【问题讨论】:

  • 你知道答案。那为什么还要问?用户不太可能允许 Java 小程序或 Flash 对象(可能只有那些刚接触 Internet 的人)——所以这不是常见情况下的解决方案。 ActiveX 和附近的东西只在 IE 中工作 - 因此,其他浏览器的用户不会受到影响(而且,更重要的是,即使在 IE 中也有一个安全策略可以防止网站做讨厌的事情)
  • 我的 IP 地址是通过该页面上的HTTP_X_FORWARDED_FOR 捕获的,只是说。
  • 那为什么要问呢?因为也许,只是也许,我什么都不知道。
  • 这些人做到了:whatismyproxy.com
  • @likebike 不错。调查他们是如何做到这一点的。

标签: javascript ip-address


【解决方案1】:

事实证明,HTML5 最近的 WebRTC 扩展允许 javascript 查询本地客户端 IP 地址。此处提供概念证明:http://net.ipcalf.com

这个功能显然是by design,并不是一个错误。然而,鉴于其有争议的性质,我会谨慎依赖这种行为。尽管如此,我认为它完美且适当地解决了您的预期目的(向用户揭示他们的浏览器正在泄漏什么)。

【讨论】:

  • 这很有帮助。再次感谢!
  • 它只适用于 chrome 和 firefox,而不适用于 IE、Edge 或 safari
  • 我正在查找我的 WAN IP,这个网站whatismyip.com 也给了我我的本地 IP,我想这与 JS 有关。
  • 谷歌浏览器默认隐藏本地IP。它显示类似于 e87e041d-15e1-4662-adad-7a6601fca9fb.local 的内容。通过在 Chrome://flags 中将变量 #enable-webrtc-hide-local-ips-with-mdns 设置为 disabled 可以更改此行为
  • 这不起作用了,对象RTCSessionDescription返回0.0.0.0作为本地ipV4地址。它一直返回本地 IP,直到 Firefox 80 左右
【解决方案2】:

更新

此解决方案将不再有效,因为浏览器正在修复 webrtc 泄漏:有关此问题的更多信息,请阅读另一个问题:RTCIceCandidate no longer returning IP


除了 afourney 的回答之外,此代码还适用于支持 WebRTC(Chrome 和 Firefox)的浏览器。我听说正在实施一项使网站请求 IP 的功能(例如在用户的地理位置或用户媒体的情况下),尽管它尚未在这两种浏览器中实现。

这是 source code 的修改版本,减少了行数,不会发出任何 stun 请求,因为您只需要本地 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;
 }
};

我们正在创建一个虚拟对等连接,以便远程对等方与我们联系。我们一般会互相交换 ice 候选项,读取 ice 候选项就可以知道用户的 ip。

你可以在 --> Demo找到一个演示

【讨论】:

  • 感谢美度!非常感谢。
  • @dampee - 我相信 Edge 目前不支持数据通道。
  • 什么是虚假数据通道?在谷歌上找不到任何参考
  • 请注意 createOffer api 已切换为基于 Promise 而不是 successCallback 和 failCallback 作为参数,因此这可能不适用于较新的版本,请参阅:developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/…
【解决方案3】:

您可以在IETF SPEC on IP handling找到更多信息,了解浏览器可能会增加哪些限制来缓解这种情况,IETF 正在做什么,以及为什么需要这样做。

【讨论】:

    【解决方案4】:

    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)

    【讨论】:

    • 请使用编辑器选项适当地格式化您的代码。
    • 如果您不仅要删除一些代码,而且还要解释他和您的代码中发生的事情,那就太好了。它可以帮助问题作者和其他用户。如果它有效就很好,但在我看来,知道为什么更重要。
    • 任何 IE 兼容的解决方案?
    • 评论是这篇文章的复制粘贴:ourcodeworld.com/articles/read/257/…
    • 刚刚发现某些浏览器(例如 Chrome)现在阻止提供 IP - 如果未请求视频/音频权限,相同的代码现在解析为 mDNS 主机名。见groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
    【解决方案5】:

    我清理了 mido 的帖子,然后清理了他们找到的功能。这将返回falsearray。在测试时记住您需要在 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 这样的新旧东西,尽管 IE11 和更早版本完全支持这些位之一。 始终使用对象检测,在相当旧的浏览器(例如 Firefox 4、IE9、Opera 12.1)中进行测试,并确保您的新脚本不会破坏您的新代码。另外总是检测符合标准的代码first,所以如果有CSS前缀检测标准的非前缀代码first然后回退因为从长远来看,支持最终将在其存在的其余部分标准化。

    【讨论】:

    • 您正在重新声明 ip - 第 3 行和第 8 行。
    • @Anu WebRTC 直到 Internet Explorer 15(或“Edge 15”)才被引入,所以没有。这就是为什么在上面的第四行中,如果不存在任何对象,该函数将返回 false。如果在 IE 中还有其他方法可以实现这一点,那么我目前不知道。
    • @John - 我们如何将返回值传递给 php 变量?通过隐藏帖子?
    • @MarcoZen 在这种情况下,您可以使用 &lt;input name="example1" type="hidden" value="whatever" /&gt; 或使用 AJAX POST。我强烈建议在这里学习我的ajax() 函数:jabcreations.com/docs/javascript
    • 刚刚发现一些浏览器(例如 Chrome)现在阻止提供 IP - 如果没有请求视频/音频权限,相同的代码现在解析为 mDNS 主机名。见groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU
    【解决方案6】:

    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>
    

    【讨论】:

      【解决方案7】:

      Chrome 76+

      去年我使用 Linblow 的回答(2018 年 10 月 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,因此您可以尝试从后台脚本中获取它。不过,从长远来看,一切都结束了。
      • 根据groups.google.com/forum/#!topic/discuss-webrtc/6stQXi72BEU,如果您实施请求音频/视频权限的解决方案,仍应返回IP。
      • 出于完全相同的原因,我一直在寻找这个,当我阅读您帖子的最后一段时,我是在寻找这个。不敢相信这在 2020 年末仍然是可能的,但很高兴它是! +1 分享。
      【解决方案8】:

      现在支持internal-ip

      可以使用RTCPeerConnection。在 Chrome 之类的浏览器中,getUserMedia permission is required,我们只能检测可用的输入设备并请求它们。

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

      【讨论】:

      • 谢谢!这正是我所需要的。只是 Javascript,没有 HTML 和可理解的代码 :)
      • 哈哈哈,所以我不得不为此允许访问我的麦克风,但它最终吐出了 hyperv vswitch 的 IP 地址
      【解决方案9】:

      尝试使用操作系统包查找wifi ip。

      const os = require('os');
      console.log('IP Address: ' + JSON.stringify(os.networkInterfaces()['Wi-Fi']).match(/"192.168.\d+.\d+"/g)[0])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-21
        • 2016-07-20
        相关资源
        最近更新 更多