2011-08-29 25 views
11

我已經在網上現在爬行約5小時,找不到我的問題的解決方案(防火牆和路由器後面):檢查IP是在LAN

我公司正在開發的教育遊戲我正在使用Monotorrent爲它編寫一個autoupdater。遊戲將在學校中使用,但由於大多數學校只有非常薄弱的​​互聯網連接,網絡中只有一臺計算機可以從httpseeder下載,而其他計算機應該從httpseed下載的一臺計算機中汲取教訓。

所以我從跟蹤器中獲取大量的IP地址,只需要過濾出局域網中的IP地址。

當然,學校有時對防火牆比較嚴格,學校裏的一些計算機之間會有大量的路由器和交換機。

我已經嘗試過大多數解決方案,像

NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces(); 

    foreach (NetworkInterface iface in interfaces) 
    { 
     IPInterfaceProperties properties = iface.GetIPProperties(); 

     foreach (UnicastIPAddressInformation address in properties.UnicastAddresses) 
     { 
      Console.WriteLine(
       "{0} (Mask: {1})", 
       address.Address, 
       address.IPv4Mask 
       ); 
     } 
    } 

或類似的技術只提供路由器/交換機/任何信息。

所以簡而言之,我想要做的是檢查給定的IP是否可以通過局域網訪問。

我真的很感激任何幫助,因爲這個功能是剩下的最後一個:)

+0

包含遊戲連接到您的互聯網服務器的所有計算機? – Yahia

+2

有限的IP地址允許內部使用私有子網。這不足以表明身份嗎?使用公共IP地址然後對其進行防火牆是非常罕見的,因爲您不想浪費IPv4地址。 IPv6是完全不同的問題。 – jishi

+0

@jishi你假設學校的網絡是根據建議設置的。雖然推薦使用私人範圍,但是沒有任何東西阻止您使用公共的範圍。 –

回答

17

您可以利用TTL。爲1的TTL,數據包將無法使其向互聯網:

private static bool IsLanIP(IPAddress address) 
{ 
    var ping = new Ping(); 
    var rep = ping.Send(address, 100, new byte[] { 1 }, new PingOptions() 
    { 
     DontFragment = true, 
     Ttl = 1 
    }); 
    return rep.Status != IPStatus.TtlExpired && rep.Status != IPStatus.TimedOut && rep.Status != IPStatus.TimeExceeded; 
} 

但是,請記住,它被稱爲IPv4面膜是有原因的 - 你可以使用它作爲一個(所以這裏您的算法解決方案):

private static bool IsLanIP(IPAddress address) 
{ 
    var interfaces = NetworkInterface.GetAllNetworkInterfaces(); 
    foreach (var iface in interfaces) 
    { 
     var properties = iface.GetIPProperties(); 
     foreach (var ifAddr in properties.UnicastAddresses) 
     { 
      if (ifAddr.IPv4Mask != null && 
       ifAddr.Address.AddressFamily == AddressFamily.InterNetwork && 
       CheckMask(ifAddr.Address, ifAddr.IPv4Mask, address)) 
       return true; 
     } 
    } 
    return false; 
} 

private static bool CheckMask(IPAddress address, IPAddress mask, IPAddress target) 
{ 
    if (mask == null) 
     return false; 

    var ba = address.GetAddressBytes(); 
    var bm = mask.GetAddressBytes(); 
    var bb = target.GetAddressBytes(); 

    if (ba.Length != bm.Length || bm.Length != bb.Length) 
     return false; 

    for (var i = 0; i < ba.Length; i++) 
    { 
     int m = bm[i]; 

     int a = ba[i] & m; 
     int b = bb[i] & m; 

     if (a != b) 
      return false; 
    } 

    return true; 
} 
+0

第二個解決方案似乎工作非常感謝,雖然我不確定TTL解決方案,糾正我,如果我錯了(我真的不知道),但不是ttl遞減時,通過本地交換機或路由器?因爲如果是這樣,它不會落後於本地交換機嗎? – Squirrel

+0

@Squirrel據我所知只有在通過路由器(不是交換機或集線器)時纔會減少;而局域網應該只有一個路由器。但是,掩模解決方案是最不可能給出錯誤結果的。 –

+0

只要檢查IP是否在同一個「局域網」中並不真正知道你是否在局域網上,或者你恰好有一個ISP爲你提供IP地址。你可能是一個/ 24或甚至一個/ 22網絡的一部分與公共IP,那麼你是「不」在局域網上,只是同一個ISP。 – jishi

1

通常喜歡10.xxx(A類)或192.xxx(C類)的IP任何可以安全地假定爲在私人局域網內。 IP Classications

+6

假設是一條非常糟糕的路線。用戶是白癡,他們做各種瘋狂的東西。 –

+2

@Jonathan作爲一個用戶,我很生氣。作爲一名開發人員,我同意。 – Rotem

1

您可能會使用的一件事是嘗試使用多播的客戶端之間的通信。大多數防火牆和路由器都會阻止組播流量(最明顯的是ISP),這意味着如果沒有其他客戶端位於局域網上,您將無法加入多播組。一個啞巴交換機會傳輸流量,一個三層交換機可能會阻塞它,或者可能允許它取決於配置。無論哪種方式,如果第3層交換機阻止它,那麼您可能總是位於不同的子網上,因此所有其他選項都會失敗。

想到的一項技術是SSDP(http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol),這將爲您的目標提供相當好的服務,我相信。這樣你就不需要知道你是否在局域網上,只要搜索另一個正在下載的節點,如果找不到,就開始下載。

由於SSDP是uPnP中使用的標準,您可能會找到可以使用的體面實現。