【问题标题】:How can I programmatically determine whether a URI, hostname or IP address is to the local host machine?如何以编程方式确定 URI、主机名或 IP 地址是否属于本地主机?
【发布时间】:2014-06-16 15:49:18
【问题描述】:

给定一个目标 URI,我如何以编程方式确定该 URI 的 HTTP GET 是否会向本地机器发出请求?

上下文:我需要这样做有两个原因。一是我有一个响应 HTTP 请求的 mod_perl2 应用程序。在这样做时,它有时需要发出 HTTP 请求以从目标 URI 中检索一些数据。为了避免 HTTP 请求的无限递归,如果目标 URI 实际上会解析到当前机器,我需要避免发出 HTTP 请求。这是为了防止用户意外射中自己的脚。它并非旨在作为安全检查。

第二个原因是,如果我的应用程序收到一个 HTTP 请求,我需要使用请求 URI 作为键来查找一些元数据。问题是几个 URI 同义词中的任何一个都可以用作创建元数据的键,所以我需要一种方法来解析同义词,但仅限于本地主机上的 URI。

问题并不像查看 URI 以查看域是“localhost”,还是它的 IP 地址是 127.0.0.1(或 127.0.1.1 或 127.*)那么简单,因为:(a)目标URI 可能使用完全限定的域名(例如 foo.example.com),它解析为当前机器上的 IP 地址; (b) 一台机器可以有多个 IP 地址。

操作系统必须拥有解决此问题所需的信息,因为它必须知道它所侦听的 IP 地址和端口。 This post 讨论了试图确定本地机器的 IP 地址(或地址,因为它可能有多个)的问题。也许我可以这样做来确定本地机器的 IP 地址,然后也许我可以将这些 IP 地址与目标 URI 中的 IP 地址(或 URI 域的 gethostbyname 返回的 IP 地址)进行比较。我真的需要这样做吗?这种方法有问题吗?有没有更好的办法?

This post 表示 C# 有一个函数 HttpContext.Current.Request.IsLocal 来做我需要的,但是我在 perl 中找不到类似的东西。

我之前在 perlmonks.org 上 asked this question(因为我使用的是 perl)但没有找到令人满意的答案。如果在 Linux 上通常可用的其他一些编程语言(例如 C、bash 或 python)中有可用的解决方案,那也足够了。我不需要保证在所有可能情况下都有效的解决方案,但如果它适用于大多数情况,那就太好了。

【问题讨论】:

  • 它还可以指向负载均衡器的 IP 地址,该负载均衡器将重写数据包以指向本地机器。
  • 第一种情况的随机建议:在您的应用程序生成的请求中,设置一些自定义 HTTP 标头。收到请求时检查它,如果存在则返回错误。请记住,您可以根据需要在自定义标头中放置尽可能多的跟踪信息(例如,请求通过的所有节点 - 如果 node2 收到 node1 请求,它会发送包含 node2 和 node1 的标头。Node3 可以,但 node1 或 node2 都会说“不”)
  • 在 /robots.txt 中添加一个包含唯一字符串(例如系统 hostid 或 CPUID 的 md5 哈希)的注释。通过 http 检索它并与本地文件系统中的 robots.txt 进行比较。
  • 到目前为止,HTTP 标头的想法似乎是最好的。 /robots.txt 的想法与需要额外的 HTTP 请求类似。但理想情况下,我希望完全避免额外的 HTTP 请求,即使它在负载均衡器存在的情况下无法正常工作。
  • .NET HttpRequest.IsLocal "如果请求发起者的 IP 地址是 127.0.0.1 或者请求的 IP 地址与服务器的 IP 地址相同,则 IsLocal 属性返回 true。"

标签: networking routing hostname interface url


【解决方案1】:

由于我没有找到更好的解决方案,我最终几乎完全按照@EightBitTony 和 perlmonks 上的其他人的建议实施了这个。将主机从URI中取出后,可以使用perl URI模块完成,下面是我用来判断主机是否为本地的perl代码:

#! /usr/bin/perl -w

use strict;

use Socket;
use IO::Interface::Simple;

print "127.0.1.1  is local\n" if &IsLocalHost("127.0.1.1");
print "google.com is local\n" if &IsLocalHost("google.com");
exit 0;

################ IsLocalHost #################
# Is the given host name, which may be either a domain name or
# an IP address, hosted on this local host machine?
# Results are cached in a hash for fast repeated lookup.
sub IsLocalHost
{
my $host = shift || return 0;
our %isLocal;   # Cache
return $isLocal{$host} if exists($isLocal{$host});
my $packedIp = gethostbyname($host);
if (!$packedIp) {
    $isLocal{$host} = 0;
    return 0;
    }
my $ip = inet_ntoa($packedIp) || "";
our %localIps;      # Another cache
%localIps = map { ($_, 1) } &GetIps() if !%localIps;
my $isLocal = $localIps{$ip} || $ip =~ m/^127\./ || 0;
# TODO: Check for IPv6 loopback also.  See:
# http://ipv6exchange.net/questions/16/what-is-the-loopback-127001-equivalent-ipv6-address
$isLocal{$host} = $isLocal;
return $isLocal;
}

################ GetIps #################
# Lookup IP addresses on this host.
sub GetIps
{
my @interfaces = IO::Interface::Simple->interfaces;
my @ips = grep {$_} map { $_->address } @interfaces;
return @ips;
}

【讨论】:

    【解决方案2】:

    对此有一个简单的解决方案,描述为,

    1. 从相关 URI 中提取完全限定的域名、主机名或 IP 地址。
    2. 将其解析为 IP 地址
    3. 将其与当前主机上的 IP 地址列表进行比较
    4. 如果匹配,则此 URI 指向此主机

    只要这样就可以了,

    1. URI 没有解析到另一个主机,然后重定向到这个主机
    2. URI 无法解析为负载平衡器,然后负载平衡器会平衡回此主机
    3. 主机没有使用可以处理请求的代理(缓存代理)或链中的其他设备。

    但是,我认为您的问题过于宽泛,您最好将其分解为两个问题,

    1. 如何从 URI 中提取 IP 地址、主机名或 FQDN(并在编程网站上询问)
    2. 如何枚举单个主机上的所有 IP 地址(如果该主机是 Linux 服务器,请在此处提问)。

    这不是一个真正的答案,但评论太长了,我怀疑你的问题将被关闭。

    【讨论】:

      【解决方案3】:
      start cmd: # ip route get 192.168.1.2
      local 192.168.1.2 dev lo  src 192.168.1.2 
          cache <local>
      

      【讨论】:

      • 我不明白你的回答。它是用编程语言编写的吗?如果有,是什么语言?
      • @DavidBooth 这是一个命令。你运行ip route get 1.2.3.4。 @HaukeLaging 可以稍微解释一下。比如它来自IProute2,你应该寻找local等。
      • @DavidBooth 我猜如果你不理解我的回答(并且期望一些“真正的编程”)那么你在这个网站上是错误的。你应该在 Stackoverflow 上询问。
      • -1 我猜这不是帕特里克要求的那种信息
      • @miracle173 我很高兴被在 unix.sx 上谈论 .NET 的人评判。现在让我们把这些旧时的东西从这里拿走。
      猜你喜欢
      • 1970-01-01
      • 2014-12-19
      • 2014-12-02
      • 2014-04-12
      • 1970-01-01
      • 2013-03-10
      • 2014-10-13
      • 2012-04-12
      • 1970-01-01
      相关资源
      最近更新 更多