Convert CIDR notation into IP range

青春壹個敷衍的年華 提交于 2020-08-22 15:06:31

问题


We are using the GeoLite2 database in order to implement an IP -> country lookup. For performance reasons, we want to import the CSV and convert it to our own format.

The CSV is represented like this:

5.39.40.96/27,3017382,3017382,,0,0
5.39.40.128/28,3017382,3017382,,0,0
5.39.40.144/28,2635167,3017382,,0,0
5.39.40.160/27,3017382,3017382,,0,0
5.39.40.192/26,3017382,3017382,,0,0
5.39.41.0/25,3017382,3017382,,0,0
5.39.41.128/26,3017382,3017382,,0,0
5.39.41.192/26,2635167,3017382,,0,0
5.39.42.0/24,3017382,3017382,,0,0
5.39.43.0/25,3017382,3017382,,0,0

So we need to convert the CIDR notation (example: 5.39.40.96/27) into an IP address range. (From IP - To IP)

How can this be done in C#?

Note: This is not a duplicate of this question, since I'm asking about a C# implementation and not Java.


回答1:


Here is one way to handle it, without using any library functions to make it clear what's happening and to help if someone needs to implement it in other languages later on.

The code first converts the CIDR into a 32bit number, then creates the mask to determine the start address, uses the inverse of the mask to determine the end address and then converts back to CIDR format.

Note that there is no error detection so the input must be in the a.b.c.d/m format.

The conversion of the IP address is just a simple concatenation of the four octets in big endian form (AABBCCDD) using bit shifts.

The mask tells how many bits from the most significant bit are fixed, meaning 32 is a single IP range and 0 would be the whole IP range. Thus we can take a mask with all bits set and shift it left with 32-maskbits to determine the actual mask.

If we set the maskbits bits to zero, we get the beginning of the range, so we AND the IP with maskbits. If we set the bits to one, we get the end of the range, so we will OR with the negated bits of mask.

Printing the IP address in CIDR format is again simple: just split the 32bit value into octets and write them separated with dots.

using System;

namespace CSTests
{
    class Program
    {
        static string toip(uint ip)
        {
            return String.Format("{0}.{1}.{2}.{3}", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff);
        }

        static void Main(string[] args)
        {
            string IP = "5.39.40.96/27";
            string[] parts = IP.Split('.', '/');

            uint ipnum = (Convert.ToUInt32(parts[0]) << 24) |
                (Convert.ToUInt32(parts[1]) << 16) |
                (Convert.ToUInt32(parts[2]) << 8) |
                Convert.ToUInt32(parts[3]);

            int maskbits = Convert.ToInt32(parts[4]);
            uint mask = 0xffffffff;
            mask <<= (32 - maskbits);

            uint ipstart = ipnum & mask;
            uint ipend = ipnum | (mask ^ 0xffffffff);

            Console.WriteLine(toip(ipstart) + " - " + toip(ipend));
        }
    }
}

Output:

5.39.40.96 - 5.39.40.127




回答2:


Sami Kuhmonen, this is very nice code and seriously simplified. I noticed that it returns the network ID and the broadcast. However, for those that wish for it to return the usable address space. Simply add one to the starting IP and subtract one from the ending IP.

toip(ipstart + 1) + " - " + toip(ipend -1);


来源:https://stackoverflow.com/questions/32028166/convert-cidr-notation-into-ip-range

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!