你能通过JavaScript获得用户本地局域网IP地址吗?

时间:2013-11-25 13:46:30

标签: javascript ip-address

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

所以我实际上并没有使用IP进行任何操作,只是出于提供信息的目的向用户显示。我曾经通过使用一个小的Java小程序来做到这一点。它工作得很好。但是现在,浏览器会让你多次同意和信任,甚至可以运行最小的java applet,我根本不会运行它。

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

所以我想知道,希望是否有一些方法可以单独在javascript中完成它?也许你可以访问一些新对象,类似于javascript可以询问浏览器在地球上的地理位置的方式。也许客户网络信息有类似之处?如果没有,也许还有其他一些方法可以完成吗?我能想到的唯一方法是java applet或flash对象。我宁愿不做其中任何一个。

8 个答案:

答案 0 :(得分:99)

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

此功能显然是by design,并不是错误。但是,鉴于其有争议的性质,我会谨慎依赖这种行为。尽管如此,我认为它完全适当地解决了您的预期目的(向用户透露他们的浏览器漏洞)。

答案 1 :(得分:70)

除了afourney的答案,此代码适用于支持WebRTC(Chrome和Firefox)的浏览器。我听说有一个动作正在实现一个功能,使网站请求IP(如用户的地理位置或用户媒体),虽然它还没有在这些浏览器中实现。< / p>

以下是link的修改版本,缩小了行数,没有发出任何眩晕请求,因为您只希望本地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。

您可以在 - &gt;找到演示。 source code

答案 2 :(得分:6)

我清理了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)中进行测试,并确保您的新脚本不会破坏您的新代码。此外总是检测符合标准的代码首先所以如果有什么说CSS前缀检测标准的非前缀代码首先然后退回因为长期支持最终将标准化为其余的支持。

答案 3 :(得分:5)

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

答案 4 :(得分:3)

您可以找到有关浏览器可能添加哪些限制以缓解此问题的更多信息,以及IETF正在做些什么以及为什么需要IETF SPEC on IP handling

答案 5 :(得分:3)

WebRTC API可用于检索客户端的本地IP。

但是,浏览器可能不支持它,或者客户端可能出于安全原因已将其禁用。无论如何,从长远来看,不应依赖此“ hack”,因为将来可能会对其进行修补(请参阅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>

答案 6 :(得分:3)

internal-ip中已支持!

可以使用RTCPeerConnection。在getUserMedia permission is required这样的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)
            }
        })
    })
}

答案 7 :(得分:0)

Chrome 76 +

去年,我使用Linblow的答案(2018年10月19日)通过javascript成功发现了我的本地IP。但是,最近的Chrome更新(76?)已经采用了这种方法,因此它现在返回的是模糊的IP,例如:return view('index')->with(['image' => $image]);

如果您完全控制浏览器,则可以通过在Chrome标记中将其关闭,方法是在地址栏中输入以下内容来撤消该行为:

1f4712db-ea17-4bcf-a596-105139dfd8bf.local

并禁用标志chrome://flags

就我而言,我需要TamperMonkey脚本的IP来确定我的当前位置,并根据自己所在的位置进行其他操作,因此我可以完全控制自己的浏览器。更改Anonymize local IPs exposed by WebRTC设置可以解决问题。

来源:

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

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

相关问题