2010-01-26 20 views
51

Se gli utenti immettono un paio di intervalli di ip, ad esempio 172.16.11.5 - 100, come potrei scrivere una funzione per verificare se un IP (172.16.11.50) cade nelle gamme?Come verificare un IP di input in un intervallo IP specifico

C'è qualche libreria esistente in .NET da sfruttare?

+0

Una nota di cautela - se si implementa questo al fine di verificare se un IP è su una particolare sottorete, allora non si può fare questo in modo affidabile senza prendere in considerazione la subnet mask pure. –

+0

Sembra che non stia specificando una subnet mask. Se lo fosse, dovresti usare un singolo IP e specificare la sottorete, piuttosto che un intervallo di indirizzi IP. Gli intervalli sono normalmente usati perché un sacco di persone non sa quali sottoreti sono ... – Ian

+0

simile/possibile duplicato - http://stackoverflow.com/questions/1820661/comparing-ipaddress-stored-as-varbinary/1821016#1821016 – ram

risposta

98

Non c'è niente nel framework, ma non ci vorrebbe molto sforzo per creare una classe IPAddressRange.

Confronta gli intervalli chiamando lo IPAddress.GetAddressBytes sull'indirizzo inferiore, l'indirizzo superiore e l'indirizzo di confronto. A partire dal primo byte, verificare se l'indirizzo di confronto si trova nell'intervallo dell'indirizzo superiore/inferiore.

Questo metodo funziona sia per indirizzi IPv4 che IPv6.

public class IPAddressRange 
{ 
    readonly AddressFamily addressFamily; 
    readonly byte[] lowerBytes; 
    readonly byte[] upperBytes; 

    public IPAddressRange(IPAddress lowerInclusive, IPAddress upperInclusive) 
    { 
     // Assert that lower.AddressFamily == upper.AddressFamily 

     this.addressFamily = lowerInclusive.AddressFamily; 
     this.lowerBytes = lowerInclusive.GetAddressBytes(); 
     this.upperBytes = upperInclusive.GetAddressBytes(); 
    } 

    public bool IsInRange(IPAddress address) 
    { 
     if (address.AddressFamily != addressFamily) 
     { 
      return false; 
     } 

     byte[] addressBytes = address.GetAddressBytes(); 

     bool lowerBoundary = true, upperBoundary = true; 

     for (int i = 0; i < this.lowerBytes.Length && 
      (lowerBoundary || upperBoundary); i++) 
     { 
      if ((lowerBoundary && addressBytes[i] < lowerBytes[i]) || 
       (upperBoundary && addressBytes[i] > upperBytes[i])) 
      { 
       return false; 
      } 

      lowerBoundary &= (addressBytes[i] == lowerBytes[i]); 
      upperBoundary &= (addressBytes[i] == upperBytes[i]); 
     } 

     return true; 
    } 
} 

NB: Il codice di cui sopra potrebbe essere esteso per aggiungere metodi factory statici pubblici FromCidr(IPAddress address, int bits)

+1

sarebbe falsa per il caso: inferiore - 222.168.2.1, superiore - 222.168.5.10 e il bersaglio - 222.168.3.55 – Ricky

+1

Buon punto. Vedi la versione aggiornata. –

+2

Contributo eccellente, @Richard. Mi ha aiutato immensamente. – egandalf

8

Il migliore è convertire questi indirizzi in un numero intero e quindi eseguire confronti.

Esempio da qui: IP to Integer

Per convertire un indirizzo IP a intero, rompere in quattro ottetti. Ad esempio, l'indirizzo IP che hai fornito può essere suddiviso in:

First Octet: 217 
Second Octet: 110 
Third Octet: 18 
Fourth Octet: 206 

per calcolare l'indirizzo decimale da una stringa punteggiata, eseguire il seguente calcolo.

(first octet * 256³) + (second octet * 256²) + (third octet * 256) + (fourth octet) 
= (first octet * 16777216) + (second octet * 65536) + (third octet * 256) + (fourth octet) 
= (217 * 16777216) + (110 * 65536) + (18 * 256) + (206) 
= 3647869646 

Considerando IPv6, è possibile convertire in numeri interi (128 bit vs 32 bit IPv4) pure. Date un'occhiata a questa domanda: Formatting IPv6 as an int in C# and storing it in SQL Server

La via più semplice è quello di ottenere il quadro di fare questo per voi. Utilizzare IPAddress.Parse per analizzare l'indirizzo, quindi IPAddress.GetAddressBytes per ottenere il "numero" come byte[].

+1

Questo non funzionerà per gli indirizzi IPv6, che la classe 'IPAddress' supporta. –

1

Potresti capire il subnet mask dalla vostra gamma IP?

Se è così allora forse si potrebbe utilizzare questo metodo IsInSameSubnet ..

+0

È possibile avere più reti con la stessa subnet mask. Non mi fiderei di questo modo. – dampee

3

reinserire la mia risposta da here

Qualche tempo fa, ho dovuto trovare la posizione di un determinato IP. Abbiamo ricevuto l'IP dalla richiesta. Ci sono database gratuiti che ci hanno dato questa mappatura. In IPv4, quando diciamo l'IP come "a.b.c.d" è essenzialmente un * (256^3) + b * (256^2) + c * (256) + d.

http://www.aboutmyip.com/AboutMyXApp/IP2Integer.jsp

così quando dici che vuoi un indirizzo IP comincia con "a", siete alla ricerca di indirizzi IP tra un * 256^3 e un * 256^3 + 256 * (256^2) (b = 256) + 256 * (256) (c = 256) + 256 (d = 256) (il limite inferiore/superiore può variare leggermente a seconda che si voglia includere/escludere i limiti).

Detto questo, ci sono IP specifici riservati per scopi specifici (come 127.0.0.1 che è localhost, 0.0.0.0 non può essere un IP ecc.).

Quindi la query LINQ sarebbe

"da I a IList dove i> = MIN & & i < = Max Selezionare i;"

dove IList è la vostra lista iniziale minimo è il vostro valore minimo per l'intervallo MAX è il vostro valore massimo per l'intervallo

9
public static bool IsInRange(string startIpAddr, string endIpAddr, string address) 
{ 
    long ipStart = BitConverter.ToInt32(IPAddress.Parse(startIpAddr).GetAddressBytes().Reverse().ToArray(), 0); 

    long ipEnd = BitConverter.ToInt32(IPAddress.Parse(endIpAddr).GetAddressBytes().Reverse().ToArray(), 0); 

    long ip = BitConverter.ToInt32(IPAddress.Parse(address).GetAddressBytes().Reverse().ToArray(), 0); 

    return ip >= ipStart && ip <= ipEnd; //edited 
} 

Console.WriteLine(IsInRange("100.0.0.1", "110.0.0.255", "102.0.0.4"));//true 
+6

Direi uguale anche rientra nell'intervallo: return ip> = ipStart && ip <= ipEnd; – Jannes

+0

Risposta perfetta! Questo ha superato tutti i miei test unitari, soprattutto per le estremità inferiori dell'intervallo. –

+2

Erm, non dovremmo usare 'UInt32' invece di' long' o 'Int32'? Questo errore non si risolverà su un eventuale bridging di indirizzi o superiore a 128.0.0.0? –

Problemi correlati