2014-04-30 43 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; 
}