2011-08-29 26 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中使用的标准,您可能会找到可以使用的体面实现。