2009-09-30 13 views

Respuesta

23

Tome un vistazo a IP Address Calculations with C# en los blogs de MSDN. Contiene un método de extensión (IsInSameSubnet) que debe satisfacer sus necesidades, así como algunos otros objetos.

public static class IPAddressExtensions 
{ 
    public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask) 
    { 
     byte[] ipAdressBytes = address.GetAddressBytes(); 
     byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); 

     if (ipAdressBytes.Length != subnetMaskBytes.Length) 
      throw new ArgumentException("Lengths of IP address and subnet mask do not match."); 

     byte[] broadcastAddress = new byte[ipAdressBytes.Length]; 
     for (int i = 0; i < broadcastAddress.Length; i++) 
     { 
      broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i]^255)); 
     } 
     return new IPAddress(broadcastAddress); 
    } 

    public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask) 
    { 
     byte[] ipAdressBytes = address.GetAddressBytes(); 
     byte[] subnetMaskBytes = subnetMask.GetAddressBytes(); 

     if (ipAdressBytes.Length != subnetMaskBytes.Length) 
      throw new ArgumentException("Lengths of IP address and subnet mask do not match."); 

     byte[] broadcastAddress = new byte[ipAdressBytes.Length]; 
     for (int i = 0; i < broadcastAddress.Length; i++) 
     { 
      broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i])); 
     } 
     return new IPAddress(broadcastAddress); 
    } 

    public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask) 
    { 
     IPAddress network1 = address.GetNetworkAddress(subnetMask); 
     IPAddress network2 = address2.GetNetworkAddress(subnetMask); 

     return network1.Equals(network2); 
    } 
} 
+0

¿Qué pasa con las direcciones IPv6? – ageroh

+0

@ageroh GitHub parece tener algunas bibliotecas de C# que pueden manejar direcciones IPv6. IPNetwork, por ejemplo, https://github.com/lduchosal/ipnetwork –

10

La manipulación de bits funciona. Cosas de la IP en un entero sin signo de 32 bits, en hacer lo mismo con la dirección de la subred, & -mask ambos con 0xFFFFFFFF << (32-20) y comparar:

unsigned int net = ..., ip = ...; 
int network_bits = 20; 
unsigned int mask = 0xFFFFFFFF << (32 - network_bits); 
if ((net & mask) == (ip & mask)) { 
    // ... 
} 
+0

O, si tan común, la subred se da como un número como 255.255.240.0, sólo cosas la máscara en un entero de 32 bits en lugar del cambio. – erikkallen

+3

Encontré la clase System.Net.IPAddress útil para analizar y descomponer direcciones IP en bytes –

0

La solución es convertir la dirección IP en bytes utilizando System.Net.IPAddress y realizar comparaciones a nivel de bits en los octetos de la dirección, de subred y la máscara.

El operador AND Binario & copia un poco el resultado si existe en ambos operandos.

El código:

using System.Net; // Used to access IPAddress 

bool IsAddressOnSubnet(string address, string subnet, string mask) 
{ 
    try 
    { 
     IPAddress Address = IPAddress.Parse(address); 
     IPAddress Subnet = IPAddress.Parse(subnet); 
     IPAddress Mask = IPAddress.Parse(mask);    

     Byte[] addressOctets = Address.GetAddressBytes(); 
     Byte[] subnetOctets = Mask.GetAddressBytes(); 
     Byte[] networkOctets = Subnet.GetAddressBytes(); 

     return 
      ((networkOctets[0] & subnetOctets[0]) == (addressOctets[0] & subnetOctets[0])) && 
      ((networkOctets[1] & subnetOctets[1]) == (addressOctets[1] & subnetOctets[1])) && 
      ((networkOctets[2] & subnetOctets[2]) == (addressOctets[2] & subnetOctets[2])) && 
      ((networkOctets[3] & subnetOctets[3]) == (addressOctets[3] & subnetOctets[3])); 
    } 
    catch (System.Exception ex) 
    { 
     return false;     
    } 
} 

Gracias especiales a Спасибо! Прекрасное решение! Reference

+1

, tenga en cuenta que esto se romperá si se presenta con direcciones IPv6 – Fowl

2

Dado que el código de MSDN blog se basa en una difusión y IPv6 no tiene uno, no sé si funciona con IPv6.

Terminé con estos métodos (gracias a nu everest). Puede obtener la subred y la máscara de una notación CIDR ("1.2.3.4/5") y comprobar si una dirección está dentro de esta red o no.

Esto funciona para IPv4 e IPv6: el uso

