简体   繁体   English

您可以通过 JavaScript 获取用户本地 LAN IP 地址吗?

[英]Can You Get A Users Local LAN IP Address Via JavaScript?

I know the initial reaction to this question is "no" and "it can't be done" and "you shouldn't need it, you are doing something wrong".我知道对这个问题的最初反应是“不”和“它无法完成”和“你不应该需要它,你做错了什么”。 What I'm trying to do is get the users LAN IP address, and display it on the web page.我要做的是获取用户的 LAN IP 地址,并将其显示在网页上。 Why?为什么? Because that's what the page I'm working on is all about, showing as much information as possible about you, the visitor: https://www.whatsmyip.org/more-info-about-you/因为这就是我正在处理的页面的全部内容,尽可能多地显示有关您(访问者)的信息: https : //www.whatsmyip.org/more-info-about-you/

So I'm not actually DOING anything with the IP, other than showing it to the user for informational purposes.所以我实际上并没有对 IP 做任何事情,除了将其显示给用户以供参考。 I used to do this by using a small Java applet.我曾经通过使用一个小的 Java 小程序来做到这一点。 It worked pretty well.它工作得很好。 But these days, browser make you hit agree and trust so many times, to run even the most minor java applet, that I'd rather not run one at all.但是现在,浏览器让你多次点击同意和信任,即使是最小的 Java 小程序,我也不想运行一个。

So for a while I just got rid of this feature, but I'd like it back if possible.所以有一段时间我只是摆脱了这个功能,但如果可能的话,我希望它回来。 It was something that I, as a computer consultant, would actually use from time to time.作为一名计算机顾问,我实际上会不时使用它。 It's faster to go to this website to see what IP range a network is running on, than it is to go into System Preferences, Networking, and then whatever interface is active.访问此网站以查看网络在哪个 IP 范围内运行会比进入系统偏好设置、网络以及任何处于活动状态的接口更快。

So I'm wondering, hoping, if there's some way to do it in javascript alone?所以我想知道,希望,是否有某种方法可以单独在 javascript 中做到这一点? Maybe some new object you can access, similar to the way javascript can ask the browser where is geographic location on earth is.也许您可以访问一些新对象,类似于 javascript 可以询问浏览器地球上的地理位置在哪里。 Maybe theres something similar for client networking information?也许客户端网络信息有类似的东西? If not, perhaps theres some other way entirely to do it?如果没有,也许有其他方法可以完全做到这一点? The only ways I can think of are a java applet, or a flash object.我能想到的唯一方法是 Java 小程序或 Flash 对象。 I'd rather not do either of those.我宁愿不做其中任何一个。

As it turns out, the recent WebRTC extension of HTML5 allows javascript to query the local client IP address.事实证明,最近 HTML5 的 WebRTC 扩展允许 javascript 查询本地客户端 IP 地址。 A proof of concept is available here: http://net.ipcalf.com概念证明可在此处获得: http : //net.ipcalf.com

This feature is apparently by design , and is not a bug.此功能显然是设计使然,而不是错误。 However, given its controversial nature, I would be cautious about relying on this behaviour.但是,鉴于其有争议的性质,我对依赖这种行为持谨慎态度。 Nevertheless, I think it perfectly and appropriately addresses your intended purpose (revealing to the user what their browser is leaking).尽管如此,我认为它完美且恰当地解决了您的预期目的(向用户透露他们的浏览器正在泄漏什么)。

Update更新

This solution would not longer work because browsers are fixing webrtc leak: for more info on that read this other question: RTCIceCandidate no longer returning IP此解决方案将不再有效,因为浏览器正在修复 webrtc 泄漏:有关该问题的更多信息,请阅读另一个问题: RTCIceCandidate 不再返回 IP


In addition to afourney's answer this code works in browsers that support WebRTC (Chrome and Firefox).除了 afourney 的回答,这段代码也适用于支持 WebRTC(Chrome 和 Firefox)的浏览器。 I heard there is a movement going on to implement a feature that makes sites request the IP (like in case of user's geo-location or user-media) though it has yet to be implemented in either of those browsers.我听说有一项运动正在进行中,以实现一项功能,使站点请求 IP(例如用户的地理位置或用户媒体),尽管它尚未在这些浏览器中的任何一个中实现。

Here is a modified version of the source code , reduced the lines, not making any stun requests since you only want Local IP not the Public 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;
 }
};

