Calculating all addresses within a subnet...for IPv6
Asked Answered
A

4

9

I have seen plenty of great C# examples which demonstrate how to convert IPv4 addresses provided in CIDR notation (e.g. 192.168.0.1/25) into their relevant ranges (192.168.0.1 - 192.168.0.126). My program needs to be able to do this (to compute all the addresses within my local subnet) but I want to also support IPv6.

If my C# program has all of my typical ipconfig information (IPv4 address, subnet mask, IPv6 address, link-local v6 address, default gateway) - how would I go about generating a list of all of the IPv6 addresses in my local subnet and outputting them to the console?

Adenitis answered 16/8, 2011 at 17:58 Comment(8)
You probably need to rethink your functionality. By design, almost any subnet you will see at IPv6 will be /64, or (2^64)-1 hosts large.Planking
That's correct, I want all 18,446,744,073,709,551,616 IP addresses ;)Adenitis
And what will you do with them? Even at 10 million a second, you'd need 58,000 years to go through them all.Planking
At a previous job, where we did a lot of network scanning, we quickly realized that any kind of address-space scan for IPv6 is essentially Sisyphean and that we had to attack some of our problem space a different way.Planking
@Planking - I think he just wants to take 2001:DB8::/48 and convert that to 2001:DB8:0:0:0:0:0:0 - 2001:DB8:0:FFFF:FFFF:FFFF:FFFF:FFFF, not get every possible address.Aldaaldan
@CodeNaked: all I have to go on is "generating a list of all IPv6 addresses in my local subnet"...Planking
@Planking - Yeah, I'm making assumptions based on the ;) part of his comment :-)Aldaaldan
Thanks guys. Emiswelt has posted code which actually provides both things...it will give me the ranges or (if i'm suicidal) the individual IP's.Adenitis
H
10

You can use the eExNetworkLibrary.IP.IPAddressAnalysis class from the eExNetworkLibrary.

The following code works with IPv4 and IPv6 (just tested).

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

I'm not completely sure if I have done the conversion from the prefix length to a byte array containing the subnet mask right, but this code should give you a good starting point.

Edit: Updated the bit-bending part of the code. May be ugly, but works for this example. I think you will be capable of finding a better solution, if you need to. Those BitArrays are a pain in the neck.

Be aware that generating an IPv6 network range can be a very memory/cpu exhausting task if the network is large.

Histidine answered 16/8, 2011 at 19:45 Comment(1)
This almost worked for me. Needed to change iIndex to equal (iMaskLength - iC1 - 1). This was the code before edit, so I'm not sure why it was changed.Tangent
S
2

I would recommend the use of IPNetwork Library https://github.com/lduchosal/ipnetwork. As of version 2, it supports IPv4 and IPv6 as well.

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

Output

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

Enumeration

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

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

Output

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

Have fun !

Sclerosis answered 11/8, 2015 at 9:22 Comment(1)
The output for first and last usable addresses is incorrect. IPv6, unlike IPv4, can use all the addresses in a subnet. A standard IPv6 subnet is /64 (a few special cases use other mask lengths), and the usable addresses are from <subnet>:: to <subnet>:ffff:ffff:ffff:ffff. There is no reservation for the subnet (<subnet>::), and IPv6 doesn't have the concept of broadcast, so no broadcast address exists at <subnet>:ffff:ffff:ffff:ffff.Gustative
Y
1

exNetworkLibrary is a great tool but if you can't use it in your project then you may just want to see this article:

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

It outlines how address masks are calculated for use in IPv4.

Your question is related to IPv6 I see and Since .Net 4.5 there is a IPAddress.MapToIPv6 method.

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

You can utilize that with the checks in the article to produce this code:

    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);
    }
Ynez answered 1/2, 2015 at 19:56 Comment(0)
C
0

I know this post is 5yr old, but given the Google capabilities it may as well have been updated this morning. So, I'll add a bit of clarification from the network engineering perspective.

It depends on what kind of addresses. If you mean every address in the range, then the above discussion is correct. If you mean addresses that can be uniquely assigned to a node in the subnet ("unicast" addresses), be aware that in IPv6 (a) there is no broadcast, and (b) there is a substantial multicast range.

Basically: [subnet]:ff:: is reserved for multicast. If you're not using a /64 for a subnet mask, you REALLY want to be careful because it goes against a fundamental assumption is many IPv6-related RFCs. There's other RFCs out that caution against using the all-zeros host address (but I'm not aware of a specific requirement to that effect).

So, for a /64 subnet, that means the range of unicast addresses is ::0:0:0:1 through ::feff:ffff:ffff:ffff.

See here for discussion: http://www.tcpipguide.com/free/t_IPv6MulticastandAnycastAddressing.htm

weylin

Coach answered 25/10, 2016 at 15:3 Comment(2)
The all-zeroes host address is reserved for the subnet router(s), which MUST respond on this address. See RFC 4291 section 2.6.1. Despite this requirement, the routers on many networks do not respond to this address, but if you try to use this address on a network where the router(s) act properly, you're going to have a bad day.Patroclus
I had a discussion recently with a Cisco IPv6 developer. Short version is that all-zeros "should work." However, (a) interactions with the router almost always use the link-local address anyway (FE80::/10), (b) if you're in a subnet with redundant routers, HSRP, VRRP, and GLBP perform much better, and (c) to your point this "any router" anycast address is not as well supported across OSes as you would think should be the case, and many uses of that address use it incorrectly.Coach

© 2022 - 2024 — McMap. All rights reserved.