public static class IpAddresses 
{ 
    public static Tuple<IPAddress, IPAddress> GetSubnetAndMaskFromCidr(string cidr) 
    { 
     var delimiterIndex = cidr.IndexOf('/'); 
     string ipSubnet = cidr.Substring(0, delimiterIndex); 
     string mask = cidr.Substring(delimiterIndex + 1); 

     var subnetAddress = IPAddress.Parse(ipSubnet); 

     if (subnetAddress.AddressFamily == AddressFamily.InterNetworkV6) 
     { 
      // ipv6 
      var ip = BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.HexNumber) << (128 - int.Parse(mask)); 

      var maskBytes = new[] 
      { 
       (byte)((ip & BigInteger.Parse("00FF000000000000000000000000000000", NumberStyles.HexNumber)) >> 120), 
       (byte)((ip & BigInteger.Parse("0000FF0000000000000000000000000000", NumberStyles.HexNumber)) >> 112), 
       (byte)((ip & BigInteger.Parse("000000FF00000000000000000000000000", NumberStyles.HexNumber)) >> 104), 
       (byte)((ip & BigInteger.Parse("00000000FF000000000000000000000000", NumberStyles.HexNumber)) >> 96), 
       (byte)((ip & BigInteger.Parse("0000000000FF0000000000000000000000", NumberStyles.HexNumber)) >> 88), 
       (byte)((ip & BigInteger.Parse("000000000000FF00000000000000000000", NumberStyles.HexNumber)) >> 80), 
       (byte)((ip & BigInteger.Parse("00000000000000FF000000000000000000", NumberStyles.HexNumber)) >> 72), 
       (byte)((ip & BigInteger.Parse("0000000000000000FF0000000000000000", NumberStyles.HexNumber)) >> 64), 
       (byte)((ip & BigInteger.Parse("000000000000000000FF00000000000000", NumberStyles.HexNumber)) >> 56), 
       (byte)((ip & BigInteger.Parse("00000000000000000000FF000000000000", NumberStyles.HexNumber)) >> 48), 
       (byte)((ip & BigInteger.Parse("0000000000000000000000FF0000000000", NumberStyles.HexNumber)) >> 40), 
       (byte)((ip & BigInteger.Parse("000000000000000000000000FF00000000", NumberStyles.HexNumber)) >> 32), 
       (byte)((ip & BigInteger.Parse("00000000000000000000000000FF000000", NumberStyles.HexNumber)) >> 24), 
       (byte)((ip & BigInteger.Parse("0000000000000000000000000000FF0000", NumberStyles.HexNumber)) >> 16), 
       (byte)((ip & BigInteger.Parse("000000000000000000000000000000FF00", NumberStyles.HexNumber)) >> 8), 
       (byte)((ip & BigInteger.Parse("00000000000000000000000000000000FF", NumberStyles.HexNumber)) >> 0), 
      }; 

      return Tuple.Create(subnetAddress, new IPAddress(maskBytes)); 
     } 
     else 
     { 
      // ipv4 
      uint ip = 0xFFFFFFFF << (32 - int.Parse(mask)); 

      var maskBytes = new[] 
      { 
       (byte)((ip & 0xFF000000) >> 24), 
       (byte)((ip & 0x00FF0000) >> 16), 
       (byte)((ip & 0x0000FF00) >> 8), 
       (byte)((ip & 0x000000FF) >> 0), 
      }; 

      return Tuple.Create(subnetAddress, new IPAddress(maskBytes)); 
     } 
    } 

    public static bool IsAddressOnSubnet(IPAddress address, IPAddress subnet, IPAddress mask) 
    { 
     byte[] addressOctets = address.GetAddressBytes(); 
     byte[] subnetOctets = mask.GetAddressBytes(); 
     byte[] networkOctets = subnet.GetAddressBytes(); 

     // ensure that IPv4 isn't mixed with IPv6 
     if (addressOctets.Length != subnetOctets.Length 
      || addressOctets.Length != networkOctets.Length) 
     { 
      return false; 
     } 

     for (int i = 0; i < addressOctets.Length; i += 1) 
     { 
      var addressOctet = addressOctets[i]; 
      var subnetOctet = subnetOctets[i]; 
      var networkOctet = networkOctets[i]; 

      if (networkOctet != (addressOctet & subnetOctet)) 
      { 
       return false; 
      } 
     } 
     return true; 
    } 
} 

Ejemplo:

var subnetAndMask = IpAddresses.GetSubnetAndMaskFromCidr("10.132.0.0/20"); 
bool result = IpAddresses.IsAddressOnSubnet(
    IPAddress.Parse("10.132.12.34"), 
    subnetAndMask.Item1, 
    subnetAndMask.Item2); 
0

llego tarde a la fiesta aquí, pero tenía una necesidad similar, y poner juntos un paquete rápida a haz exactamente esto

https://www.nuget.org/packages/IpMatcher/

y fuente:

https://github.com/jchristn/IpMatcher

uso simple:

using IpMatcher; 

Matcher matcher = new Matcher(); 
matcher.Add("192.168.1.0", "255.255.255.0"); 
matcher.Add("192.168.2.0", "255.255.255.0"); 
matcher.Remove("192.168.2.0"); 
matcher.Exists("192.168.1.0", "255.255.255.0"); // true 
matcher.Match("192.168.1.34"); // true 
matcher.Match("10.10.10.10"); // false 
Cuestiones relacionadas