什么是Request.UserHostName实际返回,是否可以将其转换为我可以获得主机条目的东西?

时间:2012-11-28 09:06:23

标签: c# .net asp.net-mvc

我想我的答案可能是this is not possible,但如果不是这样的话......

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

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

一般情况下这是好的,除非我遇到SocketException来自Dns.GetHostEntry来自“未找到主持人”Request.UserHostName的情况。

真正奇怪的是,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,一个私有和一个公共),但它们都不是从Dns.GetHostEntry返回的地址。

如果我将上述测试应用程序打印的任何地址传入{{3}}方法,我会得到合理的价值。

那么,有没有什么方法可以从这个不是公共的,也不是任何私有的奇怪的IP地址,到我可以获得它的主机条目而没有例外(这是什么地址) ?

顺便说一下,在HTTP消息中,根据我的意思,没有X_FORWARD_FOR标头或其他任何我可以识别客户端的标题?

问题背景

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

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

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

3 个答案:

答案 0 :(得分:8)

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

使用UserHostAddress属性获取IP地址。这是你能够可靠地发现的最多。一旦你有了,你可以尝试将IP转换为主机名,但这并不总是可行。

答案 1 :(得分:4)

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

答案 2 :(得分:0)

请确保您在很多情况下可能(部分)失败的情况下阅读了Dns.GetHostEntry上的“备注”部分:

  

备注

     

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

     

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

     

如果找不到主机名,则返回SocketException异常   值为11001(Windows套接字错误WSAHOST_NOT_FOUND)。这个   如果DNS服务器未响应,则可以返回异常。这个   如果名称不是官方主机,也可以返回异常   名称或别名,或者在查询的数据库中找不到该名称或别名。

     

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

     

GetHostEntry方法假定如果在   应用程序需要IPHostEntry的hostNameOrAddress参数   返回所有属性集的实例。这些特性   包括AddressList,Aliases和HostName。结果,   GetHostEntry方法的实现显示以下内容   传递IP字符串文字时的行为:

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

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

     

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

     

GetHostAddresses方法对于IP具有不同的行为   文字。如果上面的步骤#1成功(成功解析为IP   地址),该地址将立即返回。有   没有尝试反向查找。

     如果本地计算机未安装IPv6,则会从GetHostEntry方法的结果中过滤

IPv6地址。结果,有可能找回一个空的   IPHostEntry实例(如果仅IPv6结果可用于   hostNameOrAddress.parameter。

     

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