Расчет всех адресов в подсети...для IPv6

Я видел много великих Примеры C# которые демонстрируют, как конвертировать IPv4 - адреса, предоставленные в нотации CIDR (например, 192.168.0.1/25) в их соответствующие диапазоны (192.168.0.1-192.168.0.126). Моя программа должна иметь возможность сделать это (вычислить все адреса в моей локальной подсети), но я также хочу поддерживать IPv6.

Если моя программа c# имеет всю мою типичную информацию ipconfig (IPv4-адрес, маска подсети, IPv6-адрес, ссылка-локальный адрес v6, по умолчанию gateway) - как я могу создать список всех адресов IPv6 в моей локальной подсети и вывести их на консоль?

4 ответов


вы можете использовать eExNetworkLibrary.ИНТЕЛЛЕКТУАЛЬНАЯ СОБСТВЕННОСТЬ.Класс IPAddressAnalysis из eExNetworkLibrary.

следующий код работает с IPv4 и IPv6 (только что проверил).

        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();

Я не совсем уверен, что я сделал преобразование из длины префикса в массив байтов, содержащий маску подсети, но этот код должен дать вам хорошую отправную точку.

редактировать: обновлена битовая часть кода. Может быть уродливо, но работает для этого примера. Я думаю, вы сможете найти лучшее решение, если понадобится. Эти BitArrays-боль в шее.

имейте в виду, что создание сетевого диапазона IPv6 может быть очень утомительной задачей памяти/процессора, если сеть большая.


exNetworkLibrary - отличный инструмент, но если вы не можете использовать его в своем проекте, вы можете просто увидеть эту статью:

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

Он описывает, как маски адресов рассчитываются для использования в IPv4.

Ваш вопрос связан с IPv6, который я вижу, и с .Net 4.5 есть IPAddress.MapToIPv6 метод.

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

Вы можете использовать это с проверками в статье для создания этого кода:

    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);
    }

Я бы рекомендовал использовать библиотеку IPNetwork https://github.com/lduchosal/ipnetwork. Начиная с версии 2, он также поддерживает IPv4 и 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);

выход

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

перечисление

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

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

выход

::/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

удачи !


Я знаю, что этот пост 5yr старый, но, учитывая возможности Google, он также мог быть обновлен сегодня утром. Итак, я добавлю немного разъяснений с точки зрения инженерных сетей.

Это зависит от того, какие адреса. Если вы имеете в виду каждый адрес в диапазоне, то приведенное выше обсуждение является правильным. Если вы имеете в виду адреса, которые могут быть однозначно назначены узлу в подсети ("одноадресные" адреса), имейте в виду, что в IPv6 (a) нет широковещательной передачи и (b) есть существенный диапазон многоадресной рассылки.

в основном: [подсеть]: ff:: зарезервирован для многоадресной рассылки. Если вы не используете /64 для маски подсети, вы действительно хотите быть осторожными, потому что это противоречит фундаментальному предположению, что многие связанные с IPv6 RFCs. Есть и другие RFCs, которые предостерегают от использования адреса хоста всех нулей (но я не знаю конкретного требование на этот счет).

Итак, для подсети /64 это означает, что диапазон одноадресных адресов ::0: 0:0: 1 через:: feff:ffff:ffff.

см. здесь для обсуждения: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm

weylin