We are creating a dummy peer connection for the remote peer to contact us.我们正在创建一个虚拟对等连接,以便远程对等方与我们联系。 We generally exchange ice candidates with each other and reading the ice candidates we can tell the ip of the user.我们一般会互相交换ice的候选,读取ice的候选就可以知道用户的ip。

You can find a demo at --> Demo您可以在 --> Demo 中找到演示

The WebRTC API can be used to retrieve the client's local IP. WebRTC API可用于检索客户端的本地 IP。

However the browser may not support it, or the client may have disabled it for security reasons.但是浏览器可能不支持它,或者客户端可能出于安全原因禁用了它。 In any case, one should not rely on this "hack" on the long term as it is likely to be patched in the future (see Cullen Fluffy Jennings's answer).无论如何,从长远来看,人们不应该依赖这种“黑客”,因为它可能会在未来得到修补(参见 Cullen Fluffy Jennings 的回答)。

The ECMAScript 6 code below demonstrates how to do that.下面的 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();
    };
} );

Notice I write return resolve(..) or return reject(..) as a shortcut.注意我写了return resolve(..)return reject(..)作为快捷方式。 Both of those functions do not return anything.这两个函数都不返回任何内容。

Then you may have something this :那么你可能会有这样的事情:

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

I cleaned up mido's post and then cleaned up the function that they found.我清理了mido的帖子,然后清理了他们发现的功能。 This will either return false or an array .这将返回falsearray When testing remember that you need to collapse the array in the web developer console otherwise it's nonintuitive default behavior may deceive you in to thinking that it is returning an empty 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;
}

Additionally please keep in mind folks that this isn't something old-new like CSS border-radius though one of those bits that is outright not supported by IE11 and older.另外请记住,这不是像 CSS border-radius这样的新东西,尽管 IE11 和更早版本完全支持这些位之一。 Always use object detection, test in reasonably older browsers (eg Firefox 4, IE9, Opera 12.1) and make sure your newer scripts aren't breaking your newer bits of code.始终使用对象检测,在相当旧的浏览器(例如 Firefox 4、IE9、Opera 12.1)中进行测试,并确保您的新脚本不会破坏您的新代码。 Additionally always detect standards compliant code first so if there is something with say a CSS prefix detect the standard non-prefixed code first and then fall back as in the long term support will eventually be standardized for the rest of it's existence.另外随时检测符合标准的代码,第一,所以如果有什么用说CSS前缀首先检测标准的非前缀代码,然后回落作为长期的支持最终将被标准化为它的存在的其余部分。

 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)

Chrome 76+铬 76+

Last year I used Linblow's answer (2018-Oct-19) to successfully discover my local IP via javascript.去年,我使用 Linblow 的回答(2018 年 10 月 19 日)通过 javascript 成功发现了我的本地 IP。 However, recent Chrome updates (76?) have wonked this method so that it now returns an obfuscated IP, such as: 1f4712db-ea17-4bcf-a596-105139dfd8bf.local但是,最近的 Chrome 更新(76?)已经使用了这种方法,因此它现在返回一个混淆的 IP,例如: 1f4712db-ea17-4bcf-a596-105139dfd8bf.local

If you have full control over your browser, you can undo this behavior by turning it off in Chrome Flags, by typing this into your address bar:如果您可以完全控制浏览器,则可以通过在地址栏中键入以下内容在 Chrome Flags 中将其关闭来撤消此行为:

chrome://flags

and DISABLING the flag Anonymize local IPs exposed by WebRTC并禁用标志Anonymize local IPs exposed by WebRTC

In my case, I require the IP for a TamperMonkey script to determine my present location and do different things based on my location.就我而言,我需要 TamperMonkey 脚本的 IP 来确定我的当前位置并根据我的位置执行不同的操作。 I also have full control over my own browser settings (no Corporate Policies, etc).我还可以完全控制自己的浏览器设置(无公司政策等)。 So for me, changing the chrome://flags setting does the trick.所以对我来说,改变chrome://flags设置就行了。

Sources:资料来源:

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

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

您可以找到有关浏览器可能会添加哪些限制以缓解这种情况的更多信息,以及 IETF 正在做些什么,以及为什么需要在IETF SPEC 上的 IP 处理

Now supported in internal-ip !现在支持internal-ip

An RTCPeerConnection can be used.可以使用RTCPeerConnection In browsers like Chrome where a getUserMedia permission is required , we can just detect available input devices and request for them.在像 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)
            }
        })
    })
}

Try to use the OS package to find the wifi ip.尝试使用操作系统包查找wifi ip。

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

this is another way of solution:这是另一种解决方法:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM