2011-11-13 1 views
17

Finora ho questo codice:come determinare se un indirizzo IP in privato?

NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces(); 

foreach (NetworkInterface adapter in adapters) 
{ 
    IPInterfaceProperties properties = adapter.GetIPProperties(); 

    foreach (IPAddressInformation uniCast in properties.UnicastAddresses) 
    { 

    // Ignore loop-back addresses & IPv6 
    if (!IPAddress.IsLoopback(uniCast.Address) && 
     uniCast.Address.AddressFamily!= AddressFamily.InterNetworkV6) 
     Addresses.Add(uniCast.Address); 
    } 
} 

Come faccio a filtrare gli indirizzi IP privati ​​come bene? Allo stesso modo sto filtrando gli indirizzi IP di loopback.

risposta

33

Una risposta più dettagliata è qui:

private bool _IsPrivate(string ipAddress) 
{ 
    int[] ipParts = ipAddress.Split(new String[] { "." }, StringSplitOptions.RemoveEmptyEntries) 
          .Select(s => int.Parse(s)).ToArray(); 
    // in private ip range 
    if (ipParts[0] == 10 || 
     (ipParts[0] == 192 && ipParts[1] == 168) || 
     (ipParts[0] == 172 && (ipParts[1] >= 16 && ipParts[1] <= 31))) { 
     return true; 
    } 

    // IP Address is probably public. 
    // This doesn't catch some VPN ranges like OpenVPN and Hamachi. 
    return false; 
} 
13

Gli intervalli di indirizzi privati ​​sono definiti in RFC1918. Essi sono:

  • 10.0.0.0 - 10.255.255.255 (10/8 prefisso)
  • 172.16.0.0 - 172.31.255.255 (172.16/12 prefisso)
  • 192.168.0.0 - 192.168.255.255 (192.168/16 prefisso)

È inoltre possibile filtrare gli indirizzi locali di collegamento (169.254/16) come definito in RFC3927.

4
10.0.0.0  - 10.255.255.255 (10/8 prefix) 
172.16.0.0  - 172.31.255.255 (172.16/12 prefix) 
192.168.0.0  - 192.168.255.255 (192.168/16 prefix) 

Utilizzare gli intervalli definiti nell'RFC (come suggerito da Anders); di usare l'espressione regolare per rilevare/rimuovere l'indirizzo IP privato dall'elenco.

Ecco un esempio di RegEx per rilevare indirizzi IP privati. (Non testato da me)

(^127\.0\.0\.1)| 
(^10\.)| 
(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)| 
(^192\.168\.) 
+2

Forse più facile da convertire in Uint32 e quindi utilizzare operazioni bit per bit: '((indirizzi e 0xFF000000U) == 0x0A000000U) || ... '. Se ci sono molti indirizzi da controllare, dovrebbe anche essere più veloce. – Richard

+1

Sospetto che ciò funzionerà, ma le espressioni regolari sono concettualmente lo strumento sbagliato per testare se gli interi piccoli sono nel range corretto. Confrontando i numeri sarà molto più efficiente rispetto alle stringhe corrispondenti. – Anthony

+0

Converti l'IP corrente nella rappresentazione numerica e poi guarda se rientra in una qualsiasi di queste classi (usa solo il confronto numerico). Funziona perfettamente per me. – Edi

4

Il migliore per fare questo sarebbe un metodo di estensione alla classe dell'indirizzo IP

/// <summary> 
    /// An extension method to determine if an IP address is internal, as specified in RFC1918 
    /// </summary> 
    /// <param name="toTest">The IP address that will be tested</param> 
    /// <returns>Returns true if the IP is internal, false if it is external</returns> 
    public static bool IsInternal(this IPAddress toTest) 
    { 
     byte[] bytes = toTest.GetAddressBytes(); 
     switch(bytes[ 0 ]) 
     { 
      case 10: 
       return true; 
      case 172: 
       return bytes[ 1 ] < 32 && bytes[ 1 ] >= 16; 
      case 192: 
       return bytes[ 1 ] == 168; 
      default: 
       return false; 
     } 
    } 

Poi , si può chiamare il metodo su un'istanza della classe di indirizzo IP

bool isIpInternal = ipAddressInformation.Address.IsInternal(); 
3

Aggiunti casi IPv6 e localhost.

/* An IP should be considered as internal when: 

     ::1   - IPv6 loopback 
     10.0.0.0  - 10.255.255.255 (10/8 prefix) 
     127.0.0.0 - 127.255.255.255 (127/8 prefix) 
     172.16.0.0 - 172.31.255.255 (172.16/12 prefix) 
     192.168.0.0 - 192.168.255.255 (192.168/16 prefix) 
    */ 
    public bool IsInternal(string testIp) 
    { 
     if(testIp == "::1") return true; 

     byte[] ip = IPAddress.Parse(testIp).GetAddressBytes(); 
     switch (ip[0]) 
     { 
      case 10: 
      case 127: 
       return true; 
      case 172: 
       return ip[1] >= 16 && ip[1] < 32; 
      case 192: 
       return ip[1] == 168; 
      default: 
       return false; 
     } 
    }