是否有人有一些代码可以确定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属性。
我也在同一时间在MSDN论坛上发布了同样的问题。 1800多个观点,而不是一个回复。猜猜我不是唯一一个对此感到好奇的人。
答案 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
),但如果您最近没有与该主持人交谈,则可能不包含您要查找的条目。
您需要考虑的其他潜在问题:
netsh interface ipv6 show siteprefixes
可能有所帮助。看起来Windows实际上可能更像IPv4,而不是标准所期望的。编辑:这听起来像检查邻居表将是您执行此操作的阻力最小的路径;如果您正在接受来自Intranet的连接,然后转身并检查邻居表,则可以合理地确保如果邻居是本地的,则它将存在于表中。如果检查邻居表,要小心,只查看LAN接口的邻居表。 (ISATAP界面,默认安装在许多Windows系统上,将整个IPv4互联网公开为链接本地“子网”。)
同样,IPv6地址没有“网络掩码”的概念,因为链接前缀表与地址分配是分开的。 然而,如果您的服务器位于某处,则可能99%确定它位于 / 64 。 (虽然你必须要小心;如果它本身就是一个隧道端点,有时我看到为6in4隧道分配了更长的前缀)所以一个快速而肮脏的算法将是:
修改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以外的子网大小。