2014-04-30 42 views
2

给定目标URI,如何以编程方式确定该URI的HTTP GET是否会向本地计算机发出请求?如何以编程方式确定URI,主机名或IP地址是否属于本地主机?

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

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

问题不像看URI那样简单,看域名是“本地主机”,还是其IP地址是127.0.0.1(或127.0.1.1或127. *),因为:(a)目标URI可能使用解析为当前机器上IP地址的完全限定域名(例如,foo.example.com);和(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,那么这样做也足够了。我不需要一种可以保证在任何情况下都能正常工作的解决方案,但是如果它适用于大多数情况,那将会很好。

+0

它也可以指向的IP地址负载均衡器将重写数据包以指向本地机器。 – derobert

+0

第一种情况的随机建议:在您的应用生成的请求中,设置一些自定义HTTP标头。收到请求时检查它,如果存在,则返回错误。请记住,您可以根据需要在自定义标题中放置尽可能多的跟踪信息(例如,请求所经历的所有节点 - 如果node2获得node1请求,则会发送包含node2和node1的标头; Node3应该是OK ,但节点1或节点2会说“否”) – derobert

+0

将包含唯一字符串(例如系统主机ID或CPUID的md5散列)的注释添加到/robots.txt。通过http检索并将其与本地文件系统中的robots.txt进行比较。 –

回答

-1
start cmd: # ip route get 192.168.1.2 
local 192.168.1.2 dev lo src 192.168.1.2 
    cache <local> 
+0

我不明白你的答案。它是用编程语言编写的吗?如果是这样,什么语言? – DavidBooth

+1

@DavidBooth这是一个命令。你运行'ip route get 1.2.3.4'。 @HaukeLaging可以使用一点解释。例如,它来自IProute2,你应该寻找'本地'等。 – Patrick

+0

@DavidBooth我想如果你不明白我的答案(并期望一些“真正prgramming”),那么你在这个网站上是错误的。然后你应该问Stackoverflow。 –

1

有一种幼稚解决这个,被描述为,

  1. 在问题提取从URI中的完全合格的域名,主机名或IP地址。
  2. 解析为IP地址
  3. 比较,对IP列表在当前主机的地址
  4. 如果有匹配,那么这个URI指向该主机

这工作,因为只要,

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

不过,我觉得你的问题太宽泛了,你会更好地分解为两个问题,

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

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

0

因为我没有找到更好的解决方案,所以我最终实现了这一点,就像@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; 
}