2011-02-01 16 views
5

Il incorporato .Net metodo System.Net.IPAddress.ToString() si comporta in modo incoerente per gli indirizzi IPv6.Cosa determina la formattazione di indirizzi IPv6 da System.Net.IPAddress.ToString()?

Dato l'array di byte 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA, in alcuni ambienti viene restituito "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa", mentre altri restituiscono "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:172.172.172.172".

Capisco che entrambi siano formati IPv6 validi, ma vorrei essere in grado di spiegare la differenza.

Sembra che gli ambienti più recenti (Windows 7 e Server 2008 R2) abbiano maggiori probabilità di produrre il primo comportamento, quindi ho verificato differenze evidenti come la versione di .Net framework, ma non sono stato in grado di rilevare un pattern.

C'è un modo per selezionare un formato rispetto all'altro o devo codificare questo per ottenere un comportamento coerente?

Codice di ricreare:

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

risposta

4

Rovistando negli interni di ToString, utilizzando Reflector, si può vedere che se è stabilito che il sistema operativo supporta IPv6 (per un valore di supporti), poi si rimette alla una funzione Win32 chiamato WSAAddressToString, mentre se questo flag non è impostato, lo fa la formattazione manuale (da esso è array di byte interna) come:

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

che sarà sempre tornare il secondo formato avete dimostrato.

se il flag "OS supporta IPv6" flag è impostato sembra dipendere sia la conoscenza interna all'interno della classe (versione deve essere> 2000) e sembrerebbe un tentativo reale di creare una presa di IPv6 - quindi se la vostra su un macchina XP con IPv6 disabili, penso che avrete anche questo secondo formato.

1

Per alcuni casi non è dipendente dal sistema operativo supporta IPv6 bandiera. Sto ottenendo questo problema in Windows Server 2008 R2.I provato questo

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

ma address.ToString() sta tornando il valore "2400: 3c00: 3ffe :: 5EFE: 137.153.72.170".

Ma se cambio IP String a "2400: 3999: 3FFE: 1000: 1000: 5EFE: 8999: 48AA" funziona correttamente.

0

Nel mio caso dovevo garantire una formattazione coerente senza ricorrere a una chiamata API non gestita a WSAAddressToString, così ho scritto il seguente metodo di estensione. Forse questo aiuterà qualcuno in futuro:

/// <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); 
    } 
} 
Problemi correlati