计算子网内的所有地址...用于IPv6

时间:2011-08-16 17:58:07

标签: c# ipv6 subnet

我见过很多很棒的C# examples,它们演示了如何将CIDR表示法(例如192.168.0.1/25)中提供的IPv4地址转换为相关范围(192.168.0.1 - 192.168.0.126)。我的程序需要能够这样做(计算我本地子网中的所有地址),但我也想支持IPv6。

如果我的C#程序具有我所有典型的ipconfig信息(IPv4地址,子网掩码,IPv6地址,链接本地v6地址,默认网关) - 我将如何生成我所有IPv6地址的列表本地子网并将它们输出到控制台?

4 个答案:

答案 0 :(得分:9)

您可以使用eExNetworkLibrary中的eExNetworkLibrary.IP.IPAddressAnalysis类。

以下代码适用于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网络范围可能会耗费大量内存/ CPU。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

我建议使用IPNetwork Library 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

玩得开心!

答案 3 :(得分:0)

我知道这篇文章已有5年历史了,但考虑到Google的功能,它今天早上也可能已更新。因此,我将从网络工程的角度添加一些说明。

这取决于什么样的地址。如果您的意思是该范围内的每个地址,那么上述讨论是正确的。如果您指的是可以唯一分配给子网中节点的地址(&#34;单播&#34;地址),请注意在IPv6(a)中没有广播,并且(b)存在大量的组播范围

基本上:[subnet]:ff ::是为多播保留的。如果您没有使用/ 64作为子网掩码,那么您真的要小心,因为它违背了许多与IPv6相关的RFC的基本假设。还有其他的RFC警告不要使用全零主机地址(但我不知道具体的要求)。

因此,对于/ 64子网,这意味着单播地址的范围是:: 0:0:0:1到:: feff:ffff:ffff:ffff。

见此处讨论: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm

weylin