2011-08-16 19 views
6

He visto un montón de grandes C# examples que demuestran cómo convertir direcciones IPv4 proporcionadas en notación CIDR (por ejemplo, 192.168.0.1/25) en sus rangos relevantes (192.168.0.1 - 192.168 .0.126). Mi programa necesita poder hacer esto (para calcular todas las direcciones dentro de mi subred local) pero también quiero admitir IPv6.Calculando todas las direcciones dentro de una subred ... para IPv6

Si mi programa C# tiene toda mi información típica de ipconfig (dirección IPv4, máscara de subred, dirección IPv6, dirección v6 local de enlace, puerta de enlace predeterminada) - ¿cómo podría generar una lista de todas las direcciones IPv6 en mi subred local y sacarlos a la consola?

+2

es probable que tenga que replantearse su funcionalidad. Por diseño, casi cualquier subred que verá en IPv6 será/64, o (2^64) -1 hosts de gran tamaño. – Joe

+2

Eso es correcto, quiero las 18,446,744,073,709,551,616 direcciones IP;) – DaveUK

+8

¿Y qué vas a hacer con ellas? Incluso a 10 millones por segundo, necesitarías 58,000 años para revisarlos todos. – Joe

Respuesta

9

Puede usar la clase eExNetworkLibrary.IP.IPAddressAnalysis desde eExNetworkLibrary.

El siguiente código funciona con IPv4 e IPv6 (apenas probado).

 string strIn = "2001:DB8::/120"; 

     //Split the string in parts for address and prefix 
     string strAddress = strIn.Substring(0, strIn.IndexOf('/')); 
     string strPrefix = strIn.Substring(strIn.IndexOf('/') + 1); 

     int iPrefix = Int32.Parse(strPrefix); 
     IPAddress ipAddress = IPAddress.Parse(strAddress); 

     //Convert the prefix length to a valid SubnetMask 

     int iMaskLength = 32; 

     if(ipAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6) 
     { 
      iMaskLength = 128; 
     } 

     BitArray btArray = new BitArray(iMaskLength); 
     for (int iC1 = 0; iC1 < iMaskLength; iC1++) 
     { 
      //Index calculation is a bit strange, since you have to make your mind about byte order. 
      int iIndex = (int)((iMaskLength - iC1 - 1)/8) * 8 + (iC1 % 8); 

      if (iC1 < (iMaskLength - iPrefix)) 
      { 
       btArray.Set(iIndex, false); 
      } 
      else 
      { 
       btArray.Set(iIndex, true); 
      } 
     } 

     byte[] bMaskData = new byte[iMaskLength/8]; 

     btArray.CopyTo(bMaskData, 0); 

     //Create subnetmask 
     Subnetmask smMask = new Subnetmask(bMaskData); 

     //Get the IP range 
     IPAddress ipaStart = IPAddressAnalysis.GetClasslessNetworkAddress(ipAddress, smMask); 
     IPAddress ipaEnd = IPAddressAnalysis.GetClasslessBroadcastAddress(ipAddress, smMask); 

     //Omit the following lines if your network range is large 
     IPAddress[] ipaRange = IPAddressAnalysis.GetIPRange(ipaStart, ipaEnd); 

     //Debug output 
     foreach (IPAddress ipa in ipaRange) 
     { 
      Console.WriteLine(ipa.ToString()); 
     } 

     Console.ReadLine(); 

no estoy completamente seguro de si he hecho la conversión de la longitud de prefijo a una matriz de bytes que contiene la máscara de subred correcta, pero el código que debería darle un buen punto de partida.

Editar: Actualicé la parte de doblar bits del código. Puede ser feo, pero funciona para este ejemplo. Creo que serás capaz de encontrar una mejor solución, si es necesario. Esas BitArrays son un dolor en el cuello.

Tenga en cuenta que generar un rango de red IPv6 puede ser una tarea muy agotadora de memoria/CPU si la red es grande.

+0

