我可以使用客户端 Javascript 执行 DNS 查找(主机名到 IP 地址)吗?

Posted

技术标签:

【中文标题】我可以使用客户端 Javascript 执行 DNS 查找(主机名到 IP 地址)吗?【英文标题】:Can I perform a DNS lookup (hostname to IP address) using client-side Javascript? 【发布时间】:2010-09-11 06:48:13 【问题描述】:

我想使用客户端 javascript 来执行从客户端计算机上看到的 DNS 查找(主机名到 IP 地址)。这可能吗?

【问题讨论】:

这个问题的许多答案似乎都建议在服务器端进行解析。取决于可能不够用的用例。例如,如果您正在查找的服务正在使用 GSLB,它可能会根据用户所在的位置返回不同的 IP;因此,服务器端代码收到的响应很可能与浏览器收到的响应不同。话虽如此,对于那些关心这种差异的人来说,我还没有替代解决方案。 【参考方案1】:

编辑:这个问题让我很痒,所以我在 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 来读取它。

【讨论】:

您可以将源发布到您的网络服务吗?运行一个实例会很好。 对不起,但不得不投反对票,因为我认为它实际上并没有回答原始问题。他们只需要标准的 DNS 查找,而不是用户的公共 IP。 您的网址似乎已关闭【参考方案2】:

我知道很久以前有人问过这个问题,但我想我会提供一个更新的答案。

基于 HTTPS 的 DNS (DoH)

您可以通过 HTTPS 向支持它的 DNS 解析器发送 DNS 查询。 DOH 标准在RFC 8484 中描述。

这与所有其他答案所暗示的类似,只是 DoH 实际上是基于 HTTPS 的 DNS 协议。它也是一个“提议的”互联网标准,并且变得非常流行。例如,一些主流浏览器要么支持它,要么计划支持它(Chrome、Edge、Firefox),而微软正在将它构建到他们的操作系统中。

DoH 的目的之一是:

允许 Web 应用程序通过现有浏览器 API 以符合跨源资源共享 (CORS) 的安全方式访问 DNS 信息

有一个开源工具专门用于从称为dohjs 的 Web 应用程序进行 DNS 查找。它执行 DNS over HTTPS (DoH) 有线格式查询,如RFC 8484 中所述。它同时支持 GET 和 POST 方法。

完全披露:我是 dohjs 的贡献者。

在这里可以找到另一个具有类似功能的 JavaScript 库 - https://github.com/sc0Vu/doh-js-client。我没有亲自使用过这个,但我认为它也可以在客户端工作。

基于 HTTPS JSON API 的 DNS

如果您不想使用 DNS 有线格式,Google 和 Cloudflare 都为基于 HTTPS 的 DNS 提供 JSON API。

Google 的端点:https://dns.google/resolve? Google 的 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);

RFC 中使用有线格式的 DOH GET 和 POST 示例

以下是 RFC 为 GET 和 POST 提供的示例(请参阅 https://www.rfc-editor.org/rfc/rfc8484#section-4.1.1):

获取示例:

第一个示例请求使用 GET 请求“www.example.com”。

:方法 = GET :scheme = https :authority = dnsserver.example.net :path = /dns-query?dns=AAABAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB 接受 = 应用程序/dns 消息

POST 示例:

使用 POST 方法对“www.example.com”进行相同的 DNS 查询会 是:

:方法 = POST :scheme = https :authority = dnsserver.example.net :path = /dns-查询 接受 = 应用程序/dns 消息 内容类型 = 应用程序/dns 消息 内容长度 = 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 有一个很长的公共 DoH 和 DNSCrypt 解析器列表on their Github,以及一个很好的交互式版本列表https://dnscrypt.info/public-servers/ Wikipedia - comparison of public recursive nameservers List on Curl's wiki (short) list on dnsprivacy.org

在上述资源中,我想说 Curl wiki 上的列表和 DNSCrypt 列表可能是最完整和最频繁更新的。 Curl 的页面还包括用于 DoH 的开源工具列表(服务器、代理、客户端库等)。

【讨论】:

所有这些服务(例如 - cloudflare-dns.com/dns-query?)是否都受到浏览器内同源策略的阻止?或者在浏览器中运行的 JS 代码可以随意点击这些 DoH 服务吗?【参考方案3】:

javascript 标准库中没有主机或 IP 地址的概念。所以你必须访问一些外部服务来为你查找主机名。

我建议托管一个 cgi-bin,它会查找主机名的 ip 地址并通过 javascript 访问它。

【讨论】:

cgi-bin?那是老学校。我喜欢! 在撰写本文时(2008 年)确实如此。 6 年后情况并非如此:请参阅我在同一页面中对 WebRTC 的评论。 (不幸的是,在搜索 IP 地址问题的解决方案时,Google 仍然指向该线程,这可能会使人们误入歧途)。 @earizon - 你的答案是针对不同的问题 - 如何发现你自己的私有 IP 地址。 通过云端 CGI 的问题将是发现内部网主机 ips,而这在外部是不可能的。您必须在机器或 Intranet 上使用本地服务。 有一个新提议的 Internet 标准允许您通过 HTTPS 发送 DNS 查询(请参阅此答案 ***.com/a/58299823/9638991)。实际上,它与 cgi-bin 脚本的工作原理基本相同 :)(除了它已被 IETF 标准化并且大量大公司支持它)【参考方案4】:

很晚了,但我想很多人还是会通过“谷歌航空公司”登陆这里。一种现代方法是使用不需要服务器支持的 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.";
   

【讨论】:

这确实是 WebRTC 之前不存在的新功能 - 发现您自己的 IP 地址。但是@noahjacobson 提出了一个不同的问题——DNS 通过来自 javascript 的主机名查找 IP。 非常非常有趣,这是一个错误或设计缺陷,无论如何它会在某个时候得到纠正,因此对长期项目没有好处【参考方案5】:

托管的 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!

【讨论】:

谢谢tcole!正是我想要的:) 等一下,为什么还要使用 $_GET?就像你说的,这是一个漏洞。不能只使用: echo 'getip(' . $data . ');'; 对不起,但不得不投反对票,因为我认为它实际上并没有回答原始问题。他们只需要标准的 DNS 查找,而不是用户的公共 IP。 @SimonEast 嘿。您修改了一个 7 年前的问题。做任何你需要满足自己的事情;-) 我只是编辑了原始问题以使其更清楚,因为我最近正在研究同一个问题,但由于某种原因,这里的大多数答案实际上并不是原始海报所要求的,应该发布在一个不同的问题。【参考方案6】:

有一个第三方服务提供了一个 CORS 友好的 REST API 来从浏览器执行 DNS 查找 - https://exana.io/tools/dns/

【讨论】:

是否会因为同源策略而被浏览器屏蔽?或者 CORS 是否允许它通过任何浏览器中的任何 JS 代码?【参考方案7】:

我知道这是一个老问题,但我的解决方案可能对其他人有所帮助。

我发现使这一切变得简单的 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/

【讨论】:

我无法理解如何使用这个找到我自己的 IP 地址: 根据你的网站。 这是一个标准的“回声”工具,可在大多数网络服务器上使用。见:google.co.uk/… 这可能是唯一真正正确解决原始问题的答案,做得好。不幸的是,它不遵守从客户计算机上看到的部分,这可能(或可能不是)是一个重要的要求。 @Simon - 它在哪里说“从客户的计算机上看到”以及为什么我的答案不符合这个? @Simon - 好点,但由于通常客户端 JS 是服务器提供的,因此作者/服务器所有者很有可能会意识到这种 DNS 限制 - 对于使用第三方的作者来说可能是一个问题派对服务器。正如这里的帖子所示,现有技术难以满足这一技术的所有限制。我的意见旨在传达我发现在我的服务器上最实用的解决方案。【参考方案8】:

正如许多人所说,您需要使用外部服务并调用它。这只会从服务器的角度为您提供 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 函数调用它。

【讨论】:

【参考方案9】:

有一个 JavaScript 库 DNS-JS.com 可以做到这一点。

DNS.Query("dns-js.com",
    DNS.QueryType.A,
    function(data) 
        console.log(data);
);

【讨论】:

仍然不是从客户的角度来看。该库向dns-js.com/api.aspx 发出请求以获取IP 地址,然后解析DNS 服务器端。【参考方案10】:

这样做需要破坏浏览器沙箱。尝试让您的服务器进行查找并通过 XmlHttp 从客户端请求。

【讨论】:

【参考方案11】:

自 v60 以来,Firefox 有一个内置的 API,用于 WebExtensions:

https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/dns/resolve

【讨论】:

