IP地址是否与本地计算机位于同一子网上(支持IPv6)

时间:2010-09-09 18:53:38

标签: c# .net ipv6 subnet

是否有人有一些代码可以确定IP地址(IPv4或IPv6)是否与运行应用程序的计算机位于同一子网上?我已经看到了许多使用IPv4执行此操作的代码示例,但我找不到任何支持IPv6的代码。

修改

我不确定我是否理解v4和v6之间的所有差异,所以这里有一点我的问题。我有一个为Internet客户端和Intranet客户端提供服务的应用程序,也就是说有些客户端与服务器位于同一物理网络上。所以有时客户端之间有路由器,有时候没有路由器。使用IPv4,我可以通过检查客户端IP地址与服务器IP地址和子网来确定这一点,这样如果我的服务器的IP和子网掩码分别是:

192.168.123.15 255.255.255.0

服务器收到来自192.168.123.100的客户端请求我知道客户端和服务器之间没有路由器。但是,如果服务器收到来自192.168.1.100或67.7.23.4的客户端请求,我知道这些客户端和服务器之间存在路由器。在.Net中,我可以收集客户端和服务器IP地址(v4和v6)但我找不到IPv6子网掩码。

有没有办法在.Net中收集这些信息,或者我误解了IPv4和IPv6之间有什么区别?

编辑x2:

我在MS connect网站上发布了这个内容,看看它们是否正在处理,或者是否有原因导致他们没有向UnicastIPAddressInformation类添加IPv6Mask属性。

https://connect.microsoft.com/VisualStudio/feedback/details/643031/unicastipaddressinformation-class-has-no-ipv6mask-property

我也在同一时间在MSDN论坛上发布了同样的问题。 1800多个观点,而不是一个回复。猜猜我不是唯一一个对此感到好奇的人。

http://social.msdn.microsoft.com/Forums/en-US/netfxnetcom/thread/dd30e161-9be5-4d70-97c0-22e2756ce953

4 个答案:

答案 0 :(得分:3)

看起来框架没有办法做到这一点。最准确的方法是进行路由查找,但我没有看到在C#中做到这一点的好方法。 (在Linux下,我会/sbin/ip -6 route get <ipv6-addr>并查看返回的路由。)您必须在Windows中找到本机调用才能执行此操作。我没有看到命令行应用程序。

最好的方法是解析netsh interface ipv6 show route verbose的输出。您可以查找任何非/ 128前缀并对其进行最长前缀匹配。 (好吧,如果你点击/ 128,这是分配给该框的地址)

您还可以检查邻居表。 (netsh interface ipv6 show neighbors),但如果您最近没有与该主持人交谈,则可能不包含您要查找的条目。

您需要考虑的其他潜在问题:

  • Link-local addresses (fe80::/10)(以及多播,环回和未指定 - 表中的所有内容)
  • 在IPv6中,分配的地址并不意味着在链接前缀。前缀表是分开的。目前尚不清楚如何在Windows下测试,但netsh interface ipv6 show siteprefixes可能有所帮助。看起来Windows实际上可能更像IPv4,而不是标准所期望的。

编辑:这听起来像检查邻居表将是您执行此操作的阻力最小的路径;如果您正在接受来自Intranet的连接,然后转身并检查邻居表,则可以合理地确保如果邻居是本地的,则它将存在于表中。如果检查邻居表,要小心,只查看LAN接口的邻居表。 (ISATAP界面,默认安装在许多Windows系统上,将整个IPv4互联网公开为链接本地“子网”。)