Esto casi funcionó para mí. Necesario para cambiar iIndex a igual (iMaskLength - iC1 - 1). Este era el código antes de editar, así que no estoy seguro de por qué fue cambiado. –

1

exNetworkLibrary es una gran herramienta, pero si no puede usarlo en su proyecto, entonces es posible que sólo quieren ver este artículo:

http://www.codeproject.com/Articles/112020/IP-Address-Extension

Se describe cómo se calculan máscaras de direcciones IPv4 para su uso en .

Su pregunta está relacionada con IPv6 veo y desde .Net 4.5 hay un método IPAddress.MapToIPv6.

https://msdn.microsoft.com/en-us/library/system.net.ipaddress.maptoipv6(v=vs.110).aspx

Puede utilizar esa realización de la verificación en el artículo a producir este código:

private static IPAddress empty = IPAddress.Parse("0.0.0.0"); 
    private static IPAddress intranetMask1 = IPAddress.Parse("10.255.255.255"); 
    private static IPAddress intranetMask2 = IPAddress.Parse("172.16.0.0"); 
    private static IPAddress intranetMask3 = IPAddress.Parse("172.31.255.255"); 
    private static IPAddress intranetMask4 = IPAddress.Parse("192.168.255.255"); 

    /// <summary> 
    /// Retuns true if the ip address is one of the following 
    /// IANA-reserved private IPv4 network ranges (from http://en.wikipedia.org/wiki/IP_address) 
    /// Start  End 
    /// 10.0.0.0  10.255.255.255 
    /// 172.16.0.0  172.31.255.255  
    /// 192.168.0.0 192.168.255.255 
    /// </summary> 
    /// <returns></returns> 
    public static bool IsOnIntranet(this IPAddress ipAddress) 
    { 
     if (empty.Equals(ipAddress)) 
     { 
      return false; 
     } 

     bool onIntranet = IPAddress.IsLoopback(ipAddress); 

     if (false == onIntranet) 
     { 
      //Handle IPv6 by getting the IPv4 Mapped Address. 
      if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) 
      { 
       onIntranet = ipAddress.Equals(ipAddress.And(intranetMask1.MapToIPv6())); //10.255.255.255 
       onIntranet = onIntranet || ipAddress.Equals(ipAddress.And(intranetMask4.MapToIPv6())); ////192.168.255.255 

       onIntranet = onIntranet || (intranetMask2.Equals(ipAddress.And(intranetMask2.MapToIPv6())) 
        && ipAddress.Equals(ipAddress.And(intranetMask3.MapToIPv6()))); 
      } 
      else 
      { 
       onIntranet = ipAddress.Equals(ipAddress.And(intranetMask1)); //10.255.255.255 
       onIntranet = onIntranet || ipAddress.Equals(ipAddress.And(intranetMask4)); ////192.168.255.255 

       onIntranet = onIntranet || (intranetMask2.Equals(ipAddress.And(intranetMask2)) 
        && ipAddress.Equals(ipAddress.And(intranetMask3))); 
      } 


     } 

     return onIntranet; 
    } 

private static void CheckIPVersion(IPAddress ipAddress, IPAddress mask, out byte[] addressBytes, out byte[] maskBytes) 
    { 
     if (mask == null) 
     { 
      throw new ArgumentException(); 
     } 

     addressBytes = ipAddress.GetAddressBytes(); 
     maskBytes = mask.GetAddressBytes(); 

     if (addressBytes.Length != maskBytes.Length) 
     { 
      throw new ArgumentException("The address and mask don't use the same IP standard"); 
     } 
    } 

    public static IPAddress And(this IPAddress ipAddress, IPAddress mask) 
    { 
     byte[] addressBytes; 
     byte[] maskBytes; 
     CheckIPVersion(ipAddress, mask, out addressBytes, out maskBytes); 

     byte[] resultBytes = new byte[addressBytes.Length]; 
     for (int i = 0, e = addressBytes.Length; i < e; ++i) 
     { 
      resultBytes[i] = (byte)(addressBytes[i] & maskBytes[i]); 
     } 

     return new IPAddress(resultBytes); 
    } 
