2011-02-01 1 views
5

La méthode .Net intégrée System.Net.IPAddress.ToString() se comporte de manière incohérente pour les adresses IPv6.Qu'est-ce qui dicte la mise en forme des adresses IPv6 par System.Net.IPAddress.ToString()?

Compte tenu du tableau d'octets 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, dans certains environnements "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa" est retourné, alors que d'autres reviennent "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:172.172.172.172". Je comprends que les deux sont des formats IPv6 valides, mais je voudrais pouvoir expliquer la différence. Il semble que les environnements plus récents (Windows 7 et Server 2008 R2) sont plus susceptibles de produire le premier comportement, j'ai donc vérifié les différences évidentes comme la version du framework .Net, mais j'ai été incapable de détecter un pattern.

Y a-t-il un moyen de sélectionner un format par rapport à l'autre, ou dois-je coder autour de ceci pour obtenir un comportement cohérent?

code recréées:

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()); 

Répondre

4

farfouillé dans les entrailles de ToString, en utilisant Reflector, vous pouvez voir que s'il est déterminé que le système d'exploitation prend en charge IPv6 (pour une valeur de supports), il remet à une fonction appelée Win32 WSAAddressToString, alors que si ce drapeau est pas, il ne forme manuelle (à partir de son tableau d'octets interne):

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)); 

qui retournera toujours le deuxième format que vous avez montré. Si le drapeau "OS support IPv6" est activé, cela dépend de la connaissance interne de la classe (la version doit être> 2000) et il semblerait que ce soit une tentative réelle de créer une socket IPv6 - donc si vous êtes sur un XP machine avec IPv6 désactivé, je pense que vous aurez également ce deuxième format.

1

Dans certains cas, il ne dépend pas du système d'exploitation prend en charge l'indicateur IPv6. Je reçois ce problème sur Windows Server 2008 R2.I essayé cette

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

mais address.ToString() est de retour la valeur "2400: 3c00: 3ffe :: 5efe: 137.153.72.170". Mais si je change IP String à "2400: 3C00: 3FFE: 1000: 1000: 5EFE: 8999: 48AA", cela fonctionne correctement.

0

Dans mon cas, j'avais besoin d'assurer une mise en forme cohérente sans avoir recours à un appel API non géré vers WSAAddressToString, j'ai donc écrit la méthode d'extension suivante. Peut-être que cela aidera quelqu'un à l'avenir:

/// <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 http://stackoverflow.com/questions/4863352/what-dictates-the-formatting-of-ipv6-addresses-by-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); 
    } 
}