为什么IPAddress.MapToIPv4()抛出ArgumentOutOfRangeException?

时间:2014-05-12 12:17:45

标签: .net ipv6 ipv4 base-class-library bug-reporting

此代码在最后一行抛出ArgumentOutOfRangeException

var initAddress = IPAddress.Parse("1.65.128.190");
var ipv6Address = initAddress.MapToIPv6();
Assert.IsTrue(ipv6Address.IsIPv4MappedToIPv6);
var ipv4Address = ipv6Address.MapToIPv4();

有谁可以解释为什么MapToIPv6()和MapToIPv4()不兼容往返?

编辑:异常来自IP地址构造函数,由MapToIPv4()调用。

此外,第一行是

var initAddress = IPAddress.Parse("1.65.128.90");

不再抛出异常

edit2:当@Luaan转载这个时,我添加了标签[bug-reporting]。还添加了[bcl]。让我们看看是否有MS人员跟踪这些标签:)

edit3:在Connect https://connect.microsoft.com/VisualStudio/feedback/details/871964

报告

1 个答案:

答案 0 :(得分:18)

好的,我实际上已经验证了这一点,所以让我发布这个作为答案。

将地址映射回IPv4时,IPAddress类出错。

根据.NET参考代码,它执行此操作:

long address = 
  (((m_Numbers[6] & 0x0000FF00) >> 8) | ((m_Numbers[6] & 0x000000FF) << 8)) |
  ((((m_Numbers[7] & 0x0000FF00) >> 8) | ((m_Numbers[7] & 0x000000FF) << 8)) << 16);

任何在.NET中进行按位操作的人都应该明白这个问题 - 数字都是int。因此,移动第二个ushortm_Numbers[7])会给出一个负值,因为最重要的位是1。这意味着所有以高于127的字节结尾的IPv4地址在从IPv6映射时都会导致错误。

简单的解决方法就是:

long address = 
 (((m_Numbers[6] & 0x0000FF00) >> 8) | ((m_Numbers[6] & 0x000000FF) << 8)) 
 |
 (
  (uint)(((m_Numbers[7] & 0x0000FF00) >> 8) | ((m_Numbers[7] & 0x000000FF) << 8))
  << 16
 );

只需在执行bitshift之前将int强制转换为uint即可。

当您考虑签名类型时,按位操作可能非常棘手。我想这些代码是从C ++库中复制而来的,这个问题不会出现。