1

Yo recomendaría el uso de ipNetwork Biblioteca https://github.com/lduchosal/ipnetwork. A partir de la versión 2, también es compatible con IPv4 e IPv6.

IPv6

IPNetwork ipnetwork = IPNetwork.Parse("2001:0db8::/64"); 

    Console.WriteLine("Network : {0}", ipnetwork.Network); 
    Console.WriteLine("Netmask : {0}", ipnetwork.Netmask); 
    Console.WriteLine("Broadcast : {0}", ipnetwork.Broadcast); 
    Console.WriteLine("FirstUsable : {0}", ipnetwork.FirstUsable); 
    Console.WriteLine("LastUsable : {0}", ipnetwork.LastUsable); 
    Console.WriteLine("Usable : {0}", ipnetwork.Usable); 
    Console.WriteLine("Cidr : {0}", ipnetwork.Cidr); 

salida

Network : 2001:db8:: 
Netmask : ffff:ffff:ffff:ffff:: 
Broadcast : 
FirstUsable : 2001:db8:: 
LastUsable : 2001:db8::ffff:ffff:ffff:ffff 
Usable : 18446744073709551616 
Cidr : 64 

Enumeración

IPNetwork network = IPNetwork.Parse("::/124"); 
    IPNetworkCollection ips = IPNetwork.Subnet(network, 128); 

    foreach (IPNetwork ip in ips) { 
     Console.WriteLine("{0}", ip); 
    } 

salida

::/128 
::1/128 
::2/128 
::3/128 
::4/128 
::5/128 
::6/128 
::7/128 
::8/128 
::9/128 
::a/128 
::b/128 
::c/128 
::d/128 
::e/128 
::f/128 

¡Diviértete!

+0

La salida para la primera y la última dirección utilizable es incorrecta. IPv6, a diferencia de IPv4, puede usar todas las direcciones en una subred. Una subred IPv6 estándar es/64 (algunos casos especiales usan otras longitudes de máscara), y las direcciones utilizables son de ' ::' a ': ffff: ffff: ffff: ffff'.No hay reserva para la subred (' ::'), e IPv6 no tiene el concepto de transmisión, por lo que no existe una dirección de difusión en ': ffff: ffff: ffff: ffff'. –

+1

Gracias por señalar esto. Ejemplo corregido – LukeSkywalker

0

Sé que esta publicación tiene 5 años, pero dadas las capacidades de Google, es posible que también se haya actualizado esta mañana. Entonces, agregaré un poco de aclaración desde la perspectiva de la ingeniería de red.

Depende del tipo de direcciones. Si se refiere a cada dirección en el rango, entonces la discusión anterior es correcta. Si se refiere a direcciones que pueden asignarse de forma exclusiva a un nodo en la subred (direcciones de "unidifusión"), tenga en cuenta que en IPv6 (a) no hay difusión, y (b) hay un rango sustancial de multidifusión.

Básicamente: [subred]: ff :: está reservado para multidifusión. Si no está utilizando un/64 para una máscara de subred, REALMENTE quiere tener cuidado porque va en contra de una suposición fundamental de muchos RFC relacionados con IPv6. Existen otros RFC que advierten contra el uso de la dirección host de todos los ceros (pero no estoy al tanto de un requisito específico para ese efecto).

Por lo tanto, para una subred/64, eso significa que el rango de direcciones unicast es :: 0: 0: 0: 1 a :: feff: ffff: ffff: ffff.

ve aquí para la discusión: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm

Weylin

+0

La dirección de host de ceros a cero está reservada para los enrutadores de subred, que DEBEN responder en esta dirección. Ver [RFC 4291 sección 2.6.1] (https://tools.ietf.org/html/rfc4291#section-2.6.1). A pesar de este requisito, los enrutadores de muchas redes no responden a esta dirección, pero si intenta utilizar esta dirección en una red donde los enrutadores funcionan correctamente, tendrá un mal día. –

Cuestiones relacionadas