5

是否有人有一些代码可以确定 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 连接站点上发布了这个,看看他们是否正在处理它,或者是否有原因他们没有向 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

4 回答 4

3

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

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

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

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

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

于 2011-02-11T23:33:02.147 回答
3

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

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

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

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

  • 链路本地地址 (fe80::/10)(以及多播、环回和未指定 - 表中的所有内容)
  • 事实上,在 IPv6 中,分配的地址并不意味着链接上的前缀。前缀表是单独的。目前尚不清楚如何在 Windows 下对此进行测试,但netsh interface ipv6 show siteprefixes可能会有所帮助。看起来 Windows 实际上可能比标准预期的更像 IPv4。

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

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

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

编辑 2

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

于 2011-02-11T04:03:28.063 回答
2

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

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

于 2011-02-14T12:33:37.877 回答
1

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

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

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

于 2011-02-16T22:21:15.023 回答