您可以通过 JavaScript 获取用户本地 LAN IP 地址吗?
Posted
技术标签:
【中文标题】您可以通过 JavaScript 获取用户本地 LAN IP 地址吗?【英文标题】:Can You Get A Users Local LAN IP Address Via JavaScript? 【发布时间】: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 不错。调查他们是如何做到这一点的。
【参考方案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 的帖子,然后清理了他们找到的功能。这将返回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
这样的新旧东西,尽管 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 在这种情况下,您可以使用 <input name="example1" type="hidden" value="whatever" />
或使用 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])
【讨论】:
以上是关于您可以通过 JavaScript 获取用户本地 LAN IP 地址吗?的主要内容,如果未能解决你的问题,请参考以下文章