8

我想我可能处于答案是这样的情况,this is not possible但万一不是这里……

我编写了一个ASP .NET MVC 3应用程序,我正在使用Request.UserHostName属性,然后将返回的值传递给Dns.GetHostEntry以找出当前连接的客户端的所有可能 IP 和主机名,例如:

var clientAddress = Request.UserHostName;
var entry = Dns.GetHostEntry(clientAddress);

一般来说,这很好,除了我从Dns.GetHostEntry调用 中得到“找不到主机” SocketException的情况。

真正奇怪的是,从Request.UserHostName属性返回的地址不是公共地址或任何私有地址。为了证明这一点,我在有问题的客户端机器上运行了这段代码......

var host = Dns.GetHostEntry(Dns.GetHostName());

foreach (var a in host.Aliases)
{
    Console.WriteLine("alias '{0}'", a);
}

foreach (var a in host.AddressList)
{
    Console.WriteLine("ip address '{0}'", a);
}

// ...from http://stackoverflow.com/a/2353177/1039947...
String direction = "";
WebRequest request = WebRequest.Create("http://checkip.dyndns.org/");
using (WebResponse response = request.GetResponse())
{
    using (var stream = new StreamReader(response.GetResponseStream()))
    {
        direction = stream.ReadToEnd();
    }
}

int first = direction.IndexOf("Address: ") + 9;
int last = direction.LastIndexOf("</body>");
direction = direction.Substring(first, last - first);

Console.WriteLine("Public IP: '{0}'", direction);

它打印三个 IP 地址(::1、一个私有和一个公共),但它们都不是从Request.UserHostName返回的地址。

如果我将从上述测试应用程序打印的任何地址传递到Dns.GetHostEntry方法中,我会得到一个合理的值。

那么,有什么方法可以从这个既不是公共也不是任何私人的奇怪 IP 地址中获取到一个我可以毫无例外地获取它的主机条目的地址(这个地址是什么)?

顺便说一句,据我所知,在 HTTP 消息中没有 X_FORWARD_FOR 标头或其他任何我可以识别客户端的东西?

问题的背景

因此有人指出(感谢 Damien),如果我解释了为什么要问这个问题,也许有人可以提供一种替代方法,所以这里有一些背景......

我有一个要求,应该允许应用程序的管理员在配置中指定允许查看页面的单个机器 - IP 地址或机器名称 - 我可能可以删除机器名称要求,但即使他们指定配置中的 IP 地址仍然与从 UserHostName 属性返回的 IP 地址不匹配,因为他们将使用在 ping 机器名称时返回的 IP 地址。

因此,我的想法是,如果我获取 HTTP 标头中发送的任何内容并将其传递给 GetHostEntry,然后从中获取所有可能的结果(所有 IP 和主机名),看看它们中的任何一个是否与我配置的值匹配可以说“允许”,否则“不允许”(我也将删除第一个点之前的主机名部分,以涵盖这种可能性)。这种方案已经被我所遇到的这种情况吹得水泄不通了,我的 IP 地址根本不是我所期望的。

4

3 回答 3

8

客户端的主机名通常是未知的,因为它不是在 HTTP 级别传输的。服务器无法知道它。用 Fiddler 看一下 HTTP 请求,自己看看服务器可用的信息并不多(当然客户端可以伪造所有请求内容)。

使用该UserHostAddress属性获取 IP 地址。这是您可以可靠地找到的最多信息。一旦你有了它,你可以尝试将 IP 反转为主机名,但这并不总是可能的。

于 2012-11-28T15:10:20.920 回答
5

我对你的问题有更具体的回答。通过在此处检查 HttpRequest.UserHostName 的源代码,我发现它映射到名为 REMOTE_HOST 的 IIS 服务器变量,此处描述了该变量。该属性将返回客户端的 IP 地址,除非您已按照所述方式配置 IIS,在这种情况下,IIS 将执行反向 DNS 查找以尝试返回与 IP 关联的名称。

于 2016-03-15T20:20:20.480 回答
0

请务必阅读Dns.GetHostEntry的备注部分,了解它可能(部分)失败的许多情况:

评论

GetHostEntry 方法向 DNS 服务器查询与主机名或 IP 地址关联的 IP 地址。

如果将空字符串作为 hostNameOrAddress 参数传递,则此方法返回本地主机的 IPv4 和 IPv6 地址。

如果找不到主机名,则返回值为 11001 的 SocketException 异常(Windows 套接字错误 WSAHOST_NOT_FOUND)。如果 DNS 服务器没有响应,则可以返回此异常。如果名称不是正式的主机名或别名,或者在被查询的数据库中找不到它,也会返回此异常。

如果 hostNameOrAddress 参数包含 Any 或 IPv6Any,也会返回 ArgumentException 异常。

GetHostEntry 方法假定如果在 hostNameOrAddress 参数中传递 IP 文字字符串,则应用程序希望返回带有所有属性集的 IPHostEntry 实例。这些属性包括地址列表、别名和主机名。因此,当传递 IP 字符串文字时,GetHostEntry 方法的实现表现出以下行为:

  1. 该方法尝试解析地址。如果 hostNameOrAddress 参数包含合法的 IP 字符串文字,则第一阶段成功。
  2. 尝试使用 IP 字符串文字的 IP 地址进行反向查找以获取主机名。此结果设置为 HostName 属性。
  3. 来自此反向查找的主机名再次用于获取与该名称关联的所有可能 IP 地址并设置为 AddressList 属性。

对于 IPv4 字符串文字,上述所有三个步骤都可能成功。但是对于实际上属于不同主机的 IPv4 地址,可能会返回陈旧的 DNS 记录。这可能会导致第 3 步失败并引发异常(IPv4 地址有 DNS PTR 记录,但 IPv4 地址没有 DNS A 记录)。

对于 IPv6,上面的第 2 步可能会失败,因为大多数 IPv6 部署不会为 IPv6 地址注册反向 (PTR) 记录。因此,此方法可能会将字符串 IPv6 文字作为 HostName 属性中的完全限定域 (FQDN) 主机名返回。

GetHostAddresses 方法在 IP 文字方面具有不同的行为。如果上面的第 1 步成功(它成功解析为 IP 地址),则该地址会立即作为结果返回。没有尝试反向查找。

如果本地计算机没有安装 IPv6,则从 GetHostEntry 方法的结果中过滤 IPv6 地址。因此,如果只有 IPv6 结果可用于 hostNameOrAddress.parameter,则可以取回一个空的 IPHostEntry 实例。

返回的 IPHostEntry 实例的 Aliases 属性不会由此方法填充,并且始终为空。

于 2019-10-23T10:31:15.233 回答