2014-05-12 31 views
13

Questo codice genera un ArgumentOutOfRangeException sull'ultima rigaPerché IPAddress.MapToIPv4() genera ArgumentOutOfRangeException?

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

Qualcuno può spiegare perché MapToIPv6() e MapToIPv4() non sono di andata e ritorno compatibili?

modifica: l'eccezione deriva dal costruttore IPAddress, chiamato da MapToIPv4().

Inoltre, quando la prima linea è

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

senza eccezioni sono gettati più

EDIT2: come @Luaan riprodotto questo, ho aggiunto il tag [bug-reporting]. Aggiunto anche [bcl]. Vediamo se qualsiasi personale MS tracce questi tag :)

Edit3: riferito a Collegare https://connect.microsoft.com/VisualStudio/feedback/details/871964

+0

Interessante. Ci sono molti indirizzi IPv4 per i quali funziona bene. Infatti, sulla base di alcuni test ad hoc, sembra che l'ultimo bit sia la colpa - forse c'è un errore da qualche parte nel codice che usa così genericamente i lanci "long", "ulong" e "int' con numeri positivi e negativi . Perché vuoi comunque gli indirizzi IPv4 mappati IPv6? Stai lavorando con i server linux? Pensavo che Windows non li gestisse veramente (dal momento che IPv4 e IPv6 sono driver separati nello stack di rete - sono necessari due socket separati per gestire sia IPv4 che IPv6). – Luaan

+0

Beh, non ne ho davvero bisogno, ma l'ho considerato una piccola vittoria quando si confrontano gli indirizzi. Immagino di essere fortunato che i test del mio codice abbiano effettivamente un indirizzo come questo, per allontanarmi dal mio ottimismo prematuro (non compilato) ... –

+0

@PatrickHuizinga Ah, ho pubblicato anche la segnalazione del bug. Comunque, ho alzato il tuo :) – Luaan

risposta

17

Ok, in realtà ho verificato questo, per cui vorrei questo post come una risposta.

La classe IPAddress ha un errore durante la mappatura dell'indirizzo su IPv4.

Secondo il codice di riferimento .NET, lo fa:

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

Il problema dovrebbe essere abbastanza evidente a chiunque fare operazioni bit per bit in .NET - i numeri sono tutti int s. Quindi spostando il secondo ushort (m_Numbers[7]) si ottiene un valore negativo, poiché il bit più significativo è 1. Ciò significa che tutti gli indirizzi IPv4 che terminano con un byte superiore a 127 causeranno un errore durante il mapping da IPv6.

La semplice soluzione sarebbe questo:

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

Proprio lanciando il int a un uint prima di fare il Bitshift fa il trucco.

Le operazioni bit a bit possono essere piuttosto complicate quando si utilizzano tipi firmati. Immagino che il codice sia stato copiato da una libreria C++ o qualcosa del genere, dove questo problema non si sarebbe manifestato.

+1

Stai dicendo che questo è essenzialmente un bug nella fonte. NET? - Microsoft dovrebbe essere informata di questo? – series0ne

+5

@ series0ne Yup, ora è stato segnalato - https://connect.microsoft.com/VisualStudio/feedback/dettagli/871964/ipaddress-maptoipv4-throws-argumentoutofrangeexception – Luaan

+1

Solo per riferimento di tutti, ho trovato questo su un server completamente corrotto con .NET Framework 4.5.2, quindi suppongo che la correzione non sarà fino a 4.6 –