Что диктует форматирование адресов IPv6 с помощью System.Net.IPAddress.ToString ()? - PullRequest
5 голосов
/ 01 февраля 2011

Встроенный метод .Net System.Net.IPAddress.ToString () ведет себя непоследовательно для адресов IPv6.

Учитывая байтовый массив 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, в некоторых средах возвращается "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", тогда как в других возвращается "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:172.172.172.172".

Я понимаю, что оба являются допустимыми форматами IPv6, но я бы хотел объяснить разницу.

Кажется, что более новые среды (Windows 7 и Server 2008 R2) с большей вероятностью будут вызывать первое поведение, поэтому я проверил очевидные различия, такие как версия .Net Framework, но не смог обнаружить шаблон.

Есть ли способ, которым я могу выбрать один формат поверх другого, или мне нужно кодировать это, чтобы получить согласованное поведение?

Код для воссоздания:

    byte[] bytes = {0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA};
    IPAddress myIP = new IPAddress(bytes);
    Console.WriteLine(myIP.ToString());

Ответы [ 3 ]

5 голосов
/ 01 февраля 2011

Изучая внутренности ToString, используя Reflector , вы можете видеть, что если определено, что ОС поддерживает IPv6 (для некоторого значения поддержки), то она откладывается до функции Win32 с именем * 1003. * WSAAddressToString , тогда как если этот флаг не установлен, он выполняет ручное форматирование (из своего внутреннего байтового массива) как:

addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[0] })).Append(':');
addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[1] })).Append(':');
addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[2] })).Append(':');
addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[3] })).Append(':');
addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[4] })).Append(':');
addressString.Append(string.Format(CultureInfo.InvariantCulture, "{0:x4}", new object[] { this.m_Numbers[5] })).Append(':');
addressString.Append((int) ((this.m_Numbers[6] >> 8) & 0xff)).Append('.');
addressString.Append((int) (this.m_Numbers[6] & 0xff)).Append('.');
addressString.Append((int) ((this.m_Numbers[7] >> 8) & 0xff)).Append('.');
addressString.Append((int) (this.m_Numbers[7] & 0xff));

, который всегда будет возвращать второй формат, который вы показали.

Установлен ли флаг «OS поддерживает IPv6», похоже, зависит от внутренних знаний в классе (версия должна быть> 2000), и это будет реальной попыткой создать сокет IPv6 - так что если вы используете XP машина с отключенным IPv6, я думаю, вы также получите этот второй формат.

1 голос
/ 25 ноября 2012

В некоторых случаях это не зависит от того, поддерживает ли ОС флаг IPv6.Я получаю эту проблему на Windows Server 2008 R2.Я пробовал это

  String ipString = "2400:3C00:3FFE:0000:0000:5EFE:8999:48AA";
  System.Net.IPAddress address;
  IPAddress.TryParse(ipString, out address);

, но address.ToString () возвращает значение "2400: 3c00: 3ffe :: 5efe: 137.153.72.170".

Но если я изменяю IP-строку на «2400: 3C00: 3FFE: 1000: 1000: 5EFE: 8999: 48AA», это работает правильно.

0 голосов
/ 27 марта 2013

В моем случае мне нужно было обеспечить согласованное форматирование, не прибегая к неуправляемому вызову API для WSAAddressToString, поэтому я написал следующий метод расширения.Может быть, это поможет кому-то в будущем:

/// <summary>
/// Returns the IPv4 or IPv6 address in standard notation. Any transitional suffix (i.e. an IPv4-like address
/// displayed in place of the final two segments of an IPv6 address) returned by .NET is converted to standard colon notation.
/// See /3443468/chto-diktuet-formatirovanie-adresov-ipv6-s-pomoschy-system-net-ipaddress-tostring.
/// </summary>
public static string ToStringNonTransitional(this System.Net.IPAddress oIPAddress)
{
    var sIP = oIPAddress.ToString();

    if (oIPAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
        return sIP; // Return IPv4 addresses untouched.

    if (oIPAddress.AddressFamily != System.Net.Sockets.AddressFamily.InterNetworkV6)
        throw new Exception(string.Format("Can't handle '{0}' in '{1}' format. (Only IPv4 or IPv6 supported.)", sIP, oIPAddress.AddressFamily.ToString()));

    if (!sIP.Contains("."))
        return sIP;

    try
    {
        var iTransitionalStart = sIP.LastIndexOf(":") + 1;
        var sTransitionalPart = sIP.Substring(iTransitionalStart);
        sIP = sIP.Substring(0, iTransitionalStart);
        var asOctects = sTransitionalPart.Split('.');
        sIP += string.Format("{0:x2}{1:x2}", Convert.ToInt16(asOctects[0]), Convert.ToInt16(asOctects[1])).TrimStart('0');
        sIP += ":" + string.Format("{0:x2}{1:x2}", Convert.ToInt16(asOctects[2]), Convert.ToInt16(asOctects[3])).TrimStart('0');

        return sIP;
    }
    catch (Exception ex)
    {
        throw new Exception("Failed to convert IPv6 address to standard notation: " + sIP, ex);
    }
}
...