我想使用客户端 Javascript 来执行从客户端计算机上看到的 DNS 查找(主机名到 IP 地址)。那可能吗?
16 回答
编辑:这个问题让我很痒,所以我在 Google App Engine 上建立了一个 JSONP 网络服务,它返回客户端的 IP 地址。用法:
<script type="application/javascript">
function getip(json){
alert(json.ip); // alerts the ip address
}
</script>
<script type="application/javascript" src="http://jsonip.appspot.com/?callback=getip"> </script>
是的,不需要服务器代理。
纯JS不行。如果您在打印它的同一域下有一个服务器脚本,您可以发送一个 XMLHttpRequest 来读取它。
我知道很久以前有人问过这个问题,但我想我会提供一个更新的答案。
HTTPS 上的 DNS (DoH)
您可以通过 HTTPS 向支持它的 DNS 解析器发送 DNS 查询。RFC 8484中描述了 DOH 的标准。
这与所有其他答案所暗示的类似,只是 DoH 实际上是 HTTPS 上的 DNS 协议。它也是一个“提议的”互联网标准,并且变得非常流行。例如,一些主流浏览器要么支持它,要么计划支持它(Chrome、Edge、Firefox),微软正在将它构建到他们的操作系统中。
DoH 的目的之一是:
允许 Web 应用程序以与跨源资源共享 (CORS) 一致的安全方式通过现有浏览器 API 访问 DNS 信息
有一个开源工具专门用于从称为dohjs的 Web 应用程序中进行 DNS 查找。它执行RFC 8484中所述的DNS over HTTPS (DoH) 有线格式查询。它同时支持 GET 和 POST 方法。
全面披露:我是 dohjs 的贡献者。
在这里可以找到另一个具有类似功能的 JavaScript 库 - https://github.com/sc0Vu/doh-js-client。我没有亲自使用过这个,但我认为它也可以在客户端工作。
DNS over HTTPS JSON API
如果您不想打扰 DNS 有线格式,Google 和 Cloudflare 都为基于 HTTPS 的 DNS 提供 JSON API。
- 谷歌的端点:https ://dns.google/resolve ?
- 谷歌的 JSON API 文档:https ://developers.google.com/speed/public-dns/docs/doh/json
- Cloudflare 的端点:https ://cloudflare-dns.com/dns-query ?
- Cloudflare 的 JSON API 文档:https ://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/
使用 Google 的 JSON DOH API 查找 example.com 的示例 Javascript 代码:
var response = await fetch('https://dns.google/resolve?name=example.com');
var json = await response.json();
console.log(json);
DOH GET 和 POST 的 RFC 中带有线格式的示例
以下是 RFC 为 GET 和 POST 提供的示例(请参阅https://www.rfc-editor.org/rfc/rfc8484#section-4.1.1):
获取示例:
第一个示例请求使用 GET 请求“www.example.com”。
:method = GET
:scheme = https
:authority = dnsserver.example.net
:path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB
accept = application/dns-message
发布示例:
使用 POST 方法对“www.example.com”进行相同的 DNS 查询将是:
:method = POST
:scheme = https
:authority = dnsserver.example.net
:path = /dns-query
接受 = application/dns-message
content-type = application/dns-message
content-length = 33
<33字节由以下十六进制编码表示> 00 00 01 00 00 01 00 00 00 00 00 00 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00 01
其他发送 DOH 查询的地方
您可以在几个地方找到一些支持 DNS over HTTPS 的公共 DNS 解析器列表:
- DNSCrypt在他们的 Github 上有一个很长的公共 DoH 和 DNSCrypt 解析器列表,在https://dnscrypt.info/public-servers/上有一个很好的交互式版本列表
- 维基百科 - 公共递归名称服务器的比较
- 在 Curl 的 wiki 上列出
- dnsprivacy.org 上的(简短)列表
Of the above resources, I'd say that the list on Curl's wiki and the DNSCrypt list are are probably the most complete and the most frequently updated. Curl's page also includes a list of open source tools for DoH (servers, proxies, client libs, etc).
javascript 标准库中没有主机或 IP 地址的概念。因此,您必须访问一些外部服务才能为您查找主机名。
我建议托管一个 cgi-bin,它会查找主机名的 ip 地址并通过 javascript 访问它。
很晚了,但我想很多人还是会通过“谷歌航空”登陆这里。一种现代方法是使用不需要服务器支持的 WebRTC。
https://hacking.ventures/local-ip-discovery-with-html5-webrtc-security-and-privacy-risk/
下一个代码是来自http://net.ipcalf.com/的复制和粘贴
// NOTE: window.RTCPeerConnection is "not a constructor" in FF22/23
var RTCPeerConnection = /*window.RTCPeerConnection ||*/ window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
if (RTCPeerConnection) (function () {
var rtc = new RTCPeerConnection({iceServers:[]});
if (window.mozRTCPeerConnection) { // FF needs a channel/stream to proceed
rtc.createDataChannel('', {reliable:false});
};
rtc.onicecandidate = function (evt) {
if (evt.candidate) grepSDP(evt.candidate.candidate);
};
rtc.createOffer(function (offerDesc) {
grepSDP(offerDesc.sdp);
rtc.setLocalDescription(offerDesc);
}, function (e) { console.warn("offer failed", e); });
var addrs = Object.create(null);
addrs["0.0.0.0"] = false;
function updateDisplay(newAddr) {
if (newAddr in addrs) return;
else addrs[newAddr] = true;
var displayAddrs = Object.keys(addrs).filter(function (k) { return addrs[k]; });
document.getElementById('list').textContent = displayAddrs.join(" or perhaps ") || "n/a";
}
function grepSDP(sdp) {
var hosts = [];
sdp.split('\r\n').forEach(function (line) { // c.f. http://tools.ietf.org/html/rfc4566#page-39
if (~line.indexOf("a=candidate")) { // http://tools.ietf.org/html/rfc4566#section-5.13
var parts = line.split(' '), // http://tools.ietf.org/html/rfc5245#section-15.1
addr = parts[4],
type = parts[7];
if (type === 'host') updateDisplay(addr);
} else if (~line.indexOf("c=")) { // http://tools.ietf.org/html/rfc4566#section-5.7
var parts = line.split(' '),
addr = parts[2];
updateDisplay(addr);
}
});
}
})(); else {
document.getElementById('list').innerHTML = "<code>ifconfig | grep inet | grep -v inet6 | cut -d\" \" -f2 | tail -n1</code>";
document.getElementById('list').nextSibling.textContent = "In Chrome and Firefox your IP should display automatically, by the power of WebRTCskull.";
}
托管的 JSONP 版本就像一个魅力,但它似乎在大多数日子(东部时间)的夜间会占用它的资源,所以我不得不创建自己的版本。
这就是我用 PHP 完成它的方式:
<?php
header('content-type: application/json; charset=utf-8');
$data = json_encode($_SERVER['REMOTE_ADDR']);
echo $_GET['callback'] . '(' . $data . ');';
?>
那么 Javascript 和之前完全一样,只是不是数组:
<script type="application/javascript">
function getip(ip){
alert('IP Address: ' + ip);
}
</script>
<script type="application/javascript" src="http://www.anotherdomain.com/file.php?callback=getip"> </script>
就那么简单!
旁注:如果您在任何面向公众的环境中使用它,请务必清理您的 $_GET!
有一个第三方服务提供了一个 CORS 友好的 REST API 来从浏览器执行 DNS 查找 - https://exana.io/tools/dns/
我知道这是一个老问题,但我的解决方案可能会对其他人有所帮助。
我发现让这一切变得简单的 JSON(P) 服务不会永远持续下去,但在撰写本文时,以下 JavaScript 对我来说效果很好。
<script type="text/javascript">function z (x){ document.getElementById('y').innerHTML=x.query }</script>
<script type='text/javascript' src='http://ip-api.com/json/zero.eu.org?callback=z'></script>
上面将我的服务器的 IP 写在它所在的页面上,但是可以通过将“zero.eu.org”更改为另一个域名来修改脚本以查找任何 IP。这可以在我的页面上看到:http: //meon.zero.eu.org/
正如许多人所说,您需要使用外部服务并调用它。这只会从服务器的角度为您提供 DNS 解析。
如果这足够好,并且您只需要 DNS 解析,您可以使用以下 Docker 容器:
https://github.com/kuralabs/docker-webaiodns
端点:
[GET] /ipv6/[domain]
:对给定域执行 DNS 解析并返回关联的 IPv6 地址。
{
"addresses": [
"2a01:91ff::f03c:7e01:51bd:fe1f"
]
}
[GET] /ipv4/[domain]
:对给定域执行 DNS 解析并返回相关的 IPv4 地址。
{
"addresses": [
"139.180.232.162"
]
}
我的建议是您将 Web 服务器设置为反向代理到服务器中为您的 Javascript 提供服务的特定端点上的容器,并使用您的标准 Javascript Ajax 函数调用它。
有一个 JavaScript 库DNS-JS.com就是这样做的。
DNS.Query("dns-js.com",
DNS.QueryType.A,
function(data) {
console.log(data);
});
这样做需要破坏浏览器沙箱。尝试让您的服务器进行查找并通过 XmlHttp 从客户端请求。
自 v60 以来,Firefox 有一个内置的 API,用于 WebExtensions:
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/dns/resolve
确保您可以通过使用这种 dns 方法而无需使用任何添加,只需纯 javascript,browser.dns.resolve("example.com");
但它仅与 FIREFOX 60 兼容,您可以在 MDN https://developer.mozilla.org/en-US/docs上查看更多信息/Mozilla/附加组件/WebExtensions/API/dns/resolve
出于安全原因,我认为大多数浏览器都不允许这样做,正如问题所要求的那样,在纯 JavaScript 上下文中。
也许我错过了重点,但在这里回复 NAVY 的人是浏览器如何告诉你“请求者”的 IP 地址(尽管可能只有他们的服务提供商)。
在页面中放置一个脚本标签,由调用(有 src 指向)另一个负载不平衡的服务器的客户端呈现(我意识到这意味着您需要访问第二台服务器,但是这些天托管很便宜,您可以轻松且便宜地进行设置)。
这是需要添加到客户端页面的代码类型:
在另一台服务器“someServerIown”上,您需要拥有 ASP、ASPX 或 PHP 页面;
----- 包含这样的服务器代码:
"<% Response.Write("var clientipaddress = '" & Request.ServerVariables("REMOTE_ADDR") & "';") %>" (没有外部 dbl 引号 :-))
---- 并将这段代码写回脚本标签:
var clientipaddress = '178.32.21.45';
这有效地创建了一个 Javascript 变量,您可以在页面上使用 Javascript 访问该变量。
希望您访问此 var 并将值写入准备发送回的表单控件。
当用户发布或收到下一个请求时,您的 Javascript 和/或表单将“otherServerIown”为您填写的变量的值发送回您想要的服务器。
这就是我如何绕过我们拥有的愚蠢的负载均衡器,它掩盖了客户端 IP 地址并使其看起来像负载均衡器的地址......愚蠢......愚蠢愚蠢愚蠢!
我没有给出确切的解决方案,因为每个人的情况都有点不同。然而,这个概念是合理的。另外,请注意,如果您在 HTTPS 页面上执行此操作,您的“otherServerIOwn”也必须以该安全形式交付,否则客户端会收到混合内容的警报。如果您确实有 https,请确保您的所有证书都有效,否则客户端也会收到警告。
希望它可以帮助某人!抱歉,花了一年的时间来回答/贡献。:-)
我的版本是这样的:
我的服务器上的php:
<?php
header('content-type: application/json; charset=utf-8');
$data = json_encode($_SERVER['REMOTE_ADDR']);
$callback = filter_input(INPUT_GET,
'callback',
FILTER_SANITIZE_STRING,
FILTER_FLAG_ENCODE_HIGH|FILTER_FLAG_ENCODE_LOW);
echo $callback . '(' . $data . ');';
?>
页面上的 jQuery:
var self = this;
$.ajax({
url: this.url + "getip.php",
data: null,
type: 'GET',
crossDomain: true,
dataType: 'jsonp'
}).done( function( json ) {
self.ip = json;
});
它可以跨域工作。它可以使用状态检查。正在努力。
如果客户端安装了 Java,您可以执行以下操作:
ipAddress = java.net.InetAddress.getLocalHost().getHostAddress();
除此之外,您可能必须使用服务器端脚本。