无论出于何种原因,browser 在 Firefox 64 测试版中不存在,所以我想知道它是否已被删除。 @Sawtaytoes:仅对WebExtensions 公开。另请注意,它需要dns 权限,并且该脚本不得作为内容脚本运行(同样,browser.dns 不会在那里公开) @Saturnus 这适用于 Firefox 扩展。有机会以某种方式对 Chrome 扩展做同样的事情吗?【参考方案12】:

确保您可以通过使用这种 dns browser.dns.resolve("example.com"); 方法而无需使用任何添加,只需纯 JavaScript 即可做到这一点 但它仅与 FIREFOX 60 兼容,您可以在 MDN https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/dns/resolve 上查看更多信息

【讨论】:

此方法仅在 WebExtension 的上下文中可用。它不能被网页使用。【参考方案13】:

出于安全原因,我认为大多数浏览器都不允许这样做,正如问题所要求的那样,在纯 JavaScript 上下文中。

【讨论】:

这不是一个答案。这应该是一条评论!【参考方案14】:

也许我错过了重点,但在这里回答 NAVY 的家伙是浏览器如何告诉你“请求者”的 IP 地址(尽管可能只是他们的服务提供商)。

在页面中放置一个脚本标记以由客户端呈现,该客户端调用(有 src 指向)另一个负载不平衡的服务器(我意识到这意味着您需要访问第二台服务器,但现在托管很便宜并且您可以轻松且廉价地进行设置)。

这是需要添加到客户端页面的代码:

在另一台服务器“someServerIown”上,您需要有 ASP、ASPX 或 PHP 页面;

----- 包含这样的服务器代码:

"" (没有外部 dbl 引号 :-))

---- 并将这段代码写回脚本标签:

   var clientipaddress = '178.32.21.45';

这有效地创建了一个 Javascript 变量,您可以在页面上使用 Javascript 访问该变量。

希望您访问此 var 并将值写入准备发送回的表单控件。

当用户发布或收到下一个请求时,您的 Javascript 和/或表单会将“otherServerIown”为您填写的变量的值发送回您希望使用的服务器。

这就是我绕过我们拥有的愚蠢负载平衡器的方法,它掩盖了客户端 IP 地址并使其看起来像负载平衡器的地址....愚蠢...愚蠢愚蠢愚蠢!

我没有给出确切的解决方案,因为每个人的情况都有点不同。然而,这个概念是合理的。另外,请注意,如果您在 HTTPS 页面上执行此操作,您的“otherServerIOwn”也必须以该安全形式提供,否则客户端会收到混合内容的警报。如果您确实有 https,请确保您的所有证书都有效,否则客户端也会收到警告。

希望它可以帮助某人!抱歉,花了一年的时间来回答/贡献。 :-)

【讨论】:

对不起,但不得不投反对票,因为我认为它实际上并没有回答原始问题。他们只需要标准的 DNS 查找,而不是用户的公共 IP。【参考方案15】:

我的版本是这样的:

我的服务器上的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;

);

它可以跨域工作。 它可以使用状态检查。正在努力。

【讨论】:

对不起,但不得不投反对票,因为我认为它实际上并没有回答原始问题。他们只需要标准的 DNS 查找,而不是用户的公共 IP。您的代码也没有清理 $_GET 这是一个很大的安全问题。 @Simon East 我认为情况更糟。看起来他们想通过 DNS 查找任何 IP。 @SimonEast 你无法证明这是一个安全问题,因为你不知道我是如何编译我的 php 的。你的严格是愚蠢的。【参考方案16】:

如果客户端安装了 Java,你可以这样做:

ipAddress = java.net.InetAddress.getLocalHost().getHostAddress();

除此之外,您可能必须使用服务器端脚本。

【讨论】:

为什么有人支持这个? java != javascript,这不是答案。 敲敲。谁在那里? (……长时间的停顿)Java Applet

以上是关于我可以使用客户端 Javascript 执行 DNS 查找(主机名到 IP 地址)吗?的主要内容,如果未能解决你的问题,请参考以下文章

HDFS写数据流程

HDFS的读写数据流程

我可以使用客户端 Javascript 执行 DNS 查找(主机名到 IP 地址)吗?

HDFS——DN整体架构与启动流程

如何在 C# 或 JavaScript 中将 DN 拆分并加入到来自 Active Directory 对象的路径

hdfs的读写过程