同样,IPv6地址没有“网络掩码”的概念,因为链接前缀表与地址分配是分开的。 然而,如果您的服务器位于某处,则可能99%确定它位于 / 64 。 (虽然你必须要小心;如果它本身就是一个隧道端点,有时我看到为6in4隧道分配了更长的前缀)所以一个快速而肮脏的算法将是:

  • 忽略前64位为0的所有地址(本地环回)
  • 忽略所有与ff00 :: / 8(多播)匹配的地址
  • 如果地址与fe80 :: / 10匹配,则接口本地。小心这一点,因为如果你启用了ISATAP接口,“link-local”意味着“自动隧道到整个IPv4互联网”! (不好。)因此,除非您确定它们来自LAN接口,否则最好不要信任链接本地地址。 (他们不能被路由)
  • (现在是复杂的部分)确定地址是否是邻居。 (邻居查找)hack-and-slash解决方案是检查系统上配置的所有IPv6地址(通过无状态地址自动配置,DHCPv6或静态自动配置,如果可以确定)并检查前64位。 在服务器上(假设没有时髦的隧道配置了非/ 64前缀),这在极少数情况下会出现错误,因为 - 再次 - 您无法确定地址是否真的在 - 链接,除非您检查链接前缀表。 (Windows没有概念;它似乎存储在路由表中。)大多数可以配置为在以太网接口上发送路由器通告的网络设备将始终通告/ 64前缀。如果您可以检查数据包是否在LAN接口上进入,那么这将是一个错误的可能性更小。

修改2

我编写了一些代码来解析IPv6路由表并将其发布到here。它并没有解决这个问题中提出的难题,但它是朝着正确方向迈出的一步。

答案 1 :(得分:2)

IPv6中IPv4网络掩码的道德等效称为前缀长度。 (实际上,我们也喜欢在IPv4中讨论前缀长度而不是网络掩码,但有些人还没有得到备忘录。)

IPv6中没有提出IPv4的另一个缺点是默认路由器通过回答来自主机的路由器请求查询来宣传它们在链路上的存在。主机保留了他们以这种方式找到的所有默认路由器的列表以及它们的有效和首选生命周期。路由器还可以通告它们作为默认路由器的零个,一个或多个前缀,并且主机保留这些前缀的列表以及它们相关的路由器以及它们各自的有效和首选生命周期。

每个前缀在广告A和L中有两个辅助位,当它们被添加到前缀列表时,它们会被主机合并。 A = 1位表示是否允许主机自动配置具有该前缀的接口地址,而A = 0表示主机需要通过DHCPv6或手动获取具有该前缀的地址。 L = 1比特表示前缀是“在链路上”,并且主机可以使用邻居发现(ARP等效的ARP)直接通过网络发送,而L = 0表示前缀是“关闭链路”,并且主机需要将该前缀的所有流量发送到默认路由器。

长话短说:如果您想知道IPv6地址是“在链接上”那么您必须遍历IPv6前缀列​​表并将每个地址与地址进行比较,并查看L位以确保它是一个on-link前缀。唉,我只知道查看前缀列表的BSD系统方式,即sysctl(ICMPV6CTL_ND6_PRLIST, ...)。真的不确定MSFT为C#开发人员提供了什么。

是的,我意识到这不是一个完整的答案。唉。

答案 2 :(得分:2)

我一直在寻找wmi文档,试图找到ipv6前缀,我也在努力寻找它。但是,我有IPv4的工作代码。

我认为您可以放心地假设该网段的前缀为/ 64。如果这样做,您可以只比较每个地址的前8个字节。通常情况下,运行应用程序的单个本地网络将是/ 64,即使只使用2个,即使点对点链接也经常被赋予完整的/ 64范围。

答案 3 :(得分:1)

在99%的情况下,这很简单。 IPv6中的所有子网都是/ 64前缀,因此如果前缀的最左边64位是相同的,则它们位于同一子网中。

现在确实有些人正在做一些奇怪的事情并制作具有更长前缀的子网,但其中大部分是处​​理点对点电路,他们使用/ 126对两个端点进行编号然后保留/ 64包含/ 126。由于不涉及任何服务器,因此应用程序永远不会遇到这种情况。

没有充分的理由支持/ 64以外的子网大小。